summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormgiuca@chromium.org <mgiuca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-30 04:43:49 +0000
committermgiuca@chromium.org <mgiuca@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-30 04:43:49 +0000
commit7842b4f9187e716c2da05fa560ff648a65bd490d (patch)
tree12cf60ad3a8b0d7d1cebbbe7b43ef8fd7769b85f
parent5673b4b450ccbc21a10ae1b63002ba1c7a057f21 (diff)
downloadchromium_src-7842b4f9187e716c2da05fa560ff648a65bd490d.zip
chromium_src-7842b4f9187e716c2da05fa560ff648a65bd490d.tar.gz
chromium_src-7842b4f9187e716c2da05fa560ff648a65bd490d.tar.bz2
App shortcut icons on Windows are now 256x256 instead of 32x32.
icon_util.CreateIconFileFromSkBitmap has been replaced with CreateIconFileFromImageFamily, which uses a set of differently-sized icons to produce the Windows .ico file with each bitmap scaled from the best available icon size. For both apps and badged Chrome logo shortcuts, icons in the "Medium icons" view are no longer scaled up to 48x48 from 32x32. In the "Large icons" and "Extra large icons" views, if an app provides an icon >48x48, Windows now displays the icon at full size (96x96 or 256x256, respectively), instead of at 48x48 with a box around it. BUG=163864 TEST=Create web shortcut, should be a 48x48 icon. Create v2 app shortcut, should be a 256x256 icon with no pixelated bitmaps at any size <= 128x128. Review URL: https://chromiumcodereview.appspot.com/14221004 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@197263 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/jumplist_win.cc5
-rw-r--r--chrome/browser/profiles/profile_shortcut_manager_win.cc16
-rw-r--r--chrome/browser/ui/web_applications/web_app_ui.cc13
-rw-r--r--chrome/browser/web_applications/web_app_win.cc39
-rw-r--r--ui/gfx/icon_util.cc219
-rw-r--r--ui/gfx/icon_util.h50
-rw-r--r--ui/gfx/icon_util_unittest.cc255
-rw-r--r--ui/gfx/image/image_family.cc4
-rw-r--r--ui/gfx/image/image_family.h10
9 files changed, 417 insertions, 194 deletions
diff --git a/chrome/browser/jumplist_win.cc b/chrome/browser/jumplist_win.cc
index de8aaa9..f2b0372 100644
--- a/chrome/browser/jumplist_win.cc
+++ b/chrome/browser/jumplist_win.cc
@@ -47,6 +47,7 @@
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/favicon_size.h"
#include "ui/gfx/icon_util.h"
+#include "ui/gfx/image/image_family.h"
using content::BrowserThread;
@@ -236,7 +237,9 @@ bool CreateIconFile(const SkBitmap& bitmap,
// Create an icon file from the favicon attached to the given |page|, and
// save it as the temporary file.
- if (!IconUtil::CreateIconFileFromSkBitmap(bitmap, SkBitmap(), path))
+ gfx::ImageFamily image_family;
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(bitmap));
+ if (!IconUtil::CreateIconFileFromImageFamily(image_family, path))
return false;
// Add this icon file to the list and return its absolute path.
diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc
index 4620240..6d02c63 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc
@@ -36,6 +36,7 @@
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/icon_util.h"
#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_family.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/skia_util.h"
@@ -148,19 +149,20 @@ base::FilePath CreateChromeDesktopShortcutIconForProfile(
if (!app_icon_bitmap.get())
return base::FilePath();
- const SkBitmap badged_bitmap = BadgeIcon(*app_icon_bitmap,
- avatar_bitmap_1x, 1);
+ gfx::ImageFamily badged_bitmaps;
+ badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(
+ 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);
+ if (app_icon_bitmap.get()) {
+ badged_bitmaps.Add(gfx::Image::CreateFrom1xBitmap(
+ BadgeIcon(*app_icon_bitmap, avatar_bitmap_2x, 2)));
+ }
// Finally, write the .ico file containing this new bitmap.
const base::FilePath icon_path =
profile_path.AppendASCII(profiles::internal::kProfileIconFileName);
- if (!IconUtil::CreateIconFileFromSkBitmap(badged_bitmap, large_badged_bitmap,
- icon_path))
+ if (!IconUtil::CreateIconFileFromImageFamily(badged_bitmaps, icon_path))
return base::FilePath();
return icon_path;
diff --git a/chrome/browser/ui/web_applications/web_app_ui.cc b/chrome/browser/ui/web_applications/web_app_ui.cc
index 418e26f..4788e33 100644
--- a/chrome/browser/ui/web_applications/web_app_ui.cc
+++ b/chrome/browser/ui/web_applications/web_app_ui.cc
@@ -40,6 +40,7 @@
#if defined(OS_WIN)
#include "base/win/shortcut.h"
#include "base/win/windows_version.h"
+#include "ui/gfx/icon_util.h"
#endif
using content::BrowserThread;
@@ -50,12 +51,18 @@ namespace {
#if defined(OS_MACOSX)
const int kDesiredSizes[] = {16, 32, 128, 256, 512};
+const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
#elif defined(OS_LINUX)
// Linux supports icons of any size. FreeDesktop Icon Theme Specification states
// that "Minimally you should install a 48x48 icon in the hicolor theme."
const int kDesiredSizes[] = {16, 32, 48, 128, 256, 512};
+const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
+#elif defined(OS_WIN)
+const int* kDesiredSizes = IconUtil::kIconDimensions;
+const size_t kNumDesiredSizes = IconUtil::kNumIconDimensions;
#else
const int kDesiredSizes[] = {32};
+const size_t kNumDesiredSizes = arraysize(kDesiredSizes);
#endif
#if defined(OS_WIN)
@@ -330,7 +337,7 @@ void OnImageLoaded(ShellIntegration::ShortcutInfo shortcut_info,
if (image.IsEmpty()) {
gfx::Image default_icon =
ResourceBundle::GetSharedInstance().GetImageNamed(IDR_APP_DEFAULT_ICON);
- int size = kDesiredSizes[arraysize(kDesiredSizes) - 1];
+ int size = kDesiredSizes[kNumDesiredSizes - 1];
SkBitmap bmp = skia::ImageOperations::Resize(
*default_icon.ToSkBitmap(), skia::ImageOperations::RESIZE_BEST,
size, size);
@@ -430,7 +437,7 @@ void UpdateShortcutInfoAndIconForApp(
// TODO(mgiuca): Have ImageLoader build the ImageFamily directly
// (http://crbug.com/230184).
std::vector<extensions::ImageLoader::ImageRepresentation> info_list;
- for (size_t i = 0; i < arraysize(kDesiredSizes); ++i) {
+ for (size_t i = 0; i < kNumDesiredSizes; ++i) {
int size = kDesiredSizes[i];
extensions::ExtensionResource resource =
extensions::IconsInfo::GetIconResource(
@@ -445,7 +452,7 @@ void UpdateShortcutInfoAndIconForApp(
}
if (info_list.empty()) {
- size_t i = arraysize(kDesiredSizes) - 1;
+ 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.
diff --git a/chrome/browser/web_applications/web_app_win.cc b/chrome/browser/web_applications/web_app_win.cc
index 98d9e2c..5c76336 100644
--- a/chrome/browser/web_applications/web_app_win.cc
+++ b/chrome/browser/web_applications/web_app_win.cc
@@ -12,6 +12,7 @@
#include "base/md5.h"
#include "base/path_service.h"
#include "base/stringprintf.h"
+#include "base/strings/string_piece.h"
#include "base/utf_string_conversions.h"
#include "base/win/shortcut.h"
#include "base/win/windows_version.h"
@@ -29,22 +30,31 @@ const base::FilePath::CharType kIconChecksumFileExt[] =
FILE_PATH_LITERAL(".ico.md5");
// Width and height of icons exported to .ico files.
-// TODO(mgiuca): Remove when icon_util has the capability to save all icon
-// sizes, not just a single particular size.
-const int kIconExportSize = 32;
-// Calculates image checksum using MD5.
-void GetImageCheckSum(const SkBitmap& image, base::MD5Digest* digest) {
+// Calculates checksum of an icon family using MD5.
+// The checksum is derived from all of the icons in the family.
+void GetImageCheckSum(const gfx::ImageFamily& image, base::MD5Digest* digest) {
DCHECK(digest);
+ base::MD5Context md5_context;
+ base::MD5Init(&md5_context);
- SkAutoLockPixels image_lock(image);
- MD5Sum(image.getPixels(), image.getSize(), digest);
+ for (gfx::ImageFamily::const_iterator it = image.begin(); it != image.end();
+ ++it) {
+ SkBitmap bitmap = it->AsBitmap();
+
+ SkAutoLockPixels image_lock(bitmap);
+ base::StringPiece image_data(
+ reinterpret_cast<const char*>(bitmap.getPixels()), bitmap.getSize());
+ base::MD5Update(&md5_context, image_data);
+ }
+
+ base::MD5Final(digest, &md5_context);
}
// Saves |image| as an |icon_file| with the checksum.
bool SaveIconWithCheckSum(const base::FilePath& icon_file,
- const SkBitmap& image) {
- if (!IconUtil::CreateIconFileFromSkBitmap(image, SkBitmap(), icon_file))
+ const gfx::ImageFamily& image) {
+ if (!IconUtil::CreateIconFileFromImageFamily(image, icon_file))
return false;
base::MD5Digest digest;
@@ -57,7 +67,8 @@ bool SaveIconWithCheckSum(const base::FilePath& icon_file,
}
// Returns true if |icon_file| is missing or different from |image|.
-bool ShouldUpdateIcon(const base::FilePath& icon_file, const SkBitmap& image) {
+bool ShouldUpdateIcon(const base::FilePath& icon_file,
+ const gfx::ImageFamily& image) {
base::FilePath checksum_file(
icon_file.ReplaceExtension(kIconChecksumFileExt));
@@ -129,12 +140,8 @@ namespace internals {
// is up to date or successfully updated.
bool CheckAndSaveIcon(const base::FilePath& icon_file,
const gfx::ImageFamily& image) {
- // TODO(mgiuca): Save an icon with all icon sizes, not just an icon at a
- // hard-coded fixed size. http://crbug.com/163864.
- const gfx::Image* icon = image.GetBest(kIconExportSize, kIconExportSize);
- SkBitmap bitmap = icon ? icon->AsBitmap() : SkBitmap();
- if (ShouldUpdateIcon(icon_file, bitmap)) {
- if (SaveIconWithCheckSum(icon_file, bitmap)) {
+ if (ShouldUpdateIcon(icon_file, image)) {
+ if (SaveIconWithCheckSum(icon_file, image)) {
// Refresh shell's icon cache. This call is quite disruptive as user would
// see explorer rebuilding the icon cache. It would be great that we find
// a better way to achieve this.
diff --git a/ui/gfx/icon_util.cc b/ui/gfx/icon_util.cc
index 4ce9779..37ab0d5 100644
--- a/ui/gfx/icon_util.cc
+++ b/ui/gfx/icon_util.cc
@@ -15,6 +15,7 @@
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/gdi_util.h"
#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_family.h"
#include "ui/gfx/size.h"
namespace {
@@ -33,17 +34,117 @@ struct ScopedICONINFO : ICONINFO {
}
};
+// Creates a new ImageFamily, |resized_image_family|, based on the images in
+// |image_family|, but containing images of specific dimensions desirable for
+// Windows icons. For each desired image dimension, it chooses the most
+// appropriate image for that size, and resizes it to the desired size.
+// Returns true on success, false on failure. Failure can occur if
+// |image_family| is empty, all images in the family have size 0x0, or an image
+// has no allocated pixel data.
+// |resized_image_family| must be empty.
+bool BuildResizedImageFamily(const gfx::ImageFamily& image_family,
+ gfx::ImageFamily* resized_image_family) {
+ DCHECK(resized_image_family);
+ DCHECK(resized_image_family->empty());
+
+ for (size_t i = 0; i < IconUtil::kNumIconDimensions; ++i) {
+ int dimension = IconUtil::kIconDimensions[i];
+ gfx::Size size(dimension, dimension);
+ const gfx::Image* best = image_family.GetBest(size);
+ if (!best || best->IsEmpty()) {
+ // Either |image_family| is empty, or all images have size 0x0.
+ return false;
+ }
+
+ // Optimize for the "Large icons" view in Windows Vista+. This view displays
+ // icons at full size if only if there is a 256x256 (kLargeIconSize) image
+ // in the .ico file. Otherwise, it shrinks icons to 48x48 (kMediumIconSize).
+ if (dimension > IconUtil::kMediumIconSize &&
+ best->Width() <= IconUtil::kMediumIconSize &&
+ best->Height() <= IconUtil::kMediumIconSize) {
+ // There is no source icon larger than 48x48, so do not create any
+ // images larger than 48x48. kIconDimensions is sorted in ascending
+ // order, so it is safe to break here.
+ break;
+ }
+
+ if (best->Size() == size) {
+ resized_image_family->Add(*best);
+ } else {
+ // There is no |dimension|x|dimension| source image.
+ // Resize this one to the desired size, and insert it.
+ SkBitmap best_bitmap = best->AsBitmap();
+ // If a gfx::Image was created from a SkBitmap with no allocated pixels,
+ // AsBitmap will return a null bitmap instead. This bitmap will have no
+ // config and a size of 0x0. Check this and fail early, to avoid having
+ // 0x0-sized bitmaps in our resized image family.
+ if (best_bitmap.config() == SkBitmap::kNo_Config)
+ return false;
+ SkBitmap resized_bitmap = skia::ImageOperations::Resize(
+ best_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
+ dimension, dimension);
+ resized_image_family->Add(gfx::Image::CreateFrom1xBitmap(resized_bitmap));
+ }
+ }
+ return true;
+}
+
+// Creates a set of bitmaps from an image family.
+// All images smaller than 256x256 are converted to SkBitmaps, and inserted into
+// |bitmaps| in order of aspect ratio (thinnest to widest), and then ascending
+// size order. If an image of exactly 256x256 is specified, it is converted into
+// PNG format and stored in |png_bytes|. Images with width or height larger than
+// 256 are ignored.
+// |bitmaps| must be an empty vector, and not NULL.
+// Returns true on success, false on failure. This fails if any image in
+// |image_family| is not a 32-bit ARGB image, or is otherwise invalid.
+bool ConvertImageFamilyToBitmaps(
+ const gfx::ImageFamily& image_family,
+ std::vector<SkBitmap>* bitmaps,
+ scoped_refptr<base::RefCountedMemory>* png_bytes) {
+ DCHECK(bitmaps != NULL);
+ DCHECK(bitmaps->empty());
+
+ for (gfx::ImageFamily::const_iterator it = image_family.begin();
+ it != image_family.end(); ++it) {
+ const gfx::Image& image = *it;
+
+ // All images should have one of the kIconDimensions sizes.
+ DCHECK_GT(image.Width(), 0);
+ DCHECK_LE(image.Width(), IconUtil::kLargeIconSize);
+ DCHECK_GT(image.Height(), 0);
+ DCHECK_LE(image.Height(), IconUtil::kLargeIconSize);
+
+ SkBitmap bitmap = image.AsBitmap();
+
+ // Only 32 bit ARGB bitmaps are supported. We also make sure the bitmap has
+ // been properly initialized.
+ SkAutoLockPixels bitmap_lock(bitmap);
+ if ((bitmap.config() != SkBitmap::kARGB_8888_Config) ||
+ (bitmap.getPixels() == NULL)) {
+ return false;
+ }
+
+ // Special case: Icons exactly 256x256 are stored in PNG format.
+ if (image.Width() == IconUtil::kLargeIconSize &&
+ image.Height() == IconUtil::kLargeIconSize) {
+ *png_bytes = image.As1xPNGBytes();
+ } else {
+ bitmaps->push_back(bitmap);
+ }
+ }
+
+ return true;
+}
+
} // namespace
-// Defining the dimensions for the icon images. We store only one value because
-// we always resize to a square image; that is, the value 48 means that we are
-// going to resize the given bitmap to a 48 by 48 pixels bitmap.
-//
// The icon images appear in the icon file in same order in which their
-// corresponding dimensions appear in the |icon_dimensions_| array, so it is
-// important to keep this array sorted. Also note that the maximum icon image
-// size we can handle is 255 by 255.
-const int IconUtil::icon_dimensions_[] = {
+// corresponding dimensions appear in this array, so it is important to keep
+// this array sorted. Also note that the maximum icon image size we can handle
+// is 256 by 256. See:
+// http://msdn.microsoft.com/en-us/library/windows/desktop/aa511280.aspx#size
+const int IconUtil::kIconDimensions[] = {
8, // Recommended by the MSDN as a nice to have icon size.
10, // Used by the Shell (e.g. for shortcuts).
14, // Recommended by the MSDN as a nice to have icon size.
@@ -55,9 +156,13 @@ const int IconUtil::icon_dimensions_[] = {
48, // Alt+Tab icon size.
64, // Recommended by the MSDN as a nice to have icon size.
96, // Recommended by the MSDN as a nice to have icon size.
- 128 // Used by the Shell (e.g. for shortcuts).
+ 128, // Used by the Shell (e.g. for shortcuts).
+ 256 // Used by Vista onwards for large icons.
};
+const size_t IconUtil::kNumIconDimensions = arraysize(kIconDimensions);
+const size_t IconUtil::kNumIconDimensionsUpToMediumSize = 9;
+
HICON IconUtil::CreateHICONFromSkBitmap(const SkBitmap& bitmap) {
// Only 32 bit ARGB bitmaps are supported. We also try to perform as many
// validations as we can on the bitmap.
@@ -342,41 +447,36 @@ SkBitmap IconUtil::CreateSkBitmapFromHICONHelper(HICON icon,
return bitmap;
}
-bool IconUtil::CreateIconFileFromSkBitmap(const SkBitmap& bitmap,
- const SkBitmap& large_bitmap,
- const base::FilePath& icon_path) {
- // Only 32 bit ARGB bitmaps are supported. We also make sure the bitmap has
- // been properly initialized.
- SkAutoLockPixels bitmap_lock(bitmap);
- if ((bitmap.config() != SkBitmap::kARGB_8888_Config) ||
- (bitmap.height() <= 0) || (bitmap.width() <= 0) ||
- (bitmap.getPixels() == NULL)) {
+// static
+bool IconUtil::CreateIconFileFromImageFamily(
+ const gfx::ImageFamily& image_family,
+ const base::FilePath& icon_path) {
+ // Creating a set of bitmaps corresponding to the icon images we'll end up
+ // storing in the icon file. Each bitmap is created by resizing the most
+ // appropriate image from |image_family| to the desired size.
+ gfx::ImageFamily resized_image_family;
+ if (!BuildResizedImageFamily(image_family, &resized_image_family))
return false;
- }
- // If |large_bitmap| was specified, validate its dimension and convert to PNG.
+ std::vector<SkBitmap> bitmaps;
scoped_refptr<base::RefCountedMemory> png_bytes;
- if (!large_bitmap.empty()) {
- CHECK_EQ(kLargeIconSize, large_bitmap.width());
- CHECK_EQ(kLargeIconSize, large_bitmap.height());
- png_bytes = gfx::Image::CreateFrom1xBitmap(large_bitmap).As1xPNGBytes();
- }
+ if (!ConvertImageFamilyToBitmaps(resized_image_family, &bitmaps, &png_bytes))
+ return false;
- // We start by creating the file.
+ // Guaranteed true because BuildResizedImageFamily will provide at least one
+ // image < 256x256.
+ DCHECK(!bitmaps.empty());
+ size_t bitmap_count = bitmaps.size(); // Not including PNG image.
+ // Including PNG image, if any.
+ size_t image_count = bitmap_count + (png_bytes.get() ? 1 : 0);
+
+ // Now that basic checks are done, we can create the file.
base::win::ScopedHandle icon_file(::CreateFile(icon_path.value().c_str(),
GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL));
if (!icon_file.IsValid())
return false;
- // Creating a set of bitmaps corresponding to the icon images we'll end up
- // storing in the icon file. Each bitmap is created by resizing the given
- // bitmap to the desired size.
- std::vector<SkBitmap> bitmaps;
- CreateResizedBitmapSet(bitmap, &bitmaps);
- DCHECK(!bitmaps.empty());
- size_t bitmap_count = bitmaps.size();
-
// Computing the total size of the buffer we need in order to store the
// images in the desired icon format.
size_t buffer_size = ComputeIconFileBufferSize(bitmaps);
@@ -391,14 +491,9 @@ bool IconUtil::CreateIconFileFromSkBitmap(const SkBitmap& bitmap,
std::vector<uint8> buffer(buffer_size);
ICONDIR* icon_dir = reinterpret_cast<ICONDIR*>(&buffer[0]);
icon_dir->idType = kResourceTypeIcon;
- icon_dir->idCount = static_cast<WORD>(bitmap_count);
- size_t icon_dir_count = bitmap_count - 1; // Note DCHECK(!bitmaps.empty())!
-
- // Increment counts if a PNG entry will be added.
- if (png_bytes.get()) {
- icon_dir->idCount++;
- icon_dir_count++;
- }
+ icon_dir->idCount = static_cast<WORD>(image_count);
+ // - 1 because there is already one ICONDIRENTRY in ICONDIR.
+ size_t icon_dir_count = image_count - 1;
size_t offset = sizeof(ICONDIR) + (sizeof(ICONDIRENTRY) * icon_dir_count);
for (size_t i = 0; i < bitmap_count; i++) {
@@ -494,6 +589,8 @@ void IconUtil::SetSingleIconImageInformation(const SkBitmap& bitmap,
DCHECK(icon_image != NULL);
DCHECK_GT(image_offset, 0U);
DCHECK(image_byte_count != NULL);
+ DCHECK_LT(bitmap.width(), kLargeIconSize);
+ DCHECK_LT(bitmap.height(), kLargeIconSize);
// We start by computing certain image values we'll use later on.
size_t xor_mask_size, bytes_in_resource;
@@ -552,41 +649,6 @@ void IconUtil::CopySkBitmapBitsIntoIconBuffer(const SkBitmap& bitmap,
}
}
-void IconUtil::CreateResizedBitmapSet(const SkBitmap& bitmap_to_resize,
- std::vector<SkBitmap>* bitmaps) {
- DCHECK(bitmaps != NULL);
- DCHECK(bitmaps->empty());
-
- bool inserted_original_bitmap = false;
- for (size_t i = 0; i < arraysize(icon_dimensions_); i++) {
- // If the dimensions of the bitmap we are resizing are the same as the
- // current dimensions, then we should insert the bitmap and not a resized
- // bitmap. If the bitmap's dimensions are smaller, we insert our bitmap
- // first so that the bitmaps we return in the vector are sorted based on
- // their dimensions.
- if (!inserted_original_bitmap) {
- if ((bitmap_to_resize.width() == icon_dimensions_[i]) &&
- (bitmap_to_resize.height() == icon_dimensions_[i])) {
- bitmaps->push_back(bitmap_to_resize);
- inserted_original_bitmap = true;
- continue;
- }
-
- if ((bitmap_to_resize.width() < icon_dimensions_[i]) &&
- (bitmap_to_resize.height() < icon_dimensions_[i])) {
- bitmaps->push_back(bitmap_to_resize);
- inserted_original_bitmap = true;
- }
- }
- bitmaps->push_back(skia::ImageOperations::Resize(
- bitmap_to_resize, skia::ImageOperations::RESIZE_LANCZOS3,
- icon_dimensions_[i], icon_dimensions_[i]));
- }
-
- if (!inserted_original_bitmap)
- bitmaps->push_back(bitmap_to_resize);
-}
-
size_t IconUtil::ComputeIconFileBufferSize(const std::vector<SkBitmap>& set) {
DCHECK(!set.empty());
@@ -597,7 +659,8 @@ size_t IconUtil::ComputeIconFileBufferSize(const std::vector<SkBitmap>& set) {
size_t total_buffer_size = sizeof(ICONDIR);
size_t bitmap_count = set.size();
total_buffer_size += sizeof(ICONDIRENTRY) * (bitmap_count - 1);
- DCHECK_GE(bitmap_count, arraysize(icon_dimensions_));
+ // May not have all icon sizes, but must have at least up to medium icon size.
+ DCHECK_GE(bitmap_count, kNumIconDimensionsUpToMediumSize);
// Add the bitmap specific structure sizes.
for (size_t i = 0; i < bitmap_count; i++) {
diff --git a/ui/gfx/icon_util.h b/ui/gfx/icon_util.h
index b48c0a5..7ce5606 100644
--- a/ui/gfx/icon_util.h
+++ b/ui/gfx/icon_util.h
@@ -21,6 +21,7 @@ class FilePath;
}
namespace gfx {
+class ImageFamily;
class Size;
}
class SkBitmap;
@@ -60,6 +61,20 @@ class UI_EXPORT IconUtil {
public:
// The size of the large icon entries in .ico files on Windows Vista+.
static const int kLargeIconSize = 256;
+ // The size of icons in the medium icons view on Windows Vista+. This is the
+ // maximum size Windows will display an icon that does not have a 256x256
+ // image, even at the large or extra large icons views.
+ static const int kMediumIconSize = 48;
+
+ // The dimensions for icon images in Windows icon files. All sizes are square;
+ // that is, the value 48 means a 48x48 pixel image. Sizes are listed in
+ // ascending order.
+ static const int kIconDimensions[];
+
+ // The number of elements in kIconDimensions.
+ static const size_t kNumIconDimensions;
+ // The number of elements in kIconDimensions <= kMediumIconSize.
+ static const size_t kNumIconDimensionsUpToMediumSize;
// Given an SkBitmap object, the function converts the bitmap to a Windows
// icon and returns the corresponding HICON handle. If the function cannot
@@ -99,18 +114,20 @@ class UI_EXPORT IconUtil {
// Creates Windows .ico file at |icon_path|. The icon file is created with
// multiple BMP representations at varying predefined dimensions (by resizing
- // |bitmap|) because Windows uses different image sizes when loading icons,
- // depending on where the icon is drawn (ALT+TAB window, desktop shortcut,
- // Quick Launch, etc.).
+ // an appropriately sized image from |image_family|) because Windows uses
+ // different image sizes when loading icons, depending on where the icon is
+ // drawn (ALT+TAB window, desktop shortcut, Quick Launch, etc.).
//
- // To create an icon file containing a 256x256 PNG entry, which is used by
- // Vista+ for high res icons, specify a non-empty 256x256 SkBitmap for the
- // |large_bitmap| parameter.
+ // If |image_family| contains an image larger than 48x48, the resulting icon
+ // will contain all sizes up to 256x256. The 256x256 image will be stored in
+ // PNG format inside the .ico file. If not, the resulting icon will contain
+ // all sizes up to 48x48.
//
- // The function returns true on success and false otherwise.
- static bool CreateIconFileFromSkBitmap(const SkBitmap& bitmap,
- const SkBitmap& large_bitmap,
- const base::FilePath& icon_path);
+ // The function returns true on success and false otherwise. Returns false if
+ // |image_family| is empty.
+ static bool CreateIconFileFromImageFamily(
+ const gfx::ImageFamily& image_family,
+ const base::FilePath& icon_path);
// Creates a cursor of the specified size from the DIB passed in.
// Returns the cursor on success or NULL on failure.
@@ -181,15 +198,12 @@ class UI_EXPORT IconUtil {
};
#pragma pack(pop)
- FRIEND_TEST_ALL_PREFIXES(IconUtilTest, TestCreateIconFileWithLargeBitmap);
+ friend class IconUtilTest;
// Used for indicating that the .ico contains an icon (rather than a cursor)
// image. This value is set in the |idType| field of the ICONDIR structure.
static const int kResourceTypeIcon = 1;
- // The dimensions of the icon images we insert into the .ico file.
- static const int icon_dimensions_[];
-
// Returns true if any pixel in the given pixels buffer has an non-zero alpha.
static bool PixelsHaveAlpha(const uint32* pixels, size_t num_pixels);
@@ -202,6 +216,9 @@ class UI_EXPORT IconUtil {
// structures within the icon data buffer, this function sets the image
// information (dimensions, color depth, etc.) in the icon structures and
// also copies the underlying icon image into the appropriate location.
+ // The width and height of |bitmap| must be < 256.
+ // (Note that the 256x256 icon is treated specially, as a PNG, and should not
+ // use this method.)
//
// The function will set the data pointed to by |image_byte_count| with the
// number of image bytes written to the buffer. Note that the number of bytes
@@ -220,11 +237,6 @@ class UI_EXPORT IconUtil {
unsigned char* buffer,
size_t buffer_size);
- // Given a single bitmap, this function creates a set of bitmaps with
- // specific dimensions by resizing the given bitmap to the appropriate sizes.
- static void CreateResizedBitmapSet(const SkBitmap& bitmap_to_resize,
- std::vector<SkBitmap>* bitmaps);
-
// Given a set of bitmaps with varying dimensions, this function computes
// the amount of memory needed in order to store the bitmaps as image icons
// in a .ico file.
diff --git a/ui/gfx/icon_util_unittest.cc b/ui/gfx/icon_util_unittest.cc
index 2d71922..a63da08 100644
--- a/ui/gfx/icon_util_unittest.cc
+++ b/ui/gfx/icon_util_unittest.cc
@@ -11,6 +11,7 @@
#include "ui/gfx/gfx_paths.h"
#include "ui/gfx/icon_util.h"
#include "ui/gfx/image/image.h"
+#include "ui/gfx/image/image_family.h"
#include "ui/gfx/size.h"
#include "ui/test/ui_unittests_resource.h"
@@ -20,6 +21,8 @@ static const char kSmallIconName[] = "icon_util/16_X_16_icon.ico";
static const char kLargeIconName[] = "icon_util/128_X_128_icon.ico";
static const char kTempIconFilename[] = "temp_test_icon.ico";
+} // namespace
+
class IconUtilTest : public testing::Test {
public:
virtual void SetUp() OVERRIDE {
@@ -54,6 +57,12 @@ class IconUtilTest : public testing::Test {
return bitmap;
}
+ // Loads an .ico file from |icon_filename| and asserts that it contains all of
+ // the expected icon sizes up to and including |max_icon_size|, and no other
+ // icons. If |max_icon_size| >= 256, this tests for a 256x256 PNG icon entry.
+ void CheckAllIconSizes(const base::FilePath& icon_filename,
+ int max_icon_size);
+
protected:
// The root directory for test files. This should be treated as read-only.
base::FilePath test_data_directory_;
@@ -62,7 +71,70 @@ class IconUtilTest : public testing::Test {
base::ScopedTempDir temp_directory_;
};
-} // namespace
+void IconUtilTest::CheckAllIconSizes(const base::FilePath& icon_filename,
+ int max_icon_size) {
+ ASSERT_TRUE(file_util::PathExists(icon_filename));
+
+ // Determine how many icons to expect, based on |max_icon_size|.
+ int expected_num_icons = 0;
+ for (size_t i = 0; i < IconUtil::kNumIconDimensions; ++i) {
+ if (IconUtil::kIconDimensions[i] > max_icon_size)
+ break;
+ ++expected_num_icons;
+ }
+
+ // First, use the Windows API to load the icon, a basic validity test.
+ HICON icon = LoadIconFromFile(icon_filename, kSmallIconWidth,
+ kSmallIconHeight);
+ EXPECT_NE(static_cast<HICON>(NULL), icon);
+ if (icon != NULL)
+ ::DestroyIcon(icon);
+
+ // Read the file completely into memory.
+ std::string icon_data;
+ ASSERT_TRUE(file_util::ReadFileToString(icon_filename, &icon_data));
+ ASSERT_GE(icon_data.length(), sizeof(IconUtil::ICONDIR));
+
+ // Ensure that it has exactly the expected number and sizes of icons, in the
+ // expected order. This matches each entry of the loaded file's icon directory
+ // with the corresponding element of kIconDimensions.
+ // Also extracts the 256x256 entry as png_entry.
+ const IconUtil::ICONDIR* icon_dir =
+ reinterpret_cast<const IconUtil::ICONDIR*>(icon_data.data());
+ EXPECT_EQ(expected_num_icons, icon_dir->idCount);
+ ASSERT_GE(IconUtil::kNumIconDimensions, icon_dir->idCount);
+ ASSERT_GE(icon_data.length(),
+ sizeof(IconUtil::ICONDIR) +
+ icon_dir->idCount * sizeof(IconUtil::ICONDIRENTRY));
+ const IconUtil::ICONDIRENTRY* png_entry = NULL;
+ for (size_t i = 0; i < icon_dir->idCount; ++i) {
+ const IconUtil::ICONDIRENTRY* entry = &icon_dir->idEntries[i];
+ // Mod 256 because as a special case in ICONDIRENTRY, the value 0 represents
+ // a width or height of 256.
+ int expected_size = IconUtil::kIconDimensions[i] % 256;
+ EXPECT_EQ(expected_size, static_cast<int>(entry->bWidth));
+ EXPECT_EQ(expected_size, static_cast<int>(entry->bHeight));
+ if (entry->bWidth == 0 && entry->bHeight == 0) {
+ EXPECT_EQ(NULL, png_entry);
+ png_entry = entry;
+ }
+ }
+
+ if (max_icon_size >= 256) {
+ ASSERT_TRUE(png_entry);
+
+ // Convert the PNG entry data back to a SkBitmap to ensure it's valid.
+ ASSERT_GE(icon_data.length(),
+ png_entry->dwImageOffset + png_entry->dwBytesInRes);
+ const unsigned char* png_bytes = reinterpret_cast<const unsigned char*>(
+ icon_data.data() + png_entry->dwImageOffset);
+ gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
+ png_bytes, png_entry->dwBytesInRes);
+ SkBitmap bitmap = image.AsBitmap();
+ EXPECT_EQ(256, bitmap.width());
+ EXPECT_EQ(256, bitmap.height());
+ }
+}
// The following test case makes sure IconUtil::SkBitmapFromHICON fails
// gracefully when called with invalid input parameters.
@@ -121,10 +193,11 @@ TEST_F(IconUtilTest, TestBitmapToIconInvalidParameters) {
EXPECT_TRUE(icon == NULL);
}
-// The following test case makes sure IconUtil::CreateIconFileFromSkBitmap
+// The following test case makes sure IconUtil::CreateIconFileFromImageFamily
// fails gracefully when called with invalid input parameters.
TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
scoped_ptr<SkBitmap> bitmap;
+ gfx::ImageFamily image_family;
base::FilePath valid_icon_filename = temp_directory_.path().AppendASCII(
kTempIconFilename);
base::FilePath invalid_icon_filename = temp_directory_.path().AppendASCII(
@@ -134,37 +207,68 @@ TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
bitmap->setConfig(SkBitmap::kA8_Config, kSmallIconWidth, kSmallIconHeight);
- EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap, SkBitmap(),
- valid_icon_filename));
+ // Must allocate pixels or else ImageSkia will ignore the bitmap and just
+ // return an empty image.
+ bitmap->allocPixels();
+ memset(bitmap->getPixels(), 0, bitmap->width() * bitmap->height());
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
+ EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ valid_icon_filename));
EXPECT_FALSE(file_util::PathExists(valid_icon_filename));
// Invalid bitmap size.
+ image_family.clear();
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
bitmap->setConfig(SkBitmap::kARGB_8888_Config, 0, 0);
- EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap, SkBitmap(),
- valid_icon_filename));
+ bitmap->allocPixels();
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
+ EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ valid_icon_filename));
EXPECT_FALSE(file_util::PathExists(valid_icon_filename));
// Bitmap with no allocated pixels.
+ image_family.clear();
bitmap.reset(new SkBitmap);
ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
bitmap->setConfig(SkBitmap::kARGB_8888_Config,
kSmallIconWidth,
kSmallIconHeight);
- EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap, SkBitmap(),
- valid_icon_filename));
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
+ EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ valid_icon_filename));
EXPECT_FALSE(file_util::PathExists(valid_icon_filename));
// Invalid file name.
+ image_family.clear();
bitmap->allocPixels();
// Setting the pixels to black.
memset(bitmap->getPixels(), 0, bitmap->width() * bitmap->height() * 4);
- EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap, SkBitmap(),
- invalid_icon_filename));
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
+ EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ invalid_icon_filename));
EXPECT_FALSE(file_util::PathExists(invalid_icon_filename));
}
+// This test case makes sure IconUtil::CreateIconFileFromImageFamily fails if
+// the image family is empty or invalid.
+TEST_F(IconUtilTest, TestCreateIconFileEmptyImageFamily) {
+ base::FilePath icon_filename = temp_directory_.path().AppendASCII(
+ kTempIconFilename);
+
+ // Empty image family.
+ EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(gfx::ImageFamily(),
+ icon_filename));
+ EXPECT_FALSE(file_util::PathExists(icon_filename));
+
+ // Image family with only an empty image.
+ gfx::ImageFamily image_family;
+ image_family.Add(gfx::Image());
+ EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ icon_filename));
+ EXPECT_FALSE(file_util::PathExists(icon_filename));
+}
+
// This test case makes sure that when we load an icon from disk and convert
// the HICON into a bitmap, the bitmap has the expected format and dimensions.
TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) {
@@ -236,69 +340,71 @@ TEST_F(IconUtilTest, TestBasicCreateHICONFromSkBitmap) {
::DestroyIcon(icon);
}
-// The following test case makes sure IconUtil::CreateIconFileFromSkBitmap
-// creates a valid .ico file given an SkBitmap.
-TEST_F(IconUtilTest, TestCreateIconFile) {
+// This test case makes sure that CreateIconFileFromImageFamily creates a
+// valid .ico file given an ImageFamily, and appropriately creates all icon
+// sizes from the given input.
+TEST_F(IconUtilTest, TestCreateIconFileFromImageFamily) {
+ gfx::ImageFamily image_family;
base::FilePath icon_filename =
temp_directory_.path().AppendASCII(kTempIconFilename);
- SkBitmap bitmap = CreateBlackSkBitmap(kSmallIconWidth, kSmallIconHeight);
- EXPECT_TRUE(IconUtil::CreateIconFileFromSkBitmap(bitmap, SkBitmap(),
- icon_filename));
-
- // We are currently only testing that it is possible to load an icon from
- // the .ico file we just created. We don't really check the additional icon
- // images created by IconUtil::CreateIconFileFromSkBitmap.
- HICON icon = LoadIconFromFile(icon_filename,
- kSmallIconWidth,
- kSmallIconHeight);
- EXPECT_NE(icon, static_cast<HICON>(NULL));
- if (icon != NULL) {
- ::DestroyIcon(icon);
- }
-}
-
-TEST_F(IconUtilTest, TestCreateIconFileWithLargeBitmap) {
- const base::FilePath icon_path(
- temp_directory_.path().AppendASCII(kTempIconFilename));
- const SkBitmap bitmap_48 = CreateBlackSkBitmap(48, 48);
- const SkBitmap bitmap_256 = CreateBlackSkBitmap(256, 256);
-
- // First, create the icon file.
- ASSERT_TRUE(IconUtil::CreateIconFileFromSkBitmap(bitmap_48, bitmap_256,
- icon_path));
- ASSERT_TRUE(file_util::PathExists(icon_path));
-
- // Then, read the file and ensure it has a valid 256x256 PNG icon entry.
- std::string icon_data;
- ASSERT_TRUE(file_util::ReadFileToString(icon_path, &icon_data));
- ASSERT_GE(icon_data.length(), sizeof(IconUtil::ICONDIR));
-
- const IconUtil::ICONDIR* icon_dir =
- reinterpret_cast<const IconUtil::ICONDIR*>(icon_data.data());
- ASSERT_GE(icon_data.length(),
- sizeof(IconUtil::ICONDIR) +
- icon_dir->idCount * sizeof(IconUtil::ICONDIRENTRY));
- const IconUtil::ICONDIRENTRY* png_entry = NULL;
- for (size_t i = 0; i < icon_dir->idCount; ++i) {
- const IconUtil::ICONDIRENTRY* entry = &icon_dir->idEntries[i];
- if (entry->bWidth == 0 && entry->bHeight == 0) {
- EXPECT_EQ(NULL, png_entry);
- png_entry = entry;
- }
- }
- ASSERT_TRUE(png_entry);
-
- // Convert the PNG entry data back to a SkBitmap to ensure it's valid.
- ASSERT_GE(icon_data.length(),
- png_entry->dwImageOffset + png_entry->dwBytesInRes);
- const unsigned char* png_bytes = reinterpret_cast<const unsigned char*>(
- icon_data.data() + png_entry->dwImageOffset);
- gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(png_bytes,
- png_entry->dwBytesInRes);
- SkBitmap bitmap = image.AsBitmap();
- EXPECT_EQ(256, bitmap.width());
- EXPECT_EQ(256, bitmap.height());
+ // Test with only a 16x16 icon. Should only scale up to 48x48.
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(
+ CreateBlackSkBitmap(kSmallIconWidth, kSmallIconHeight)));
+ ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ icon_filename));
+ CheckAllIconSizes(icon_filename, 48);
+
+ // Test with a 48x48 icon. Should only scale down.
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(48, 48)));
+ ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ icon_filename));
+ CheckAllIconSizes(icon_filename, 48);
+
+ // Test with a 64x64 icon. Should scale up to 256x256.
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(64, 64)));
+ ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ icon_filename));
+ CheckAllIconSizes(icon_filename, 256);
+
+ // Test with a 256x256 icon. Should include the 256x256 in the output.
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(
+ CreateBlackSkBitmap(256, 256)));
+ ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ icon_filename));
+ CheckAllIconSizes(icon_filename, 256);
+
+ // Test with a 49x49 icon. Should scale up to 256x256, but exclude the
+ // original 49x49 representation from the output.
+ image_family.clear();
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(49, 49)));
+ ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ icon_filename));
+ CheckAllIconSizes(icon_filename, 256);
+
+ // Test with a non-square 16x32 icon. Should scale up to 48, but exclude the
+ // original 16x32 representation from the output.
+ image_family.clear();
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(16, 32)));
+ ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ icon_filename));
+ CheckAllIconSizes(icon_filename, 48);
+
+ // Test with a non-square 32x49 icon. Should scale up to 256, but exclude the
+ // original 32x49 representation from the output.
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(32, 49)));
+ ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ icon_filename));
+ CheckAllIconSizes(icon_filename, 256);
+
+ // Test with an empty and non-empty image.
+ // The empty image should be ignored.
+ image_family.clear();
+ image_family.Add(gfx::Image());
+ image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(16, 16)));
+ ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
+ icon_filename));
+ CheckAllIconSizes(icon_filename, 48);
}
TEST_F(IconUtilTest, TestCreateSkBitmapFromIconResource48x48) {
@@ -318,3 +424,12 @@ TEST_F(IconUtilTest, TestCreateSkBitmapFromIconResource256x256) {
EXPECT_EQ(256, bitmap->width());
EXPECT_EQ(256, bitmap->height());
}
+
+// This tests that kNumIconDimensionsUpToMediumSize has the correct value.
+TEST_F(IconUtilTest, TestNumIconDimensionsUpToMediumSize) {
+ ASSERT_LE(IconUtil::kNumIconDimensionsUpToMediumSize,
+ IconUtil::kNumIconDimensions);
+ EXPECT_EQ(IconUtil::kMediumIconSize,
+ IconUtil::kIconDimensions[
+ IconUtil::kNumIconDimensionsUpToMediumSize - 1]);
+}
diff --git a/ui/gfx/image/image_family.cc b/ui/gfx/image/image_family.cc
index 27b7f8c..4a43a92 100644
--- a/ui/gfx/image/image_family.cc
+++ b/ui/gfx/image/image_family.cc
@@ -101,6 +101,10 @@ float ImageFamily::GetClosestAspect(float desired_aspect) const {
}
}
+const gfx::Image* ImageFamily::GetBest(const gfx::Size& size) const {
+ return GetBest(size.width(), size.height());
+}
+
const gfx::Image* ImageFamily::GetWithExactAspect(float aspect,
int width) const {
// Find the two images of given aspect ratio on either side of |width|.
diff --git a/ui/gfx/image/image_family.h b/ui/gfx/image/image_family.h
index 28ea7df..78a4524 100644
--- a/ui/gfx/image/image_family.h
+++ b/ui/gfx/image/image_family.h
@@ -14,6 +14,7 @@
namespace gfx {
class ImageSkia;
+class Size;
// A collection of images at different sizes. The images should be different
// representations of the same basic concept (for example, an icon) at various
@@ -111,6 +112,15 @@ class UI_EXPORT ImageFamily {
// aspect ratio. If there are no images in the family, returns NULL.
const gfx::Image* GetBest(int width, int height) const;
+ // Gets the best image to use in a rectangle of |size|.
+ // Gets an image at the same aspect ratio as |size.width()|:|size.height()|,
+ // if possible, or if not, the closest aspect ratio. Among images of that
+ // aspect ratio, returns the smallest image with both its width and height
+ // bigger or equal to the requested size. If none exists, returns the largest
+ // image of that aspect ratio. If there are no images in the family, returns
+ // NULL.
+ const gfx::Image* GetBest(const gfx::Size& size) const;
+
private:
// An <aspect ratio, DIP width> pair.
// A 0x0 image has aspect ratio 1.0. 0xN and Nx0 images are treated as 0x0.