Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ui / gfx / icon_util_unittest.cc
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.
4
5 #include "ui/gfx/icon_util.h"
6
7 #include "base/file_util.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/memory/scoped_ptr.h"
10 #include "base/path_service.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12 #include "third_party/skia/include/core/SkBitmap.h"
13 #include "ui/gfx/gfx_paths.h"
14 #include "ui/gfx/icon_util_unittests_resource.h"
15 #include "ui/gfx/image/image.h"
16 #include "ui/gfx/image/image_family.h"
17 #include "ui/gfx/size.h"
18
19 namespace {
20
21 static const char kSmallIconName[] = "icon_util/16_X_16_icon.ico";
22 static const char kLargeIconName[] = "icon_util/128_X_128_icon.ico";
23 static const char kTempIconFilename[] = "temp_test_icon.ico";
24
25 }  // namespace
26
27 class IconUtilTest : public testing::Test {
28  public:
29   virtual void SetUp() OVERRIDE {
30     PathService::Get(gfx::DIR_TEST_DATA, &test_data_directory_);
31     temp_directory_.CreateUniqueTempDir();
32   }
33
34   static const int kSmallIconWidth = 16;
35   static const int kSmallIconHeight = 16;
36   static const int kLargeIconWidth = 128;
37   static const int kLargeIconHeight = 128;
38
39   // Given a file name for an .ico file and an image dimensions, this
40   // function loads the icon and returns an HICON handle.
41   HICON LoadIconFromFile(const base::FilePath& filename,
42                          int width, int height) {
43     HICON icon = static_cast<HICON>(LoadImage(NULL,
44                                     filename.value().c_str(),
45                                     IMAGE_ICON,
46                                     width,
47                                     height,
48                                     LR_LOADTRANSPARENT | LR_LOADFROMFILE));
49     return icon;
50   }
51
52   SkBitmap CreateBlackSkBitmap(int width, int height) {
53     SkBitmap bitmap;
54     bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
55     bitmap.allocPixels();
56     // Setting the pixels to black.
57     memset(bitmap.getPixels(), 0, width * height * 4);
58     return bitmap;
59   }
60
61   // Loads an .ico file from |icon_filename| and asserts that it contains all of
62   // the expected icon sizes up to and including |max_icon_size|, and no other
63   // icons. If |max_icon_size| >= 256, this tests for a 256x256 PNG icon entry.
64   void CheckAllIconSizes(const base::FilePath& icon_filename,
65                          int max_icon_size);
66
67  protected:
68   // The root directory for test files. This should be treated as read-only.
69   base::FilePath test_data_directory_;
70
71   // Directory for creating files by this test.
72   base::ScopedTempDir temp_directory_;
73 };
74
75 void IconUtilTest::CheckAllIconSizes(const base::FilePath& icon_filename,
76                                      int max_icon_size) {
77   ASSERT_TRUE(base::PathExists(icon_filename));
78
79   // Determine how many icons to expect, based on |max_icon_size|.
80   int expected_num_icons = 0;
81   for (size_t i = 0; i < IconUtil::kNumIconDimensions; ++i) {
82     if (IconUtil::kIconDimensions[i] > max_icon_size)
83       break;
84     ++expected_num_icons;
85   }
86
87   // First, use the Windows API to load the icon, a basic validity test.
88   HICON icon = LoadIconFromFile(icon_filename, kSmallIconWidth,
89                                 kSmallIconHeight);
90   EXPECT_NE(static_cast<HICON>(NULL), icon);
91   if (icon != NULL)
92     ::DestroyIcon(icon);
93
94   // Read the file completely into memory.
95   std::string icon_data;
96   ASSERT_TRUE(base::ReadFileToString(icon_filename, &icon_data));
97   ASSERT_GE(icon_data.length(), sizeof(IconUtil::ICONDIR));
98
99   // Ensure that it has exactly the expected number and sizes of icons, in the
100   // expected order. This matches each entry of the loaded file's icon directory
101   // with the corresponding element of kIconDimensions.
102   // Also extracts the 256x256 entry as png_entry.
103   const IconUtil::ICONDIR* icon_dir =
104       reinterpret_cast<const IconUtil::ICONDIR*>(icon_data.data());
105   EXPECT_EQ(expected_num_icons, icon_dir->idCount);
106   ASSERT_GE(IconUtil::kNumIconDimensions, icon_dir->idCount);
107   ASSERT_GE(icon_data.length(),
108             sizeof(IconUtil::ICONDIR) +
109                 icon_dir->idCount * sizeof(IconUtil::ICONDIRENTRY));
110   const IconUtil::ICONDIRENTRY* png_entry = NULL;
111   for (size_t i = 0; i < icon_dir->idCount; ++i) {
112     const IconUtil::ICONDIRENTRY* entry = &icon_dir->idEntries[i];
113     // Mod 256 because as a special case in ICONDIRENTRY, the value 0 represents
114     // a width or height of 256.
115     int expected_size = IconUtil::kIconDimensions[i] % 256;
116     EXPECT_EQ(expected_size, static_cast<int>(entry->bWidth));
117     EXPECT_EQ(expected_size, static_cast<int>(entry->bHeight));
118     if (entry->bWidth == 0 && entry->bHeight == 0) {
119       EXPECT_EQ(NULL, png_entry);
120       png_entry = entry;
121     }
122   }
123
124   if (max_icon_size >= 256) {
125     ASSERT_TRUE(png_entry);
126
127     // Convert the PNG entry data back to a SkBitmap to ensure it's valid.
128     ASSERT_GE(icon_data.length(),
129               png_entry->dwImageOffset + png_entry->dwBytesInRes);
130     const unsigned char* png_bytes = reinterpret_cast<const unsigned char*>(
131         icon_data.data() + png_entry->dwImageOffset);
132     gfx::Image image = gfx::Image::CreateFrom1xPNGBytes(
133         png_bytes, png_entry->dwBytesInRes);
134     SkBitmap bitmap = image.AsBitmap();
135     EXPECT_EQ(256, bitmap.width());
136     EXPECT_EQ(256, bitmap.height());
137   }
138 }
139
140 // The following test case makes sure IconUtil::SkBitmapFromHICON fails
141 // gracefully when called with invalid input parameters.
142 TEST_F(IconUtilTest, TestIconToBitmapInvalidParameters) {
143   base::FilePath icon_filename =
144       test_data_directory_.AppendASCII(kSmallIconName);
145   gfx::Size icon_size(kSmallIconWidth, kSmallIconHeight);
146   HICON icon = LoadIconFromFile(icon_filename,
147                                 icon_size.width(),
148                                 icon_size.height());
149   ASSERT_TRUE(icon != NULL);
150
151   // Invalid size parameter.
152   gfx::Size invalid_icon_size(kSmallIconHeight, 0);
153   EXPECT_EQ(IconUtil::CreateSkBitmapFromHICON(icon, invalid_icon_size),
154             static_cast<SkBitmap*>(NULL));
155
156   // Invalid icon.
157   EXPECT_EQ(IconUtil::CreateSkBitmapFromHICON(NULL, icon_size),
158             static_cast<SkBitmap*>(NULL));
159
160   // The following code should succeed.
161   scoped_ptr<SkBitmap> bitmap;
162   bitmap.reset(IconUtil::CreateSkBitmapFromHICON(icon, icon_size));
163   EXPECT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
164   ::DestroyIcon(icon);
165 }
166
167 // The following test case makes sure IconUtil::CreateHICONFromSkBitmap fails
168 // gracefully when called with invalid input parameters.
169 TEST_F(IconUtilTest, TestBitmapToIconInvalidParameters) {
170   HICON icon = NULL;
171   scoped_ptr<SkBitmap> bitmap;
172
173   // Wrong bitmap format.
174   bitmap.reset(new SkBitmap);
175   ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
176   bitmap->setConfig(SkBitmap::kA8_Config, kSmallIconWidth, kSmallIconHeight);
177   icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
178   EXPECT_EQ(icon, static_cast<HICON>(NULL));
179
180   // Invalid bitmap size.
181   bitmap.reset(new SkBitmap);
182   ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
183   bitmap->setConfig(SkBitmap::kARGB_8888_Config, 0, 0);
184   icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
185   EXPECT_EQ(icon, static_cast<HICON>(NULL));
186
187   // Valid bitmap configuration but no pixels allocated.
188   bitmap.reset(new SkBitmap);
189   ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
190   bitmap->setConfig(SkBitmap::kARGB_8888_Config,
191                     kSmallIconWidth,
192                     kSmallIconHeight);
193   icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
194   EXPECT_TRUE(icon == NULL);
195 }
196
197 // The following test case makes sure IconUtil::CreateIconFileFromImageFamily
198 // fails gracefully when called with invalid input parameters.
199 TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
200   scoped_ptr<SkBitmap> bitmap;
201   gfx::ImageFamily image_family;
202   base::FilePath valid_icon_filename = temp_directory_.path().AppendASCII(
203       kTempIconFilename);
204   base::FilePath invalid_icon_filename = temp_directory_.path().AppendASCII(
205       "<>?.ico");
206
207   // Wrong bitmap format.
208   bitmap.reset(new SkBitmap);
209   ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
210   bitmap->setConfig(SkBitmap::kA8_Config, kSmallIconWidth, kSmallIconHeight);
211   // Must allocate pixels or else ImageSkia will ignore the bitmap and just
212   // return an empty image.
213   bitmap->allocPixels();
214   memset(bitmap->getPixels(), 0, bitmap->width() * bitmap->height());
215   image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
216   EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
217                                                        valid_icon_filename));
218   EXPECT_FALSE(base::PathExists(valid_icon_filename));
219
220   // Invalid bitmap size.
221   image_family.clear();
222   bitmap.reset(new SkBitmap);
223   ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
224   bitmap->setConfig(SkBitmap::kARGB_8888_Config, 0, 0);
225   bitmap->allocPixels();
226   image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
227   EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
228                                                        valid_icon_filename));
229   EXPECT_FALSE(base::PathExists(valid_icon_filename));
230
231   // Bitmap with no allocated pixels.
232   image_family.clear();
233   bitmap.reset(new SkBitmap);
234   ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
235   bitmap->setConfig(SkBitmap::kARGB_8888_Config,
236                     kSmallIconWidth,
237                     kSmallIconHeight);
238   image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
239   EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
240                                                        valid_icon_filename));
241   EXPECT_FALSE(base::PathExists(valid_icon_filename));
242
243   // Invalid file name.
244   image_family.clear();
245   bitmap->allocPixels();
246   // Setting the pixels to black.
247   memset(bitmap->getPixels(), 0, bitmap->width() * bitmap->height() * 4);
248   image_family.Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
249   EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
250                                                        invalid_icon_filename));
251   EXPECT_FALSE(base::PathExists(invalid_icon_filename));
252 }
253
254 // This test case makes sure IconUtil::CreateIconFileFromImageFamily fails if
255 // the image family is empty or invalid.
256 TEST_F(IconUtilTest, TestCreateIconFileEmptyImageFamily) {
257   base::FilePath icon_filename = temp_directory_.path().AppendASCII(
258       kTempIconFilename);
259
260   // Empty image family.
261   EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(gfx::ImageFamily(),
262                                                        icon_filename));
263   EXPECT_FALSE(base::PathExists(icon_filename));
264
265   // Image family with only an empty image.
266   gfx::ImageFamily image_family;
267   image_family.Add(gfx::Image());
268   EXPECT_FALSE(IconUtil::CreateIconFileFromImageFamily(image_family,
269                                                        icon_filename));
270   EXPECT_FALSE(base::PathExists(icon_filename));
271 }
272
273 // This test case makes sure that when we load an icon from disk and convert
274 // the HICON into a bitmap, the bitmap has the expected format and dimensions.
275 TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) {
276   scoped_ptr<SkBitmap> bitmap;
277   base::FilePath small_icon_filename = test_data_directory_.AppendASCII(
278       kSmallIconName);
279   gfx::Size small_icon_size(kSmallIconWidth, kSmallIconHeight);
280   HICON small_icon = LoadIconFromFile(small_icon_filename,
281                                       small_icon_size.width(),
282                                       small_icon_size.height());
283   ASSERT_NE(small_icon, static_cast<HICON>(NULL));
284   bitmap.reset(IconUtil::CreateSkBitmapFromHICON(small_icon, small_icon_size));
285   ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
286   EXPECT_EQ(bitmap->width(), small_icon_size.width());
287   EXPECT_EQ(bitmap->height(), small_icon_size.height());
288   EXPECT_EQ(bitmap->config(), SkBitmap::kARGB_8888_Config);
289   ::DestroyIcon(small_icon);
290
291   base::FilePath large_icon_filename = test_data_directory_.AppendASCII(
292       kLargeIconName);
293   gfx::Size large_icon_size(kLargeIconWidth, kLargeIconHeight);
294   HICON large_icon = LoadIconFromFile(large_icon_filename,
295                                       large_icon_size.width(),
296                                       large_icon_size.height());
297   ASSERT_NE(large_icon, static_cast<HICON>(NULL));
298   bitmap.reset(IconUtil::CreateSkBitmapFromHICON(large_icon, large_icon_size));
299   ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
300   EXPECT_EQ(bitmap->width(), large_icon_size.width());
301   EXPECT_EQ(bitmap->height(), large_icon_size.height());
302   EXPECT_EQ(bitmap->config(), SkBitmap::kARGB_8888_Config);
303   ::DestroyIcon(large_icon);
304 }
305
306 // This test case makes sure that when an HICON is created from an SkBitmap,
307 // the returned handle is valid and refers to an icon with the expected
308 // dimensions color depth etc.
309 TEST_F(IconUtilTest, TestBasicCreateHICONFromSkBitmap) {
310   SkBitmap bitmap = CreateBlackSkBitmap(kSmallIconWidth, kSmallIconHeight);
311   HICON icon = IconUtil::CreateHICONFromSkBitmap(bitmap);
312   EXPECT_NE(icon, static_cast<HICON>(NULL));
313   ICONINFO icon_info;
314   ASSERT_TRUE(::GetIconInfo(icon, &icon_info));
315   EXPECT_TRUE(icon_info.fIcon);
316
317   // Now that have the icon information, we should obtain the specification of
318   // the icon's bitmap and make sure it matches the specification of the
319   // SkBitmap we started with.
320   //
321   // The bitmap handle contained in the icon information is a handle to a
322   // compatible bitmap so we need to call ::GetDIBits() in order to retrieve
323   // the bitmap's header information.
324   BITMAPINFO bitmap_info;
325   ::ZeroMemory(&bitmap_info, sizeof(BITMAPINFO));
326   bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFO);
327   HDC hdc = ::GetDC(NULL);
328   int result = ::GetDIBits(hdc,
329                            icon_info.hbmColor,
330                            0,
331                            kSmallIconWidth,
332                            NULL,
333                            &bitmap_info,
334                            DIB_RGB_COLORS);
335   ASSERT_GT(result, 0);
336   EXPECT_EQ(bitmap_info.bmiHeader.biWidth, kSmallIconWidth);
337   EXPECT_EQ(bitmap_info.bmiHeader.biHeight, kSmallIconHeight);
338   EXPECT_EQ(bitmap_info.bmiHeader.biPlanes, 1);
339   EXPECT_EQ(bitmap_info.bmiHeader.biBitCount, 32);
340   ::ReleaseDC(NULL, hdc);
341   ::DestroyIcon(icon);
342 }
343
344 // This test case makes sure that CreateIconFileFromImageFamily creates a
345 // valid .ico file given an ImageFamily, and appropriately creates all icon
346 // sizes from the given input.
347 TEST_F(IconUtilTest, TestCreateIconFileFromImageFamily) {
348   gfx::ImageFamily image_family;
349   base::FilePath icon_filename =
350       temp_directory_.path().AppendASCII(kTempIconFilename);
351
352   // Test with only a 16x16 icon. Should only scale up to 48x48.
353   image_family.Add(gfx::Image::CreateFrom1xBitmap(
354       CreateBlackSkBitmap(kSmallIconWidth, kSmallIconHeight)));
355   ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
356                                                       icon_filename));
357   CheckAllIconSizes(icon_filename, 48);
358
359   // Test with a 48x48 icon. Should only scale down.
360   image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(48, 48)));
361   ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
362                                                       icon_filename));
363   CheckAllIconSizes(icon_filename, 48);
364
365   // Test with a 64x64 icon. Should scale up to 256x256.
366   image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(64, 64)));
367   ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
368                                                       icon_filename));
369   CheckAllIconSizes(icon_filename, 256);
370
371   // Test with a 256x256 icon. Should include the 256x256 in the output.
372   image_family.Add(gfx::Image::CreateFrom1xBitmap(
373       CreateBlackSkBitmap(256, 256)));
374   ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
375                                                       icon_filename));
376   CheckAllIconSizes(icon_filename, 256);
377
378   // Test with a 49x49 icon. Should scale up to 256x256, but exclude the
379   // original 49x49 representation from the output.
380   image_family.clear();
381   image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(49, 49)));
382   ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
383                                                       icon_filename));
384   CheckAllIconSizes(icon_filename, 256);
385
386   // Test with a non-square 16x32 icon. Should scale up to 48, but exclude the
387   // original 16x32 representation from the output.
388   image_family.clear();
389   image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(16, 32)));
390   ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
391                                                       icon_filename));
392   CheckAllIconSizes(icon_filename, 48);
393
394   // Test with a non-square 32x49 icon. Should scale up to 256, but exclude the
395   // original 32x49 representation from the output.
396   image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(32, 49)));
397   ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
398                                                       icon_filename));
399   CheckAllIconSizes(icon_filename, 256);
400
401   // Test with an empty and non-empty image.
402   // The empty image should be ignored.
403   image_family.clear();
404   image_family.Add(gfx::Image());
405   image_family.Add(gfx::Image::CreateFrom1xBitmap(CreateBlackSkBitmap(16, 16)));
406   ASSERT_TRUE(IconUtil::CreateIconFileFromImageFamily(image_family,
407                                                        icon_filename));
408   CheckAllIconSizes(icon_filename, 48);
409 }
410
411 TEST_F(IconUtilTest, TestCreateSkBitmapFromIconResource48x48) {
412   HMODULE module = GetModuleHandle(NULL);
413   scoped_ptr<SkBitmap> bitmap(
414       IconUtil::CreateSkBitmapFromIconResource(module, IDR_MAINFRAME, 48));
415   ASSERT_TRUE(bitmap.get());
416   EXPECT_EQ(48, bitmap->width());
417   EXPECT_EQ(48, bitmap->height());
418 }
419
420 TEST_F(IconUtilTest, TestCreateSkBitmapFromIconResource256x256) {
421   HMODULE module = GetModuleHandle(NULL);
422   scoped_ptr<SkBitmap> bitmap(
423       IconUtil::CreateSkBitmapFromIconResource(module, IDR_MAINFRAME, 256));
424   ASSERT_TRUE(bitmap.get());
425   EXPECT_EQ(256, bitmap->width());
426   EXPECT_EQ(256, bitmap->height());
427 }
428
429 // This tests that kNumIconDimensionsUpToMediumSize has the correct value.
430 TEST_F(IconUtilTest, TestNumIconDimensionsUpToMediumSize) {
431   ASSERT_LE(IconUtil::kNumIconDimensionsUpToMediumSize,
432             IconUtil::kNumIconDimensions);
433   EXPECT_EQ(IconUtil::kMediumIconSize,
434             IconUtil::kIconDimensions[
435                 IconUtil::kNumIconDimensionsUpToMediumSize - 1]);
436 }