summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorasvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-31 05:27:37 +0000
committerasvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-31 05:27:37 +0000
commit05af9e8c72d448d5286c6c1aad4b01fae03037b7 (patch)
tree4466e94fb210afb7c258aecef91d68fe526fc7ef
parentb31b7ea92d9c1e4dfc57c7218d1b01b454d8ca10 (diff)
downloadchromium_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.grd32
-rw-r--r--chrome/browser/profiles/profile_shortcut_manager_win.cc177
-rw-r--r--ui/gfx/icon_util.cc8
-rw-r--r--ui/gfx/icon_util.h3
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.