icon_util_unittest.cc revision 5821806d5e7f356e8fa4b058a389a808ea183019
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 "base/file_util.h"
6#include "base/memory/scoped_ptr.h"
7#include "base/path_service.h"
8#include "testing/gtest/include/gtest/gtest.h"
9#include "third_party/skia/include/core/SkBitmap.h"
10#include "ui/gfx/gfx_paths.h"
11#include "ui/gfx/icon_util.h"
12#include "ui/gfx/size.h"
13
14namespace {
15
16static const char kSmallIconName[] = "icon_util/16_X_16_icon.ico";
17static const char kLargeIconName[] = "icon_util/128_X_128_icon.ico";
18static const char kTempIconFilename[] = "temp_test_icon.ico";
19
20class IconUtilTest : public testing::Test {
21 public:
22  IconUtilTest() {
23    PathService::Get(gfx::DIR_TEST_DATA, &test_data_directory_);
24  }
25  ~IconUtilTest() {}
26
27  static const int kSmallIconWidth = 16;
28  static const int kSmallIconHeight = 16;
29  static const int kLargeIconWidth = 128;
30  static const int kLargeIconHeight = 128;
31
32  // Given a file name for an .ico file and an image dimentions, this
33  // function loads the icon and returns an HICON handle.
34  HICON LoadIconFromFile(const FilePath& filename, int width, int height) {
35    HICON icon = static_cast<HICON>(LoadImage(NULL,
36                                    filename.value().c_str(),
37                                    IMAGE_ICON,
38                                    width,
39                                    height,
40                                    LR_LOADTRANSPARENT | LR_LOADFROMFILE));
41    return icon;
42  }
43
44 protected:
45  // The root directory for test files.
46  FilePath test_data_directory_;
47
48 private:
49  DISALLOW_COPY_AND_ASSIGN(IconUtilTest);
50};
51
52}  // namespace
53
54// The following test case makes sure IconUtil::SkBitmapFromHICON fails
55// gracefully when called with invalid input parameters.
56TEST_F(IconUtilTest, TestIconToBitmapInvalidParameters) {
57  FilePath icon_filename = test_data_directory_.AppendASCII(kSmallIconName);
58  gfx::Size icon_size(kSmallIconWidth, kSmallIconHeight);
59  HICON icon = LoadIconFromFile(icon_filename,
60                                icon_size.width(),
61                                icon_size.height());
62  ASSERT_TRUE(icon != NULL);
63
64  // Invalid size parameter.
65  gfx::Size invalid_icon_size(kSmallIconHeight, 0);
66  EXPECT_EQ(IconUtil::CreateSkBitmapFromHICON(icon, invalid_icon_size),
67            static_cast<SkBitmap*>(NULL));
68
69  // Invalid icon.
70  EXPECT_EQ(IconUtil::CreateSkBitmapFromHICON(NULL, icon_size),
71            static_cast<SkBitmap*>(NULL));
72
73  // The following code should succeed.
74  scoped_ptr<SkBitmap> bitmap;
75  bitmap.reset(IconUtil::CreateSkBitmapFromHICON(icon, icon_size));
76  EXPECT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
77  ::DestroyIcon(icon);
78}
79
80// The following test case makes sure IconUtil::CreateHICONFromSkBitmap fails
81// gracefully when called with invalid input parameters.
82TEST_F(IconUtilTest, TestBitmapToIconInvalidParameters) {
83  HICON icon = NULL;
84  scoped_ptr<SkBitmap> bitmap;
85
86  // Wrong bitmap format.
87  bitmap.reset(new SkBitmap);
88  ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
89  bitmap->setConfig(SkBitmap::kA8_Config, kSmallIconWidth, kSmallIconHeight);
90  icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
91  EXPECT_EQ(icon, static_cast<HICON>(NULL));
92
93  // Invalid bitmap size.
94  bitmap.reset(new SkBitmap);
95  ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
96  bitmap->setConfig(SkBitmap::kARGB_8888_Config, 0, 0);
97  icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
98  EXPECT_EQ(icon, static_cast<HICON>(NULL));
99
100  // Valid bitmap configuration but no pixels allocated.
101  bitmap.reset(new SkBitmap);
102  ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
103  bitmap->setConfig(SkBitmap::kARGB_8888_Config,
104                    kSmallIconWidth,
105                    kSmallIconHeight);
106  icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
107  EXPECT_TRUE(icon == NULL);
108}
109
110// The following test case makes sure IconUtil::CreateIconFileFromSkBitmap
111// fails gracefully when called with invalid input parameters.
112TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
113  scoped_ptr<SkBitmap> bitmap;
114  FilePath valid_icon_filename = test_data_directory_.AppendASCII(
115      kSmallIconName);
116  FilePath invalid_icon_filename(FILE_PATH_LITERAL("C:\\<>?.ico"));
117
118  // Wrong bitmap format.
119  bitmap.reset(new SkBitmap);
120  ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
121  bitmap->setConfig(SkBitmap::kA8_Config, kSmallIconWidth, kSmallIconHeight);
122  EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap,
123                                                    valid_icon_filename));
124
125  // Invalid bitmap size.
126  bitmap.reset(new SkBitmap);
127  ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
128  bitmap->setConfig(SkBitmap::kARGB_8888_Config, 0, 0);
129  EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap,
130                                                    valid_icon_filename));
131
132  // Bitmap with no allocated pixels.
133  bitmap.reset(new SkBitmap);
134  ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
135  bitmap->setConfig(SkBitmap::kARGB_8888_Config,
136                    kSmallIconWidth,
137                    kSmallIconHeight);
138  EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap,
139                                                    valid_icon_filename));
140
141  // Invalid file name.
142  bitmap->allocPixels();
143  // Setting the pixels to black.
144  memset(bitmap->getPixels(), 0, bitmap->width() * bitmap->height() * 4);
145  EXPECT_FALSE(IconUtil::CreateIconFileFromSkBitmap(*bitmap,
146                                                    invalid_icon_filename));
147}
148
149// This test case makes sure that when we load an icon from disk and convert
150// the HICON into a bitmap, the bitmap has the expected format and dimentions.
151TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) {
152  scoped_ptr<SkBitmap> bitmap;
153  FilePath small_icon_filename = test_data_directory_.AppendASCII(
154      kSmallIconName);
155  gfx::Size small_icon_size(kSmallIconWidth, kSmallIconHeight);
156  HICON small_icon = LoadIconFromFile(small_icon_filename,
157                                      small_icon_size.width(),
158                                      small_icon_size.height());
159  ASSERT_NE(small_icon, static_cast<HICON>(NULL));
160  bitmap.reset(IconUtil::CreateSkBitmapFromHICON(small_icon, small_icon_size));
161  ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
162  EXPECT_EQ(bitmap->width(), small_icon_size.width());
163  EXPECT_EQ(bitmap->height(), small_icon_size.height());
164  EXPECT_EQ(bitmap->config(), SkBitmap::kARGB_8888_Config);
165  ::DestroyIcon(small_icon);
166
167  FilePath large_icon_filename = test_data_directory_.AppendASCII(
168      kLargeIconName);
169  gfx::Size large_icon_size(kLargeIconWidth, kLargeIconHeight);
170  HICON large_icon = LoadIconFromFile(large_icon_filename,
171                                      large_icon_size.width(),
172                                      large_icon_size.height());
173  ASSERT_NE(large_icon, static_cast<HICON>(NULL));
174  bitmap.reset(IconUtil::CreateSkBitmapFromHICON(large_icon, large_icon_size));
175  ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
176  EXPECT_EQ(bitmap->width(), large_icon_size.width());
177  EXPECT_EQ(bitmap->height(), large_icon_size.height());
178  EXPECT_EQ(bitmap->config(), SkBitmap::kARGB_8888_Config);
179  ::DestroyIcon(large_icon);
180}
181
182// This test case makes sure that when an HICON is created from an SkBitmap,
183// the returned handle is valid and refers to an icon with the expected
184// dimentions color depth etc.
185TEST_F(IconUtilTest, TestBasicCreateHICONFromSkBitmap) {
186  scoped_ptr<SkBitmap> bitmap;
187  bitmap.reset(new SkBitmap);
188  ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
189  bitmap->setConfig(SkBitmap::kARGB_8888_Config,
190                    kSmallIconWidth,
191                    kSmallIconHeight);
192  bitmap->allocPixels();
193  HICON icon = IconUtil::CreateHICONFromSkBitmap(*bitmap);
194  EXPECT_NE(icon, static_cast<HICON>(NULL));
195  ICONINFO icon_info;
196  ASSERT_TRUE(::GetIconInfo(icon, &icon_info));
197  EXPECT_TRUE(icon_info.fIcon);
198
199  // Now that have the icon information, we should obtain the specification of
200  // the icon's bitmap and make sure it matches the specification of the
201  // SkBitmap we started with.
202  //
203  // The bitmap handle contained in the icon information is a handle to a
204  // compatible bitmap so we need to call ::GetDIBits() in order to retrieve
205  // the bitmap's header information.
206  BITMAPINFO bitmap_info;
207  ::ZeroMemory(&bitmap_info, sizeof(BITMAPINFO));
208  bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFO);
209  HDC hdc = ::GetDC(NULL);
210  int result = ::GetDIBits(hdc,
211                           icon_info.hbmColor,
212                           0,
213                           kSmallIconWidth,
214                           NULL,
215                           &bitmap_info,
216                           DIB_RGB_COLORS);
217  ASSERT_GT(result, 0);
218  EXPECT_EQ(bitmap_info.bmiHeader.biWidth, kSmallIconWidth);
219  EXPECT_EQ(bitmap_info.bmiHeader.biHeight, kSmallIconHeight);
220  EXPECT_EQ(bitmap_info.bmiHeader.biPlanes, 1);
221  EXPECT_EQ(bitmap_info.bmiHeader.biBitCount, 32);
222  ::ReleaseDC(NULL, hdc);
223  ::DestroyIcon(icon);
224}
225
226// The following test case makes sure IconUtil::CreateIconFileFromSkBitmap
227// creates a valid .ico file given an SkBitmap.
228TEST_F(IconUtilTest, TestCreateIconFile) {
229  scoped_ptr<SkBitmap> bitmap;
230  FilePath icon_filename = test_data_directory_.AppendASCII(kTempIconFilename);
231
232  // Allocating the bitmap.
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  bitmap->allocPixels();
239
240  // Setting the pixels to black.
241  memset(bitmap->getPixels(), 0, bitmap->width() * bitmap->height() * 4);
242
243  EXPECT_TRUE(IconUtil::CreateIconFileFromSkBitmap(*bitmap,
244                                                   icon_filename));
245
246  // We are currently only testing that it is possible to load an icon from
247  // the .ico file we just created. We don't really check the additional icon
248  // images created by IconUtil::CreateIconFileFromSkBitmap.
249  HICON icon = LoadIconFromFile(icon_filename,
250                                kSmallIconWidth,
251                                kSmallIconHeight);
252  EXPECT_NE(icon, static_cast<HICON>(NULL));
253  if (icon != NULL) {
254    ::DestroyIcon(icon);
255  }
256}
257