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
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 @@
     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 @@
   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 @@
   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 @@
 // 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 @@
 // 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 @@
     ::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());
+}