1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/file_util.h"
6 #include "base/files/scoped_temp_dir.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "base/path_service.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "third_party/skia/include/core/SkBitmap.h"
11 #include "ui/gfx/gfx_paths.h"
12 #include "ui/gfx/icon_util.h"
13 #include "ui/gfx/image/image.h"
14 #include "ui/gfx/size.h"
15 #include "ui/test/ui_unittests_resource.h"
19 static const char kSmallIconName
[] = "icon_util/16_X_16_icon.ico";
20 static const char kLargeIconName
[] = "icon_util/128_X_128_icon.ico";
21 static const char kTempIconFilename
[] = "temp_test_icon.ico";
23 class IconUtilTest
: public testing::Test
{
26 PathService::Get(gfx::DIR_TEST_DATA
, &test_data_directory_
);
30 static const int kSmallIconWidth
= 16;
31 static const int kSmallIconHeight
= 16;
32 static const int kLargeIconWidth
= 128;
33 static const int kLargeIconHeight
= 128;
35 // Given a file name for an .ico file and an image dimentions, this
36 // function loads the icon and returns an HICON handle.
37 HICON
LoadIconFromFile(const base::FilePath
& filename
,
38 int width
, int height
) {
39 HICON icon
= static_cast<HICON
>(LoadImage(NULL
,
40 filename
.value().c_str(),
44 LR_LOADTRANSPARENT
| LR_LOADFROMFILE
));
48 SkBitmap
CreateBlackSkBitmap(int width
, int height
) {
50 bitmap
.setConfig(SkBitmap::kARGB_8888_Config
, width
, height
);
52 // Setting the pixels to black.
53 memset(bitmap
.getPixels(), 0, width
* height
* 4);
58 // The root directory for test files.
59 base::FilePath test_data_directory_
;
61 // Directory for creating files by this test.
62 base::ScopedTempDir temp_directory_
;
65 DISALLOW_COPY_AND_ASSIGN(IconUtilTest
);
70 // The following test case makes sure IconUtil::SkBitmapFromHICON fails
71 // gracefully when called with invalid input parameters.
72 TEST_F(IconUtilTest
, TestIconToBitmapInvalidParameters
) {
73 base::FilePath icon_filename
=
74 test_data_directory_
.AppendASCII(kSmallIconName
);
75 gfx::Size
icon_size(kSmallIconWidth
, kSmallIconHeight
);
76 HICON icon
= LoadIconFromFile(icon_filename
,
79 ASSERT_TRUE(icon
!= NULL
);
81 // Invalid size parameter.
82 gfx::Size
invalid_icon_size(kSmallIconHeight
, 0);
83 EXPECT_EQ(IconUtil::CreateSkBitmapFromHICON(icon
, invalid_icon_size
),
84 static_cast<SkBitmap
*>(NULL
));
87 EXPECT_EQ(IconUtil::CreateSkBitmapFromHICON(NULL
, icon_size
),
88 static_cast<SkBitmap
*>(NULL
));
90 // The following code should succeed.
91 scoped_ptr
<SkBitmap
> bitmap
;
92 bitmap
.reset(IconUtil::CreateSkBitmapFromHICON(icon
, icon_size
));
93 EXPECT_NE(bitmap
.get(), static_cast<SkBitmap
*>(NULL
));
97 // The following test case makes sure IconUtil::CreateHICONFromSkBitmap fails
98 // gracefully when called with invalid input parameters.
99 TEST_F(IconUtilTest
, TestBitmapToIconInvalidParameters
) {
101 scoped_ptr
<SkBitmap
> bitmap
;
103 // Wrong bitmap format.
104 bitmap
.reset(new SkBitmap
);
105 ASSERT_NE(bitmap
.get(), static_cast<SkBitmap
*>(NULL
));
106 bitmap
->setConfig(SkBitmap::kA8_Config
, kSmallIconWidth
, kSmallIconHeight
);
107 icon
= IconUtil::CreateHICONFromSkBitmap(*bitmap
);
108 EXPECT_EQ(icon
, static_cast<HICON
>(NULL
));
110 // Invalid bitmap size.
111 bitmap
.reset(new SkBitmap
);
112 ASSERT_NE(bitmap
.get(), static_cast<SkBitmap
*>(NULL
));
113 bitmap
->setConfig(SkBitmap::kARGB_8888_Config
, 0, 0);
114 icon
= IconUtil::CreateHICONFromSkBitmap(*bitmap
);
115 EXPECT_EQ(icon
, static_cast<HICON
>(NULL
));
117 // Valid bitmap configuration but no pixels allocated.
118 bitmap
.reset(new SkBitmap
);
119 ASSERT_NE(bitmap
.get(), static_cast<SkBitmap
*>(NULL
));
120 bitmap
->setConfig(SkBitmap::kARGB_8888_Config
,
123 icon
= IconUtil::CreateHICONFromSkBitmap(*bitmap
);
124 EXPECT_TRUE(icon
== NULL
);
127 // The following test case makes sure IconUtil::CreateIconFileFromSkBitmap
128 // fails gracefully when called with invalid input parameters.
129 TEST_F(IconUtilTest
, TestCreateIconFileInvalidParameters
) {
130 scoped_ptr
<SkBitmap
> bitmap
;
131 base::FilePath valid_icon_filename
= test_data_directory_
.AppendASCII(
133 base::FilePath
invalid_icon_filename(FILE_PATH_LITERAL("C:\\<>?.ico"));
135 // Wrong bitmap format.
136 bitmap
.reset(new SkBitmap
);
137 ASSERT_NE(bitmap
.get(), static_cast<SkBitmap
*>(NULL
));
138 bitmap
->setConfig(SkBitmap::kA8_Config
, kSmallIconWidth
, kSmallIconHeight
);
139 EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap
, SkBitmap(),
140 valid_icon_filename
));
142 // Invalid bitmap size.
143 bitmap
.reset(new SkBitmap
);
144 ASSERT_NE(bitmap
.get(), static_cast<SkBitmap
*>(NULL
));
145 bitmap
->setConfig(SkBitmap::kARGB_8888_Config
, 0, 0);
146 EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap
, SkBitmap(),
147 valid_icon_filename
));
149 // Bitmap with no allocated pixels.
150 bitmap
.reset(new SkBitmap
);
151 ASSERT_NE(bitmap
.get(), static_cast<SkBitmap
*>(NULL
));
152 bitmap
->setConfig(SkBitmap::kARGB_8888_Config
,
155 EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap
, SkBitmap(),
156 valid_icon_filename
));
158 // Invalid file name.
159 bitmap
->allocPixels();
160 // Setting the pixels to black.
161 memset(bitmap
->getPixels(), 0, bitmap
->width() * bitmap
->height() * 4);
162 EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap
, SkBitmap(),
163 invalid_icon_filename
));
166 // This test case makes sure that when we load an icon from disk and convert
167 // the HICON into a bitmap, the bitmap has the expected format and dimentions.
168 TEST_F(IconUtilTest
, TestCreateSkBitmapFromHICON
) {
169 scoped_ptr
<SkBitmap
> bitmap
;
170 base::FilePath small_icon_filename
= test_data_directory_
.AppendASCII(
172 gfx::Size
small_icon_size(kSmallIconWidth
, kSmallIconHeight
);
173 HICON small_icon
= LoadIconFromFile(small_icon_filename
,
174 small_icon_size
.width(),
175 small_icon_size
.height());
176 ASSERT_NE(small_icon
, static_cast<HICON
>(NULL
));
177 bitmap
.reset(IconUtil::CreateSkBitmapFromHICON(small_icon
, small_icon_size
));
178 ASSERT_NE(bitmap
.get(), static_cast<SkBitmap
*>(NULL
));
179 EXPECT_EQ(bitmap
->width(), small_icon_size
.width());
180 EXPECT_EQ(bitmap
->height(), small_icon_size
.height());
181 EXPECT_EQ(bitmap
->config(), SkBitmap::kARGB_8888_Config
);
182 ::DestroyIcon(small_icon
);
184 base::FilePath large_icon_filename
= test_data_directory_
.AppendASCII(
186 gfx::Size
large_icon_size(kLargeIconWidth
, kLargeIconHeight
);
187 HICON large_icon
= LoadIconFromFile(large_icon_filename
,
188 large_icon_size
.width(),
189 large_icon_size
.height());
190 ASSERT_NE(large_icon
, static_cast<HICON
>(NULL
));
191 bitmap
.reset(IconUtil::CreateSkBitmapFromHICON(large_icon
, large_icon_size
));
192 ASSERT_NE(bitmap
.get(), static_cast<SkBitmap
*>(NULL
));
193 EXPECT_EQ(bitmap
->width(), large_icon_size
.width());
194 EXPECT_EQ(bitmap
->height(), large_icon_size
.height());
195 EXPECT_EQ(bitmap
->config(), SkBitmap::kARGB_8888_Config
);
196 ::DestroyIcon(large_icon
);
199 // This test case makes sure that when an HICON is created from an SkBitmap,
200 // the returned handle is valid and refers to an icon with the expected
201 // dimentions color depth etc.
202 TEST_F(IconUtilTest
, TestBasicCreateHICONFromSkBitmap
) {
203 SkBitmap bitmap
= CreateBlackSkBitmap(kSmallIconWidth
, kSmallIconHeight
);
204 HICON icon
= IconUtil::CreateHICONFromSkBitmap(bitmap
);
205 EXPECT_NE(icon
, static_cast<HICON
>(NULL
));
207 ASSERT_TRUE(::GetIconInfo(icon
, &icon_info
));
208 EXPECT_TRUE(icon_info
.fIcon
);
210 // Now that have the icon information, we should obtain the specification of
211 // the icon's bitmap and make sure it matches the specification of the
212 // SkBitmap we started with.
214 // The bitmap handle contained in the icon information is a handle to a
215 // compatible bitmap so we need to call ::GetDIBits() in order to retrieve
216 // the bitmap's header information.
217 BITMAPINFO bitmap_info
;
218 ::ZeroMemory(&bitmap_info
, sizeof(BITMAPINFO
));
219 bitmap_info
.bmiHeader
.biSize
= sizeof(BITMAPINFO
);
220 HDC hdc
= ::GetDC(NULL
);
221 int result
= ::GetDIBits(hdc
,
228 ASSERT_GT(result
, 0);
229 EXPECT_EQ(bitmap_info
.bmiHeader
.biWidth
, kSmallIconWidth
);
230 EXPECT_EQ(bitmap_info
.bmiHeader
.biHeight
, kSmallIconHeight
);
231 EXPECT_EQ(bitmap_info
.bmiHeader
.biPlanes
, 1);
232 EXPECT_EQ(bitmap_info
.bmiHeader
.biBitCount
, 32);
233 ::ReleaseDC(NULL
, hdc
);
237 // The following test case makes sure IconUtil::CreateIconFileFromSkBitmap
238 // creates a valid .ico file given an SkBitmap.
239 TEST_F(IconUtilTest
, TestCreateIconFile
) {
240 base::FilePath icon_filename
=
241 test_data_directory_
.AppendASCII(kTempIconFilename
);
243 SkBitmap bitmap
= CreateBlackSkBitmap(kSmallIconWidth
, kSmallIconHeight
);
244 EXPECT_TRUE(IconUtil::CreateIconFileFromSkBitmap(bitmap
, SkBitmap(),
247 // We are currently only testing that it is possible to load an icon from
248 // the .ico file we just created. We don't really check the additional icon
249 // images created by IconUtil::CreateIconFileFromSkBitmap.
250 HICON icon
= LoadIconFromFile(icon_filename
,
253 EXPECT_NE(icon
, static_cast<HICON
>(NULL
));
259 TEST_F(IconUtilTest
, TestCreateIconFileWithLargeBitmap
) {
260 const base::FilePath
icon_path(
261 temp_directory_
.path().AppendASCII("test.ico"));
262 const SkBitmap bitmap_48
= CreateBlackSkBitmap(48, 48);
263 const SkBitmap bitmap_256
= CreateBlackSkBitmap(256, 256);
265 // First, create the icon file.
266 ASSERT_TRUE(IconUtil::CreateIconFileFromSkBitmap(bitmap_48
, bitmap_256
,
268 ASSERT_TRUE(file_util::PathExists(icon_path
));
270 // Then, read the file and ensure it has a valid 256x256 PNG icon entry.
271 std::string icon_data
;
272 ASSERT_TRUE(file_util::ReadFileToString(icon_path
, &icon_data
));
273 ASSERT_GE(icon_data
.length(), sizeof(IconUtil::ICONDIR
));
275 const IconUtil::ICONDIR
* icon_dir
=
276 reinterpret_cast<const IconUtil::ICONDIR
*>(icon_data
.data());
277 ASSERT_GE(icon_data
.length(),
278 sizeof(IconUtil::ICONDIR
) +
279 icon_dir
->idCount
* sizeof(IconUtil::ICONDIRENTRY
));
280 const IconUtil::ICONDIRENTRY
* png_entry
= NULL
;
281 for (size_t i
= 0; i
< icon_dir
->idCount
; ++i
) {
282 const IconUtil::ICONDIRENTRY
* entry
= &icon_dir
->idEntries
[i
];
283 if (entry
->bWidth
== 0 && entry
->bHeight
== 0) {
284 EXPECT_EQ(NULL
, png_entry
);
288 ASSERT_TRUE(png_entry
);
290 // Convert the PNG entry data back to a SkBitmap to ensure it's valid.
291 ASSERT_GE(icon_data
.length(),
292 png_entry
->dwImageOffset
+ png_entry
->dwBytesInRes
);
293 const unsigned char* png_bytes
= reinterpret_cast<const unsigned char*>(
294 icon_data
.data() + png_entry
->dwImageOffset
);
295 gfx::Image image
= gfx::Image::CreateFrom1xPNGBytes(png_bytes
,
296 png_entry
->dwBytesInRes
);
297 SkBitmap bitmap
= image
.AsBitmap();
298 EXPECT_EQ(256, bitmap
.width());
299 EXPECT_EQ(256, bitmap
.height());
302 TEST_F(IconUtilTest
, TestCreateSkBitmapFromIconResource48x48
) {
303 HMODULE module
= GetModuleHandle(NULL
);
304 scoped_ptr
<SkBitmap
> bitmap(
305 IconUtil::CreateSkBitmapFromIconResource(module
, IDR_MAINFRAME
, 48));
306 ASSERT_TRUE(bitmap
.get());
307 EXPECT_EQ(48, bitmap
->width());
308 EXPECT_EQ(48, bitmap
->height());
311 TEST_F(IconUtilTest
, TestCreateSkBitmapFromIconResource256x256
) {
312 HMODULE module
= GetModuleHandle(NULL
);
313 scoped_ptr
<SkBitmap
> bitmap(
314 IconUtil::CreateSkBitmapFromIconResource(module
, IDR_MAINFRAME
, 256));
315 ASSERT_TRUE(bitmap
.get());
316 EXPECT_EQ(256, bitmap
->width());
317 EXPECT_EQ(256, bitmap
->height());