summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorasvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-08 19:02:59 +0000
committerasvitkine@chromium.org <asvitkine@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-08 19:02:59 +0000
commit6ed46c8295401386f3764f5155e9c513949f7c1c (patch)
tree5ea7af6ac99f10cc3b705c2623bac68cc4721b84 /ui
parent1f21a52382e86370a3b51a919763fc6bd76657ee (diff)
downloadchromium_src-6ed46c8295401386f3764f5155e9c513949f7c1c.zip
chromium_src-6ed46c8295401386f3764f5155e9c513949f7c1c.tar.gz
chromium_src-6ed46c8295401386f3764f5155e9c513949f7c1c.tar.bz2
Add support for adding 256x256 pngs to Windows .ico files.
These are needed to support the "large icon" view under Vista+. BUG=167277,163864,110379 TEST=New unit test. Review URL: https://chromiumcodereview.appspot.com/11742007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@175567 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r--ui/gfx/icon_util.cc54
-rw-r--r--ui/gfx/icon_util.h18
-rw-r--r--ui/gfx/icon_util_unittest.cc89
3 files changed, 120 insertions, 41 deletions
diff --git a/ui/gfx/icon_util.cc b/ui/gfx/icon_util.cc
index 62b6b98..1c87fa9 100644
--- a/ui/gfx/icon_util.cc
+++ b/ui/gfx/icon_util.cc
@@ -13,6 +13,7 @@
#include "skia/ext/image_operations.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/gdi_util.h"
+#include "ui/gfx/image/image.h"
#include "ui/gfx/size.h"
namespace {
@@ -282,14 +283,24 @@ SkBitmap IconUtil::CreateSkBitmapFromHICONHelper(HICON icon,
}
bool IconUtil::CreateIconFileFromSkBitmap(const SkBitmap& bitmap,
+ const SkBitmap& large_bitmap,
const 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))
+ (bitmap.getPixels() == NULL)) {
return false;
+ }
+
+ // If |large_bitmap| was specified, validate its dimension and convert to PNG.
+ scoped_refptr<base::RefCountedMemory> png_bytes;
+ if (!large_bitmap.empty()) {
+ DCHECK_EQ(256, large_bitmap.width());
+ DCHECK_EQ(256, large_bitmap.height());
+ png_bytes = gfx::Image(large_bitmap).As1xPNGBytes();
+ }
// We start by creating the file.
base::win::ScopedHandle icon_file(::CreateFile(icon_path.value().c_str(),
@@ -309,21 +320,29 @@ bool IconUtil::CreateIconFileFromSkBitmap(const SkBitmap& bitmap,
// 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);
- unsigned char* buffer = new unsigned char[buffer_size];
- DCHECK(buffer != NULL);
- memset(buffer, 0, buffer_size);
+ // Account for the bytes needed for the PNG entry.
+ if (png_bytes.get())
+ buffer_size += sizeof(ICONDIRENTRY) + png_bytes->size();
// Setting the information in the structures residing within the buffer.
// First, we set the information which doesn't require iterating through the
// bitmap set and then we set the bitmap specific structures. In the latter
// step we also copy the actual bits.
- ICONDIR* icon_dir = reinterpret_cast<ICONDIR*>(buffer);
+ std::vector<uint8> buffer(buffer_size);
+ ICONDIR* icon_dir = reinterpret_cast<ICONDIR*>(&buffer[0]);
icon_dir->idType = kResourceTypeIcon;
icon_dir->idCount = 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++;
+ }
+
size_t offset = sizeof(ICONDIR) + (sizeof(ICONDIRENTRY) * icon_dir_count);
for (size_t i = 0; i < bitmap_count; i++) {
- ICONIMAGE* image = reinterpret_cast<ICONIMAGE*>(buffer + offset);
+ ICONIMAGE* image = reinterpret_cast<ICONIMAGE*>(&buffer[offset]);
DCHECK_LT(offset, buffer_size);
size_t icon_image_size = 0;
SetSingleIconImageInformation(bitmaps[i], i, icon_dir, image, offset,
@@ -331,17 +350,32 @@ bool IconUtil::CreateIconFileFromSkBitmap(const SkBitmap& bitmap,
DCHECK_GT(icon_image_size, 0U);
offset += icon_image_size;
}
+
+ // Add the PNG entry, if necessary.
+ if (png_bytes.get()) {
+ ICONDIRENTRY* entry = &icon_dir->idEntries[bitmap_count];
+ entry->bWidth = 0;
+ entry->bHeight = 0;
+ entry->wPlanes = 1;
+ entry->wBitCount = 32;
+ entry->dwBytesInRes = png_bytes->size();
+ entry->dwImageOffset = offset;
+ memcpy(&buffer[offset], png_bytes->front(), png_bytes->size());
+ offset += png_bytes->size();
+ }
+
DCHECK_EQ(offset, buffer_size);
- // Finally, writing the data info the file.
+ // Finally, write the data to the file.
DWORD bytes_written;
bool delete_file = false;
- if (!WriteFile(icon_file.Get(), buffer, buffer_size, &bytes_written, NULL) ||
- bytes_written != buffer_size)
+ if (!WriteFile(icon_file.Get(), &buffer[0], buffer_size, &bytes_written,
+ NULL) ||
+ bytes_written != buffer_size) {
delete_file = true;
+ }
::CloseHandle(icon_file.Take());
- delete [] buffer;
if (delete_file) {
bool success = file_util::Delete(icon_path, false);
DCHECK(success);
diff --git a/ui/gfx/icon_util.h b/ui/gfx/icon_util.h
index edd4961..ae16e01 100644
--- a/ui/gfx/icon_util.h
+++ b/ui/gfx/icon_util.h
@@ -10,6 +10,7 @@
#include <vector>
#include "base/basictypes.h"
+#include "base/gtest_prod_util.h"
#include "ui/base/ui_export.h"
#include "ui/gfx/point.h"
#include "ui/gfx/size.h"
@@ -81,16 +82,19 @@ class UI_EXPORT IconUtil {
// it when it is no longer needed.
static SkBitmap* CreateSkBitmapFromHICON(HICON icon);
- // Given an initialized SkBitmap object and a file name, this function
- // creates a .ico file with the given name using the provided bitmap. The
- // icon file is created with multiple icon images of varying predefined
- // dimensions because Windows uses different image sizes when loading icons,
+ // 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.). |icon_file_name| needs to specify the full path for
- // the desired .ico file.
+ // 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.
//
// The function returns true on success and false otherwise.
static bool CreateIconFileFromSkBitmap(const SkBitmap& bitmap,
+ const SkBitmap& large_bitmap,
const FilePath& icon_path);
// Creates a cursor of the specified size from the DIB passed in.
@@ -139,6 +143,8 @@ class UI_EXPORT IconUtil {
};
#pragma pack(pop)
+ FRIEND_TEST_ALL_PREFIXES(IconUtilTest, TestCreateIconFileWithLargeBitmap);
+
// 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;
diff --git a/ui/gfx/icon_util_unittest.cc b/ui/gfx/icon_util_unittest.cc
index 50c1058..c8963af 100644
--- a/ui/gfx/icon_util_unittest.cc
+++ b/ui/gfx/icon_util_unittest.cc
@@ -3,12 +3,14 @@
// found in the LICENSE file.
#include "base/file_util.h"
+#include "base/files/scoped_temp_dir.h"
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/gfx_paths.h"
#include "ui/gfx/icon_util.h"
+#include "ui/gfx/image/image.h"
#include "ui/gfx/size.h"
namespace {
@@ -41,10 +43,22 @@ class IconUtilTest : public testing::Test {
return icon;
}
+ SkBitmap CreateBlackSkBitmap(int width, int height) {
+ SkBitmap bitmap;
+ bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
+ bitmap.allocPixels();
+ // Setting the pixels to black.
+ memset(bitmap.getPixels(), 0, width * height * 4);
+ return bitmap;
+ }
+
protected:
// The root directory for test files.
FilePath test_data_directory_;
+ // Directory for creating files by this test.
+ base::ScopedTempDir temp_directory_;
+
private:
DISALLOW_COPY_AND_ASSIGN(IconUtilTest);
};
@@ -119,14 +133,14 @@ 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,
+ EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap, SkBitmap(),
valid_icon_filename));
// Invalid bitmap size.
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,
+ EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap, SkBitmap(),
valid_icon_filename));
// Bitmap with no allocated pixels.
@@ -135,14 +149,14 @@ TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
bitmap->setConfig(SkBitmap::kARGB_8888_Config,
kSmallIconWidth,
kSmallIconHeight);
- EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap,
+ EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap, SkBitmap(),
valid_icon_filename));
// Invalid file name.
bitmap->allocPixels();
// Setting the pixels to black.
memset(bitmap->getPixels(), 0, bitmap->width() * bitmap->height() * 4);
- EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap,
+ EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap, SkBitmap(),
invalid_icon_filename));
}
@@ -183,14 +197,8 @@ TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) {
// the returned handle is valid and refers to an icon with the expected
// dimentions color depth etc.
TEST_F(IconUtilTest, TestBasicCreateHICONFromSkBitmap) {
- scoped_ptr<SkBitmap> bitmap;
- bitmap.reset(new SkBitmap);
- ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kARGB_8888_Config,
- kSmallIconWidth,
- kSmallIconHeight);
- bitmap->allocPixels();
- HICON icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
+ SkBitmap bitmap = CreateBlackSkBitmap(kSmallIconWidth, kSmallIconHeight);
+ HICON icon = IconUtil::CreateHICONFromSkBitmap(bitmap);
EXPECT_NE(icon, static_cast<HICON>(NULL));
ICONINFO icon_info;
ASSERT_TRUE(::GetIconInfo(icon, &icon_info));
@@ -226,21 +234,10 @@ TEST_F(IconUtilTest, TestBasicCreateHICONFromSkBitmap) {
// The following test case makes sure IconUtil::CreateIconFileFromSkBitmap
// creates a valid .ico file given an SkBitmap.
TEST_F(IconUtilTest, TestCreateIconFile) {
- scoped_ptr<SkBitmap> bitmap;
FilePath icon_filename = test_data_directory_.AppendASCII(kTempIconFilename);
- // Allocating the bitmap.
- bitmap.reset(new SkBitmap);
- ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
- bitmap->setConfig(SkBitmap::kARGB_8888_Config,
- kSmallIconWidth,
- kSmallIconHeight);
- bitmap->allocPixels();
-
- // Setting the pixels to black.
- memset(bitmap->getPixels(), 0, bitmap->width() * bitmap->height() * 4);
-
- EXPECT_TRUE(IconUtil::CreateIconFileFromSkBitmap(*bitmap,
+ 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
@@ -254,3 +251,45 @@ TEST_F(IconUtilTest, TestCreateIconFile) {
::DestroyIcon(icon);
}
}
+
+TEST_F(IconUtilTest, TestCreateIconFileWithLargeBitmap) {
+ const FilePath icon_path(temp_directory_.path().AppendASCII("test.ico"));
+ 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());
+}