diff options
author | asvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-31 05:27:37 +0000 |
---|---|---|
committer | asvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-31 05:27:37 +0000 |
commit | 05af9e8c72d448d5286c6c1aad4b01fae03037b7 (patch) | |
tree | 4466e94fb210afb7c258aecef91d68fe526fc7ef | |
parent | b31b7ea92d9c1e4dfc57c7218d1b01b454d8ca10 (diff) | |
download | chromium_src-05af9e8c72d448d5286c6c1aad4b01fae03037b7.zip chromium_src-05af9e8c72d448d5286c6c1aad4b01fae03037b7.tar.gz chromium_src-05af9e8c72d448d5286c6c1aad4b01fae03037b7.tar.bz2 |
Support large icons for Windows desktop profile shortcuts.
Also, fixes a problem in the existing code where the badged
avatar on the icon was slightly stretched compared to the
original image (as shown in the tab strip).
BUG=167277
TEST=See bug.
Review URL: https://chromiumcodereview.appspot.com/12090073
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@179804 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/app/theme/chrome_unscaled_resources.grd | 32 | ||||
-rw-r--r-- | chrome/browser/profiles/profile_shortcut_manager_win.cc | 177 | ||||
-rw-r--r-- | ui/gfx/icon_util.cc | 8 | ||||
-rw-r--r-- | ui/gfx/icon_util.h | 3 |
4 files changed, 162 insertions, 58 deletions
diff --git a/chrome/app/theme/chrome_unscaled_resources.grd b/chrome/app/theme/chrome_unscaled_resources.grd index a28314f..bb7f999 100644 --- a/chrome/app/theme/chrome_unscaled_resources.grd +++ b/chrome/app/theme/chrome_unscaled_resources.grd @@ -47,6 +47,38 @@ <include name="IDR_STATUS_TRAY_ICON_PRESSED" file="chromium/product_logo_22.png" type="BINDATA" /> </if> </if> + <if expr="is_win"> + <!-- Double-size profile avatar images used for generating .ico + files for Windows profile shortcuts. Included here because + they do not depend on the UI scale factor. + See: http://crbug.com/167277. --> + <include name="IDR_PROFILE_AVATAR_2X_0" file="default_200_percent/profile_avatar_generic.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_1" file="default_200_percent/profile_avatar_generic_aqua.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_2" file="default_200_percent/profile_avatar_generic_blue.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_3" file="default_200_percent/profile_avatar_generic_green.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_4" file="default_200_percent/profile_avatar_generic_orange.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_5" file="default_200_percent/profile_avatar_generic_purple.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_6" file="default_200_percent/profile_avatar_generic_red.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_7" file="default_200_percent/profile_avatar_generic_yellow.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_8" file="default_200_percent/profile_avatar_secret_agent.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_9" file="default_200_percent/profile_avatar_superhero.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_10" file="default_200_percent/profile_avatar_volley_ball.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_11" file="default_200_percent/profile_avatar_businessman.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_12" file="default_200_percent/profile_avatar_ninja.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_13" file="default_200_percent/profile_avatar_alien.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_14" file="default_200_percent/profile_avatar_awesome.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_15" file="default_200_percent/profile_avatar_flower.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_16" file="default_200_percent/profile_avatar_pizza.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_17" file="default_200_percent/profile_avatar_soccer.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_18" file="default_200_percent/profile_avatar_burger.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_19" file="default_200_percent/profile_avatar_cat.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_20" file="default_200_percent/profile_avatar_cupcake.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_21" file="default_200_percent/profile_avatar_dog.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_22" file="default_200_percent/profile_avatar_horse.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_23" file="default_200_percent/profile_avatar_margarita.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_24" file="default_200_percent/profile_avatar_note.png" type="BINDATA" /> + <include name="IDR_PROFILE_AVATAR_2X_25" file="default_200_percent/profile_avatar_sun_cloud.png" type="BINDATA" /> + </if> </includes> </release> </grit> diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc index 1a8f575..4c3283f 100644 --- a/chrome/browser/profiles/profile_shortcut_manager_win.cc +++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc @@ -26,11 +26,14 @@ #include "chrome/installer/util/product.h" #include "chrome/installer/util/shell_util.h" #include "content/public/browser/browser_thread.h" +#include "grit/chrome_unscaled_resources.h" #include "skia/ext/image_operations.h" #include "skia/ext/platform_canvas.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/icon_util.h" #include "ui/gfx/image/image.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/skia_util.h" using content::BrowserThread; @@ -48,63 +51,111 @@ const char16 kReservedCharacters[] = L"<>:\"/\\|?*\x01\x02\x03\x04\x05\x06\x07" // differently than it was when a shortcut was originally created. const int kMaxProfileShortcutFileNameLength = 64; -const int kProfileAvatarShortcutBadgeWidth = 28; -const int kProfileAvatarShortcutBadgeHeight = 28; +const int kProfileAvatarBadgeSize = 28; const int kShortcutIconSize = 48; -// Creates a desktop shortcut icon file (.ico) on the disk for a given profile, -// badging the browser distribution icon with the profile avatar. -// Returns a path to the shortcut icon file on disk, which is empty if this -// fails. Use index 0 when assigning the resulting file as the icon. -FilePath CreateChromeDesktopShortcutIconForProfile( - const FilePath& profile_path, - const SkBitmap& avatar_bitmap) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); - scoped_ptr<SkBitmap> app_icon_bitmap(GetAppIconForSize(kShortcutIconSize)); - if (!app_icon_bitmap.get()) - return FilePath(); - +// 2x sized profile avatar icons. Mirrors |kDefaultAvatarIconResources| in +// profile_info_cache.cc. +const int kProfileAvatarIconResources2x[] = { + IDR_PROFILE_AVATAR_2X_0, + IDR_PROFILE_AVATAR_2X_1, + IDR_PROFILE_AVATAR_2X_2, + IDR_PROFILE_AVATAR_2X_3, + IDR_PROFILE_AVATAR_2X_4, + IDR_PROFILE_AVATAR_2X_5, + IDR_PROFILE_AVATAR_2X_6, + IDR_PROFILE_AVATAR_2X_7, + IDR_PROFILE_AVATAR_2X_8, + IDR_PROFILE_AVATAR_2X_9, + IDR_PROFILE_AVATAR_2X_10, + IDR_PROFILE_AVATAR_2X_11, + IDR_PROFILE_AVATAR_2X_12, + IDR_PROFILE_AVATAR_2X_13, + IDR_PROFILE_AVATAR_2X_14, + IDR_PROFILE_AVATAR_2X_15, + IDR_PROFILE_AVATAR_2X_16, + IDR_PROFILE_AVATAR_2X_17, + IDR_PROFILE_AVATAR_2X_18, + IDR_PROFILE_AVATAR_2X_19, + IDR_PROFILE_AVATAR_2X_20, + IDR_PROFILE_AVATAR_2X_21, + IDR_PROFILE_AVATAR_2X_22, + IDR_PROFILE_AVATAR_2X_23, + IDR_PROFILE_AVATAR_2X_24, + IDR_PROFILE_AVATAR_2X_25, +}; + +// Badges |app_icon_bitmap| with |avatar_bitmap| at the bottom right corner and +// returns the resulting SkBitmap. +SkBitmap BadgeIcon(const SkBitmap& app_icon_bitmap, + const SkBitmap& avatar_bitmap, + int scale_factor) { // TODO(rlp): Share this chunk of code with // avatar_menu_button::DrawTaskBarDecoration. - const SkBitmap* source_bitmap = NULL; - SkBitmap squarer_bitmap; - if ((avatar_bitmap.width() == profiles::kAvatarIconWidth) && - (avatar_bitmap.height() == profiles::kAvatarIconHeight)) { + SkBitmap source_bitmap = avatar_bitmap; + if ((avatar_bitmap.width() == scale_factor * profiles::kAvatarIconWidth) && + (avatar_bitmap.height() == scale_factor * profiles::kAvatarIconHeight)) { // Shave a couple of columns so the bitmap is more square. So when // resized to a square aspect ratio it looks pretty. - int x = 2; - avatar_bitmap.extractSubset(&squarer_bitmap, SkIRect::MakeXYWH(x, 0, - profiles::kAvatarIconWidth - x * 2, profiles::kAvatarIconHeight)); - source_bitmap = &squarer_bitmap; + gfx::Rect frame(scale_factor * profiles::kAvatarIconWidth, + scale_factor * profiles::kAvatarIconHeight); + frame.Inset(scale_factor * 2, 0, scale_factor * 2, 0); + avatar_bitmap.extractSubset(&source_bitmap, gfx::RectToSkIRect(frame)); } else { - source_bitmap = &avatar_bitmap; + NOTREACHED(); + } + int avatar_badge_size = kProfileAvatarBadgeSize; + if (app_icon_bitmap.width() != kShortcutIconSize) { + avatar_badge_size = + app_icon_bitmap.width() * kProfileAvatarBadgeSize / kShortcutIconSize; } SkBitmap sk_icon = skia::ImageOperations::Resize( - *source_bitmap, - skia::ImageOperations::RESIZE_LANCZOS3, - kProfileAvatarShortcutBadgeWidth, - kProfileAvatarShortcutBadgeHeight); + source_bitmap, skia::ImageOperations::RESIZE_LANCZOS3, avatar_badge_size, + source_bitmap.height() * avatar_badge_size / source_bitmap.width()); // Overlay the avatar on the icon, anchoring it to the bottom-right of the // icon. scoped_ptr<SkCanvas> offscreen_canvas( - skia::CreateBitmapCanvas(app_icon_bitmap->width(), - app_icon_bitmap->height(), + skia::CreateBitmapCanvas(app_icon_bitmap.width(), + app_icon_bitmap.height(), false)); DCHECK(offscreen_canvas.get()); - offscreen_canvas->drawBitmap(*app_icon_bitmap, 0, 0); - offscreen_canvas->drawBitmap( - sk_icon, - app_icon_bitmap->width() - kProfileAvatarShortcutBadgeWidth, - app_icon_bitmap->height() - kProfileAvatarShortcutBadgeHeight); - const SkBitmap& final_bitmap = + offscreen_canvas->drawBitmap(app_icon_bitmap, 0, 0); + offscreen_canvas->drawBitmap(sk_icon, + app_icon_bitmap.width() - sk_icon.width(), + app_icon_bitmap.height() - sk_icon.height()); + const SkBitmap& badged_bitmap = offscreen_canvas->getDevice()->accessBitmap(false); + SkBitmap badged_bitmap_copy; + badged_bitmap.deepCopyTo(&badged_bitmap_copy, badged_bitmap.getConfig()); + return badged_bitmap_copy; +} + +// Creates a desktop shortcut icon file (.ico) on the disk for a given profile, +// badging the browser distribution icon with the profile avatar. +// Returns a path to the shortcut icon file on disk, which is empty if this +// fails. Use index 0 when assigning the resulting file as the icon. +FilePath CreateChromeDesktopShortcutIconForProfile( + const FilePath& profile_path, + const SkBitmap& avatar_bitmap_1x, + const SkBitmap& avatar_bitmap_2x) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + scoped_ptr<SkBitmap> app_icon_bitmap(GetAppIconForSize(kShortcutIconSize)); + if (!app_icon_bitmap.get()) + return FilePath(); + + const SkBitmap badged_bitmap = BadgeIcon(*app_icon_bitmap, + avatar_bitmap_1x, 1); + + SkBitmap large_badged_bitmap; + app_icon_bitmap = GetAppIconForSize(IconUtil::kLargeIconSize); + if (app_icon_bitmap.get()) + large_badged_bitmap = BadgeIcon(*app_icon_bitmap, avatar_bitmap_2x, 2); // Finally, write the .ico file containing this new bitmap. const FilePath icon_path = profile_path.AppendASCII(profiles::internal::kProfileIconFileName); - // TODO(asvitkine): Create icon with a large 256x256 bitmap. - if (!IconUtil::CreateIconFileFromSkBitmap(final_bitmap, SkBitmap(), + if (!IconUtil::CreateIconFileFromSkBitmap(badged_bitmap, large_badged_bitmap, icon_path)) return FilePath(); @@ -242,7 +293,8 @@ void CreateOrUpdateDesktopShortcutsForProfile( const FilePath& profile_path, const string16& old_profile_name, const string16& profile_name, - const SkBitmap& avatar_image, + const SkBitmap& avatar_image_1x, + const SkBitmap& avatar_image_2x, ProfileShortcutManagerWin::CreateOrUpdateMode create_mode, ProfileShortcutManagerWin::NonProfileShortcutAction action) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); @@ -281,7 +333,9 @@ void CreateOrUpdateDesktopShortcutsForProfile( // non-profile Chrome shortcut. if (!profile_name.empty()) { const FilePath shortcut_icon = - CreateChromeDesktopShortcutIconForProfile(profile_path, avatar_image); + CreateChromeDesktopShortcutIconForProfile(profile_path, + avatar_image_1x, + avatar_image_2x); if (!shortcut_icon.empty()) properties.set_icon(shortcut_icon, 0); properties.set_arguments(command_line); @@ -429,6 +483,19 @@ string16 SanitizeShortcutProfileNameString(const string16& profile_name) { return sanitized; } +// Returns a copied SkBitmap for the given resource id that can be safely passed +// to another thread. +SkBitmap GetImageResourceSkBitmapCopy(int resource_id) { + const gfx::Image image = + ResourceBundle::GetSharedInstance().GetNativeImageNamed(resource_id); + DCHECK(!image.IsEmpty()); + + const SkBitmap* image_bitmap = image.ToSkBitmap(); + SkBitmap bitmap_copy; + image_bitmap->deepCopyTo(&bitmap_copy, image_bitmap->getConfig()); + return bitmap_copy; +} + } // namespace namespace profiles { @@ -470,6 +537,10 @@ ProfileShortcutManager* ProfileShortcutManager::Create( ProfileShortcutManagerWin::ProfileShortcutManagerWin(ProfileManager* manager) : profile_manager_(manager) { + DCHECK_EQ( + arraysize(kProfileAvatarIconResources2x), + profile_manager_->GetProfileInfoCache().GetDefaultAvatarIconCount()); + profile_manager_->GetProfileInfoCache().AddObserver(this); } @@ -576,27 +647,25 @@ void ProfileShortcutManagerWin::CreateOrUpdateShortcutsForProfileAtPath( if (!remove_badging) new_shortcut_appended_name = cache->GetNameOfProfileAtIndex(profile_index); - SkBitmap profile_avatar_bitmap_copy; + SkBitmap avatar_bitmap_copy_1x; + SkBitmap avatar_bitmap_copy_2x; if (!remove_badging) { - size_t profile_icon_index = + const size_t icon_index = cache->GetAvatarIconIndexOfProfileAtIndex(profile_index); - gfx::Image profile_avatar_image = ResourceBundle::GetSharedInstance(). - GetNativeImageNamed( - cache->GetDefaultAvatarIconResourceIDAtIndex(profile_icon_index)); - - DCHECK(!profile_avatar_image.IsEmpty()); - const SkBitmap* profile_avatar_bitmap = profile_avatar_image.ToSkBitmap(); - // Make a copy of the SkBitmap to ensure that we can safely use the image + const int resource_id_1x = + cache->GetDefaultAvatarIconResourceIDAtIndex(icon_index); + const int resource_id_2x = kProfileAvatarIconResources2x[icon_index]; + // Make a copy of the SkBitmaps to ensure that we can safely use the image // data on the FILE thread. - profile_avatar_bitmap->deepCopyTo(&profile_avatar_bitmap_copy, - profile_avatar_bitmap->getConfig()); + avatar_bitmap_copy_1x = GetImageResourceSkBitmapCopy(resource_id_1x); + avatar_bitmap_copy_2x = GetImageResourceSkBitmapCopy(resource_id_2x); } BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, - base::Bind(&CreateOrUpdateDesktopShortcutsForProfile, - profile_path, old_shortcut_appended_name, - new_shortcut_appended_name, profile_avatar_bitmap_copy, - create_mode, action)); + base::Bind(&CreateOrUpdateDesktopShortcutsForProfile, profile_path, + old_shortcut_appended_name, new_shortcut_appended_name, + avatar_bitmap_copy_1x, avatar_bitmap_copy_2x, create_mode, + action)); cache->SetShortcutNameOfProfileAtIndex(profile_index, new_shortcut_appended_name); diff --git a/ui/gfx/icon_util.cc b/ui/gfx/icon_util.cc index 7bce98e..d071a2f 100644 --- a/ui/gfx/icon_util.cc +++ b/ui/gfx/icon_util.cc @@ -138,10 +138,10 @@ SkBitmap* IconUtil::CreateSkBitmapFromHICON(HICON icon, const gfx::Size& s) { scoped_ptr<SkBitmap> IconUtil::CreateSkBitmapFromIconResource(HMODULE module, int resource_id, int size) { - DCHECK_LE(size, 256); + DCHECK_LE(size, kLargeIconSize); // For everything except the Vista+ 256x256 icons, use |LoadImage()|. - if (size != 256) { + if (size != kLargeIconSize) { HICON icon_handle = static_cast<HICON>(LoadImage(module, MAKEINTRESOURCE(resource_id), IMAGE_ICON, size, size, @@ -357,8 +357,8 @@ bool IconUtil::CreateIconFileFromSkBitmap(const SkBitmap& bitmap, // If |large_bitmap| was specified, validate its dimension and convert to PNG. scoped_refptr<base::RefCountedMemory> png_bytes; if (!large_bitmap.empty()) { - CHECK_EQ(256, large_bitmap.width()); - CHECK_EQ(256, large_bitmap.height()); + CHECK_EQ(kLargeIconSize, large_bitmap.width()); + CHECK_EQ(kLargeIconSize, large_bitmap.height()); png_bytes = gfx::Image::CreateFrom1xBitmap(large_bitmap).As1xPNGBytes(); } diff --git a/ui/gfx/icon_util.h b/ui/gfx/icon_util.h index dfeea4c..4aa2676 100644 --- a/ui/gfx/icon_util.h +++ b/ui/gfx/icon_util.h @@ -55,6 +55,9 @@ class SkBitmap; /////////////////////////////////////////////////////////////////////////////// class UI_EXPORT IconUtil { public: + // The size of the large icon entries in .ico files on Windows Vista+. + static const int kLargeIconSize = 256; + // Given an SkBitmap object, the function converts the bitmap to a Windows // icon and returns the corresponding HICON handle. If the function cannot // convert the bitmap, NULL is returned. |