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/ui/web_applications/web_app_ui.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/path_service.h"
11868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/prefs/pref_service.h"
12868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string16.h"
13868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "chrome/browser/chrome_notification_types.h"
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/extensions/image_loader.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/extensions/tab_helper.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/favicon/favicon_tab_helper.h"
18d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)#include "chrome/browser/history/select_favicon_frames.h"
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/profiles/profile.h"
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/web_applications/web_app.h"
21868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
22c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/common/extensions/manifest_handlers/icons_handler.h"
23868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "chrome/common/pref_names.h"
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_details.h"
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_registrar.h"
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/notification_source.h"
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
29f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "extensions/common/extension.h"
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/theme_resources.h"
312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "skia/ext/image_operations.h"
322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image.h"
35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image_family.h"
36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/image/image_skia.h"
377dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#include "url/gurl.h"
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_POSIX) && !defined(OS_MACOSX)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/environment.h"
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/shortcut.h"
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/win/windows_version.h"
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include "chrome/browser/web_applications/web_app_win.h"
47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "ui/gfx/icon_util.h"
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::NavigationController;
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::WebContents;
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#if defined(OS_MACOSX)
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kDesiredSizes[] = {16, 32, 128, 256, 512};
58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#elif defined(OS_LINUX)
602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Linux supports icons of any size. FreeDesktop Icon Theme Specification states
612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// that "Minimally you should install a 48x48 icon in the hicolor theme."
622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kDesiredSizes[] = {16, 32, 48, 128, 256, 512};
63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#elif defined(OS_WIN)
65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const int* kDesiredSizes = IconUtil::kIconDimensions;
66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const size_t kNumDesiredSizes = IconUtil::kNumIconDimensions;
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#else
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const int kDesiredSizes[] = {32};
69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#endif
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// UpdateShortcutWorker holds all context data needed for update shortcut.
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// It schedules a pre-update check to find all shortcuts that needs to be
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// updated. If there are such shortcuts, it schedules icon download and
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// update them when icons are downloaded. It observes TAB_CLOSING notification
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and cancels all the work when the underlying tab is closing.
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class UpdateShortcutWorker : public content::NotificationObserver {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  explicit UpdateShortcutWorker(WebContents* web_contents);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Run();
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Overridden from content::NotificationObserver:
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual void Observe(int type,
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const content::NotificationSource& source,
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                       const content::NotificationDetails& details);
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Downloads icon via the FaviconTabHelper.
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DownloadIcon();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Favicon download callback.
942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void DidDownloadFavicon(
95d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      int requested_size,
962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      int id,
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      int http_status_code,
982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const GURL& image_url,
99d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      const std::vector<SkBitmap>& bitmaps,
100d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)      const std::vector<gfx::Size>& original_bitmap_sizes);
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Checks if shortcuts exists on desktop, start menu and quick launch.
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void CheckExistingShortcuts();
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update shortcut files and icons.
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void UpdateShortcuts();
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void UpdateShortcutsOnFileThread();
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Callback after shortcuts are updated.
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void OnShortcutsUpdated(bool);
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Deletes the worker on UI thread where it gets created.
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DeleteMe();
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void DeleteMeOnUIThread();
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  content::NotificationRegistrar registrar_;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Underlying WebContents whose shortcuts will be updated.
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  WebContents* web_contents_;
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Icons info from web_contents_'s web app data.
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_app::IconInfoList unprocessed_icons_;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Cached shortcut data from the web_contents_.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ShellIntegration::ShortcutInfo shortcut_info_;
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Our copy of profile path.
1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath profile_path_;
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // File name of shortcut/ico file based on app title.
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath file_name_;
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Existing shortcuts.
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<base::FilePath> shortcut_files_;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(UpdateShortcutWorker);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)UpdateShortcutWorker::UpdateShortcutWorker(WebContents* web_contents)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : web_contents_(web_contents),
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_path_(Profile::FromBrowserContext(
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          web_contents->GetBrowserContext())->GetPath()) {
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  extensions::TabHelper* extensions_tab_helper =
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extensions::TabHelper::FromWebContents(web_contents);
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_app::GetShortcutInfoForTab(web_contents_, &shortcut_info_);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  web_app::GetIconsInfo(extensions_tab_helper->web_app_info(),
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                        &unprocessed_icons_);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  file_name_ = web_app::internals::GetSanitizedFileName(shortcut_info_.title);
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  registrar_.Add(
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      this,
1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      chrome::NOTIFICATION_TAB_CLOSING,
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<NavigationController>(&web_contents->GetController()));
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateShortcutWorker::Run() {
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Starting by downloading app icon.
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DownloadIcon();
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateShortcutWorker::Observe(
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int type,
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationSource& source,
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const content::NotificationDetails& details) {
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (type == chrome::NOTIFICATION_TAB_CLOSING &&
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::Source<NavigationController>(source).ptr() ==
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        &web_contents_->GetController()) {
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Underlying tab is closing.
1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    web_contents_ = NULL;
1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateShortcutWorker::DownloadIcon() {
1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // FetchIcon must run on UI thread because it relies on WebContents
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // to download the icon.
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (web_contents_ == NULL) {
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeleteMe();  // We are done if underlying WebContents is gone.
1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (unprocessed_icons_.empty()) {
1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // No app icon. Just use the favicon from WebContents.
1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateShortcuts();
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
189eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  int preferred_size = std::max(unprocessed_icons_.back().width,
190eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch                                unprocessed_icons_.back().height);
191c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  web_contents_->DownloadImage(
1922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      unprocessed_icons_.back().url,
1932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      true,  // favicon
194eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      0,  // no maximum size
1952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&UpdateShortcutWorker::DidDownloadFavicon,
196d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 base::Unretained(this),
197d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                 preferred_size));
1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  unprocessed_icons_.pop_back();
1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void UpdateShortcutWorker::DidDownloadFavicon(
202d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    int requested_size,
2032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int id,
20490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)    int http_status_code,
2052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const GURL& image_url,
206d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<SkBitmap>& bitmaps,
207d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)    const std::vector<gfx::Size>& original_sizes) {
2082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<ui::ScaleFactor> scale_factors;
2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  scale_factors.push_back(ui::SCALE_FACTOR_100P);
2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
211d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  std::vector<size_t> closest_indices;
212d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  SelectFaviconFrameIndices(original_sizes,
213d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                            scale_factors,
214d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                            requested_size,
215d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                            &closest_indices,
216d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)                            NULL);
217d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)  size_t closest_index = closest_indices[0];
2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (!bitmaps.empty() && !bitmaps[closest_index].isNull()) {
2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Update icon with download image and update shortcut.
221c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shortcut_info_.favicon.Add(
222c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        gfx::Image::CreateFrom1xBitmap(bitmaps[closest_index]));
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    extensions::TabHelper* extensions_tab_helper =
2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        extensions::TabHelper::FromWebContents(web_contents_);
2252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extensions_tab_helper->SetAppIcon(bitmaps[closest_index]);
2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    UpdateShortcuts();
2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Try the next icon otherwise.
2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DownloadIcon();
2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateShortcutWorker::CheckExistingShortcuts() {
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Locations to check to shortcut_paths.
2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct {
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int location_id;
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const wchar_t* sub_dir;
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } locations[] = {
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    {
2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::DIR_USER_DESKTOP,
2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL
2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }, {
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::DIR_START_MENU,
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NULL
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }, {
2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      // For Win7, create_in_quick_launch_bar means pinning to taskbar.
2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::DIR_APP_DATA,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (base::win::GetVersion() >= base::win::VERSION_WIN7) ?
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          L"Microsoft\\Internet Explorer\\Quick Launch\\User Pinned\\TaskBar" :
2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          L"Microsoft\\Internet Explorer\\Quick Launch"
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (int i = 0; i < arraysize(locations); ++i) {
2572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath path;
2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!PathService::Get(locations[i].location_id, &path)) {
2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      NOTREACHED();
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (locations[i].sub_dir != NULL)
2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      path = path.Append(locations[i].sub_dir);
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    base::FilePath shortcut_file = path.Append(file_name_).
2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        ReplaceExtension(FILE_PATH_LITERAL(".lnk"));
2687dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    if (base::PathExists(shortcut_file)) {
2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_files_.push_back(shortcut_file);
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateShortcutWorker::UpdateShortcuts() {
2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&UpdateShortcutWorker::UpdateShortcutsOnFileThread,
2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(this)));
2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateShortcutWorker::UpdateShortcutsOnFileThread() {
2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath web_app_path = web_app::GetWebAppDataDirectory(
2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      profile_path_, shortcut_info_.extension_id, shortcut_info_.url);
2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Ensure web_app_path exists. web_app_path could be missing for a legacy
2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // shortcut created by Gears.
2887dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (!base::PathExists(web_app_path) &&
289a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      !base::CreateDirectory(web_app_path)) {
2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED();
2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return;
2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath icon_file = web_app_path.Append(file_name_).ReplaceExtension(
2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FILE_PATH_LITERAL(".ico"));
296c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  web_app::internals::CheckAndSaveIcon(icon_file, shortcut_info_.favicon);
2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Update existing shortcuts' description, icon and app id.
2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  CheckExistingShortcuts();
3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!shortcut_files_.empty()) {
3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Generates app id from web app url and profile path.
302a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    base::string16 app_id = ShellIntegration::GetAppModelIdForProfile(
3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        UTF8ToWide(web_app::GenerateApplicationNameFromURL(shortcut_info_.url)),
3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        profile_path_);
3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Sanitize description
3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (shortcut_info_.description.length() >= MAX_PATH)
3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_info_.description.resize(MAX_PATH - 1);
3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    for (size_t i = 0; i < shortcut_files_.size(); ++i) {
3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::win::ShortcutProperties shortcut_properties;
3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_properties.set_target(shortcut_files_[i]);
3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_properties.set_description(shortcut_info_.description);
3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_properties.set_icon(icon_file, 0);
3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      shortcut_properties.set_app_id(app_id);
3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::win::CreateOrUpdateShortcutLink(
3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          shortcut_files_[i], shortcut_properties,
3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::win::SHORTCUT_UPDATE_EXISTING);
3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OnShortcutsUpdated(true);
3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateShortcutWorker::OnShortcutsUpdated(bool) {
3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DeleteMe();  // We are done.
3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateShortcutWorker::DeleteMe() {
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DeleteMeOnUIThread();
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&UpdateShortcutWorker::DeleteMeOnUIThread,
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 base::Unretained(this)));
3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateShortcutWorker::DeleteMeOnUIThread() {
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete this;
3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(OS_WIN)
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void OnImageLoaded(ShellIntegration::ShortcutInfo shortcut_info,
3462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   web_app::ShortcutInfoCallback callback,
3472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                   const gfx::Image& image) {
3482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // If the image failed to load (e.g. if the resource being loaded was empty)
3492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // use the standard application icon.
3502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (image.IsEmpty()) {
3512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    gfx::Image default_icon =
3522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ResourceBundle::GetSharedInstance().GetImageNamed(IDR_APP_DEFAULT_ICON);
353c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    int size = kDesiredSizes[kNumDesiredSizes - 1];
3542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    SkBitmap bmp = skia::ImageOperations::Resize(
3552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          *default_icon.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST,
3562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          size, size);
357c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    gfx::ImageSkia image_skia = gfx::ImageSkia::CreateFrom1xBitmap(bmp);
358c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // We are on the UI thread, and this image is needed from the FILE thread,
359c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // for creating shortcut icon files.
360c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    image_skia.MakeThreadSafe();
361c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    shortcut_info.favicon.Add(gfx::Image(image_skia));
3622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  } else {
363c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // As described in UpdateShortcutInfoAndIconForApp, image contains all of
364c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // the icons, hackily put into a single ImageSkia. Separate them out into
365c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // individual ImageSkias and insert them into the icon family.
366c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const gfx::ImageSkia& multires_image_skia = image.AsImageSkia();
36768043e1e95eeb07d5cae7aca370b26518b0867d6Torne (Richard Coles)    // NOTE: We do not call ImageSkia::EnsureRepsForSupportedScales here.
368c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // The image reps here are not really for different scale factors (ImageSkia
369c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    // is just being used as a handy container for multiple images).
370c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::vector<gfx::ImageSkiaRep> image_reps =
371c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        multires_image_skia.image_reps();
372c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    for (std::vector<gfx::ImageSkiaRep>::const_iterator it = image_reps.begin();
373c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)         it != image_reps.end(); ++it) {
374c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      gfx::ImageSkia image_skia(*it);
375c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      image_skia.MakeThreadSafe();
376c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      shortcut_info.favicon.Add(image_skia);
377c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    }
3782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
3792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  callback.Run(shortcut_info);
3812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace web_app {
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ShellIntegration::ShortcutInfo ShortcutInfoForExtensionAndProfile(
3882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const extensions::Extension* extension, Profile* profile) {
3892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ShellIntegration::ShortcutInfo shortcut_info;
3902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  web_app::UpdateShortcutInfoForApp(*extension, profile, &shortcut_info);
3912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return shortcut_info;
3922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
3932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void GetShortcutInfoForTab(WebContents* web_contents,
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           ShellIntegration::ShortcutInfo* info) {
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(info);  // Must provide a valid info.
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const FaviconTabHelper* favicon_tab_helper =
3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      FaviconTabHelper::FromWebContents(web_contents);
4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const extensions::TabHelper* extensions_tab_helper =
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      extensions::TabHelper::FromWebContents(web_contents);
4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  const WebApplicationInfo& app_info = extensions_tab_helper->web_app_info();
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info->url = app_info.app_url.is_empty() ? web_contents->GetURL() :
4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                            app_info.app_url;
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info->title = app_info.title.empty() ?
4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      (web_contents->GetTitle().empty() ? UTF8ToUTF16(info->url.spec()) :
4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                          web_contents->GetTitle()) :
4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      app_info.title;
4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info->description = app_info.description;
411c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  info->favicon.Add(favicon_tab_helper->GetFavicon());
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Profile* profile =
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      Profile::FromBrowserContext(web_contents->GetBrowserContext());
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  info->profile_path = profile->GetPath();
4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void UpdateShortcutForTabContents(WebContents* web_contents) {
4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // UpdateShortcutWorker will delete itself when it's done.
4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  UpdateShortcutWorker* worker = new UpdateShortcutWorker(web_contents);
4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  worker->Run();
4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // defined(OS_WIN)
4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void UpdateShortcutInfoForApp(const extensions::Extension& app,
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              Profile* profile,
4282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                              ShellIntegration::ShortcutInfo* shortcut_info) {
4292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  shortcut_info->extension_id = app.id();
4302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  shortcut_info->is_platform_app = app.is_platform_app();
431868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  shortcut_info->url = extensions::AppLaunchInfo::GetLaunchWebURL(&app);
4322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  shortcut_info->title = UTF8ToUTF16(app.name());
4332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  shortcut_info->description = UTF8ToUTF16(app.description());
4342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  shortcut_info->extension_path = app.path();
4352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  shortcut_info->profile_path = profile->GetPath();
436868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)  shortcut_info->profile_name =
437868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      profile->GetPrefs()->GetString(prefs::kProfileName);
4382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void UpdateShortcutInfoAndIconForApp(
4412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const extensions::Extension& extension,
4422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Profile* profile,
4432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const web_app::ShortcutInfoCallback& callback) {
4442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ShellIntegration::ShortcutInfo shortcut_info =
4452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ShortcutInfoForExtensionAndProfile(&extension, profile);
4462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
447c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // We want to load each icon into a separate ImageSkia to insert into an
448c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // ImageFamily, but LoadImagesAsync currently only builds a single ImageSkia.
449c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // Hack around this by loading all images into the ImageSkia as 100%
450c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // representations, and later (in OnImageLoaded), pulling them out and
451c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // individually inserting them into an ImageFamily.
452c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // TODO(mgiuca): Have ImageLoader build the ImageFamily directly
453c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // (http://crbug.com/230184).
4542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
455c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  for (size_t i = 0; i < kNumDesiredSizes; ++i) {
4562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int size = kDesiredSizes[i];
4572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extensions::ExtensionResource resource =
4582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extensions::IconsInfo::GetIconResource(
4592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            &extension, size, ExtensionIconSet::MATCH_EXACTLY);
4602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!resource.empty()) {
4612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      info_list.push_back(extensions::ImageLoader::ImageRepresentation(
4622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          resource,
4632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          extensions::ImageLoader::ImageRepresentation::RESIZE_WHEN_LARGER,
4642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          gfx::Size(size, size),
4652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          ui::SCALE_FACTOR_100P));
4662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (info_list.empty()) {
470c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    size_t i = kNumDesiredSizes - 1;
4712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    int size = kDesiredSizes[i];
4722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // If there is no icon at the desired sizes, we will resize what we can get.
4742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // Making a large icon smaller is preferred to making a small icon larger,
4752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // so look for a larger icon first:
4762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    extensions::ExtensionResource resource =
4772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extensions::IconsInfo::GetIconResource(
4782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)            &extension, size, ExtensionIconSet::MATCH_BIGGER);
4792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (resource.empty()) {
4802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      resource = extensions::IconsInfo::GetIconResource(
4812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          &extension, size, ExtensionIconSet::MATCH_SMALLER);
4822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
4832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    info_list.push_back(extensions::ImageLoader::ImageRepresentation(
4842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        resource,
4852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        extensions::ImageLoader::ImageRepresentation::RESIZE_WHEN_LARGER,
4862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        gfx::Size(size, size),
4872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ui::SCALE_FACTOR_100P));
4882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
4892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // |info_list| may still be empty at this point, in which case LoadImage
4912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // will call the OnImageLoaded callback with an empty image and exit
4922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // immediately.
4932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  extensions::ImageLoader::Get(profile)->LoadImagesAsync(&extension, info_list,
4942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&OnImageLoaded, shortcut_info, callback));
4952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
4962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace web_app
498