Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(404)

Side by Side Diff: ui/gfx/icon_util_unittest.cc

Issue 1406403007: Eliminate HICON leaks caused by creating icons from bitmap image. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/gfx/icon_util.cc ('k') | ui/gfx/path_win.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "ui/gfx/icon_util.h" 5 #include "ui/gfx/icon_util.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/files/file_util.h" 9 #include "base/files/file_util.h"
10 #include "base/files/scoped_temp_dir.h" 10 #include "base/files/scoped_temp_dir.h"
(...skipping 10 matching lines...) Expand all
21 namespace { 21 namespace {
22 22
23 static const char kSmallIconName[] = "icon_util/16_X_16_icon.ico"; 23 static const char kSmallIconName[] = "icon_util/16_X_16_icon.ico";
24 static const char kLargeIconName[] = "icon_util/128_X_128_icon.ico"; 24 static const char kLargeIconName[] = "icon_util/128_X_128_icon.ico";
25 static const char kTempIconFilename[] = "temp_test_icon.ico"; 25 static const char kTempIconFilename[] = "temp_test_icon.ico";
26 26
27 } // namespace 27 } // namespace
28 28
29 class IconUtilTest : public testing::Test { 29 class IconUtilTest : public testing::Test {
30 public: 30 public:
31 using ScopedHICON = base::win::ScopedHICON;
32
31 void SetUp() override { 33 void SetUp() override {
32 gfx::RegisterPathProvider(); 34 gfx::RegisterPathProvider();
33 ASSERT_TRUE(PathService::Get(gfx::DIR_TEST_DATA, &test_data_directory_)); 35 ASSERT_TRUE(PathService::Get(gfx::DIR_TEST_DATA, &test_data_directory_));
34 ASSERT_TRUE(temp_directory_.CreateUniqueTempDir()); 36 ASSERT_TRUE(temp_directory_.CreateUniqueTempDir());
35 } 37 }
36 38
37 static const int kSmallIconWidth = 16; 39 static const int kSmallIconWidth = 16;
38 static const int kSmallIconHeight = 16; 40 static const int kSmallIconHeight = 16;
39 static const int kLargeIconWidth = 128; 41 static const int kLargeIconWidth = 128;
40 static const int kLargeIconHeight = 128; 42 static const int kLargeIconHeight = 128;
41 43
42 // Given a file name for an .ico file and an image dimensions, this 44 // Given a file name for an .ico file and an image dimensions, this
43 // function loads the icon and returns an HICON handle. 45 // function loads the icon and returns an HICON handle.
44 HICON LoadIconFromFile(const base::FilePath& filename, 46 ScopedHICON LoadIconFromFile(const base::FilePath& filename,
45 int width, int height) { 47 int width,
48 int height) {
46 HICON icon = static_cast<HICON>(LoadImage(NULL, 49 HICON icon = static_cast<HICON>(LoadImage(NULL,
47 filename.value().c_str(), 50 filename.value().c_str(),
48 IMAGE_ICON, 51 IMAGE_ICON,
49 width, 52 width,
50 height, 53 height,
51 LR_LOADTRANSPARENT | LR_LOADFROMFILE)); 54 LR_LOADTRANSPARENT | LR_LOADFROMFILE));
52 return icon; 55 return ScopedHICON(icon);
53 } 56 }
54 57
55 SkBitmap CreateBlackSkBitmap(int width, int height) { 58 SkBitmap CreateBlackSkBitmap(int width, int height) {
56 SkBitmap bitmap; 59 SkBitmap bitmap;
57 bitmap.allocN32Pixels(width, height); 60 bitmap.allocN32Pixels(width, height);
58 // Setting the pixels to transparent-black. 61 // Setting the pixels to transparent-black.
59 memset(bitmap.getPixels(), 0, width * height * 4); 62 memset(bitmap.getPixels(), 0, width * height * 4);
60 return bitmap; 63 return bitmap;
61 } 64 }
62 65
(...skipping 17 matching lines...) Expand all
80 83
81 // Determine how many icons to expect, based on |max_icon_size|. 84 // Determine how many icons to expect, based on |max_icon_size|.
82 int expected_num_icons = 0; 85 int expected_num_icons = 0;
83 for (size_t i = 0; i < IconUtil::kNumIconDimensions; ++i) { 86 for (size_t i = 0; i < IconUtil::kNumIconDimensions; ++i) {
84 if (IconUtil::kIconDimensions[i] > max_icon_size) 87 if (IconUtil::kIconDimensions[i] > max_icon_size)
85 break; 88 break;
86 ++expected_num_icons; 89 ++expected_num_icons;
87 } 90 }
88 91
89 // First, use the Windows API to load the icon, a basic validity test. 92 // First, use the Windows API to load the icon, a basic validity test.
90 HICON icon = LoadIconFromFile(icon_filename, kSmallIconWidth, 93 EXPECT_TRUE(LoadIconFromFile(icon_filename, kSmallIconWidth, kSmallIconHeight)
91 kSmallIconHeight); 94 .is_valid());
92 EXPECT_NE(static_cast<HICON>(NULL), icon);
93 if (icon != NULL)
94 ::DestroyIcon(icon);
95 95
96 // Read the file completely into memory. 96 // Read the file completely into memory.
97 std::string icon_data; 97 std::string icon_data;
98 ASSERT_TRUE(base::ReadFileToString(icon_filename, &icon_data)); 98 ASSERT_TRUE(base::ReadFileToString(icon_filename, &icon_data));
99 ASSERT_GE(icon_data.length(), sizeof(IconUtil::ICONDIR)); 99 ASSERT_GE(icon_data.length(), sizeof(IconUtil::ICONDIR));
100 100
101 // Ensure that it has exactly the expected number and sizes of icons, in the 101 // Ensure that it has exactly the expected number and sizes of icons, in the
102 // expected order. This matches each entry of the loaded file's icon directory 102 // expected order. This matches each entry of the loaded file's icon directory
103 // with the corresponding element of kIconDimensions. 103 // with the corresponding element of kIconDimensions.
104 // Also extracts the 256x256 entry as png_entry. 104 // Also extracts the 256x256 entry as png_entry.
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
138 EXPECT_EQ(256, bitmap.height()); 138 EXPECT_EQ(256, bitmap.height());
139 } 139 }
140 } 140 }
141 141
142 // The following test case makes sure IconUtil::SkBitmapFromHICON fails 142 // The following test case makes sure IconUtil::SkBitmapFromHICON fails
143 // gracefully when called with invalid input parameters. 143 // gracefully when called with invalid input parameters.
144 TEST_F(IconUtilTest, TestIconToBitmapInvalidParameters) { 144 TEST_F(IconUtilTest, TestIconToBitmapInvalidParameters) {
145 base::FilePath icon_filename = 145 base::FilePath icon_filename =
146 test_data_directory_.AppendASCII(kSmallIconName); 146 test_data_directory_.AppendASCII(kSmallIconName);
147 gfx::Size icon_size(kSmallIconWidth, kSmallIconHeight); 147 gfx::Size icon_size(kSmallIconWidth, kSmallIconHeight);
148 HICON icon = LoadIconFromFile(icon_filename, 148 ScopedHICON icon(
149 icon_size.width(), 149 LoadIconFromFile(icon_filename, icon_size.width(), icon_size.height()));
150 icon_size.height()); 150 ASSERT_TRUE(icon.is_valid());
151 ASSERT_TRUE(icon != NULL);
152 151
153 // Invalid size parameter. 152 // Invalid size parameter.
154 gfx::Size invalid_icon_size(kSmallIconHeight, 0); 153 gfx::Size invalid_icon_size(kSmallIconHeight, 0);
155 EXPECT_EQ(IconUtil::CreateSkBitmapFromHICON(icon, invalid_icon_size), 154 EXPECT_EQ(IconUtil::CreateSkBitmapFromHICON(icon.get(), invalid_icon_size),
156 static_cast<SkBitmap*>(NULL)); 155 static_cast<SkBitmap*>(NULL));
157 156
158 // Invalid icon. 157 // Invalid icon.
159 EXPECT_EQ(IconUtil::CreateSkBitmapFromHICON(NULL, icon_size), 158 EXPECT_EQ(IconUtil::CreateSkBitmapFromHICON(NULL, icon_size),
160 static_cast<SkBitmap*>(NULL)); 159 static_cast<SkBitmap*>(NULL));
161 160
162 // The following code should succeed. 161 // The following code should succeed.
163 scoped_ptr<SkBitmap> bitmap; 162 scoped_ptr<SkBitmap> bitmap;
164 bitmap.reset(IconUtil::CreateSkBitmapFromHICON(icon, icon_size)); 163 bitmap.reset(IconUtil::CreateSkBitmapFromHICON(icon.get(), icon_size));
165 EXPECT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL)); 164 EXPECT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
166 ::DestroyIcon(icon);
167 } 165 }
168 166
169 // The following test case makes sure IconUtil::CreateHICONFromSkBitmap fails 167 // The following test case makes sure IconUtil::CreateHICONFromSkBitmap fails
170 // gracefully when called with invalid input parameters. 168 // gracefully when called with invalid input parameters.
171 TEST_F(IconUtilTest, TestBitmapToIconInvalidParameters) { 169 TEST_F(IconUtilTest, TestBitmapToIconInvalidParameters) {
172 HICON icon = NULL; 170 ScopedHICON icon;
173 scoped_ptr<SkBitmap> bitmap; 171 scoped_ptr<SkBitmap> bitmap;
174 172
175 // Wrong bitmap format. 173 // Wrong bitmap format.
176 bitmap.reset(new SkBitmap); 174 bitmap.reset(new SkBitmap);
177 ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL)); 175 ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
178 bitmap->setInfo(SkImageInfo::MakeA8(kSmallIconWidth, kSmallIconHeight)); 176 bitmap->setInfo(SkImageInfo::MakeA8(kSmallIconWidth, kSmallIconHeight));
179 icon = IconUtil::CreateHICONFromSkBitmap(*bitmap); 177 icon = IconUtil::CreateHICONFromSkBitmap(*bitmap).Pass();
180 EXPECT_EQ(icon, static_cast<HICON>(NULL)); 178 EXPECT_FALSE(icon.is_valid());
181 179
182 // Invalid bitmap size. 180 // Invalid bitmap size.
183 bitmap.reset(new SkBitmap); 181 bitmap.reset(new SkBitmap);
184 ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL)); 182 ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
185 bitmap->setInfo(SkImageInfo::MakeN32Premul(0, 0)); 183 bitmap->setInfo(SkImageInfo::MakeN32Premul(0, 0));
186 icon = IconUtil::CreateHICONFromSkBitmap(*bitmap); 184 icon = IconUtil::CreateHICONFromSkBitmap(*bitmap).Pass();
187 EXPECT_EQ(icon, static_cast<HICON>(NULL)); 185 EXPECT_FALSE(icon.is_valid());
188 186
189 // Valid bitmap configuration but no pixels allocated. 187 // Valid bitmap configuration but no pixels allocated.
190 bitmap.reset(new SkBitmap); 188 bitmap.reset(new SkBitmap);
191 ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL)); 189 ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
192 bitmap->setInfo(SkImageInfo::MakeN32Premul(kSmallIconWidth, 190 bitmap->setInfo(SkImageInfo::MakeN32Premul(kSmallIconWidth,
193 kSmallIconHeight)); 191 kSmallIconHeight));
194 icon = IconUtil::CreateHICONFromSkBitmap(*bitmap); 192 icon = IconUtil::CreateHICONFromSkBitmap(*bitmap).Pass();
195 EXPECT_TRUE(icon == NULL); 193 EXPECT_FALSE(icon.is_valid());
196 } 194 }
197 195
198 // The following test case makes sure IconUtil::CreateIconFileFromImageFamily 196 // The following test case makes sure IconUtil::CreateIconFileFromImageFamily
199 // fails gracefully when called with invalid input parameters. 197 // fails gracefully when called with invalid input parameters.
200 TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) { 198 TEST_F(IconUtilTest, TestCreateIconFileInvalidParameters) {
201 scoped_ptr<SkBitmap> bitmap; 199 scoped_ptr<SkBitmap> bitmap;
202 gfx::ImageFamily image_family; 200 gfx::ImageFamily image_family;
203 base::FilePath valid_icon_filename = temp_directory_.path().AppendASCII( 201 base::FilePath valid_icon_filename = temp_directory_.path().AppendASCII(
204 kTempIconFilename); 202 kTempIconFilename);
205 base::FilePath invalid_icon_filename = temp_directory_.path().AppendASCII( 203 base::FilePath invalid_icon_filename = temp_directory_.path().AppendASCII(
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 EXPECT_FALSE(base::PathExists(icon_filename)); 266 EXPECT_FALSE(base::PathExists(icon_filename));
269 } 267 }
270 268
271 // This test case makes sure that when we load an icon from disk and convert 269 // This test case makes sure that when we load an icon from disk and convert
272 // the HICON into a bitmap, the bitmap has the expected format and dimensions. 270 // the HICON into a bitmap, the bitmap has the expected format and dimensions.
273 TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) { 271 TEST_F(IconUtilTest, TestCreateSkBitmapFromHICON) {
274 scoped_ptr<SkBitmap> bitmap; 272 scoped_ptr<SkBitmap> bitmap;
275 base::FilePath small_icon_filename = test_data_directory_.AppendASCII( 273 base::FilePath small_icon_filename = test_data_directory_.AppendASCII(
276 kSmallIconName); 274 kSmallIconName);
277 gfx::Size small_icon_size(kSmallIconWidth, kSmallIconHeight); 275 gfx::Size small_icon_size(kSmallIconWidth, kSmallIconHeight);
278 HICON small_icon = LoadIconFromFile(small_icon_filename, 276 ScopedHICON small_icon(LoadIconFromFile(
279 small_icon_size.width(), 277 small_icon_filename, small_icon_size.width(), small_icon_size.height()));
280 small_icon_size.height()); 278 ASSERT_TRUE(small_icon.is_valid());
281 ASSERT_NE(small_icon, static_cast<HICON>(NULL)); 279 bitmap.reset(
282 bitmap.reset(IconUtil::CreateSkBitmapFromHICON(small_icon, small_icon_size)); 280 IconUtil::CreateSkBitmapFromHICON(small_icon.get(), small_icon_size));
283 ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL)); 281 ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
284 EXPECT_EQ(bitmap->width(), small_icon_size.width()); 282 EXPECT_EQ(bitmap->width(), small_icon_size.width());
285 EXPECT_EQ(bitmap->height(), small_icon_size.height()); 283 EXPECT_EQ(bitmap->height(), small_icon_size.height());
286 EXPECT_EQ(bitmap->colorType(), kN32_SkColorType); 284 EXPECT_EQ(bitmap->colorType(), kN32_SkColorType);
287 ::DestroyIcon(small_icon);
288 285
289 base::FilePath large_icon_filename = test_data_directory_.AppendASCII( 286 base::FilePath large_icon_filename = test_data_directory_.AppendASCII(
290 kLargeIconName); 287 kLargeIconName);
291 gfx::Size large_icon_size(kLargeIconWidth, kLargeIconHeight); 288 gfx::Size large_icon_size(kLargeIconWidth, kLargeIconHeight);
292 HICON large_icon = LoadIconFromFile(large_icon_filename, 289 ScopedHICON large_icon(LoadIconFromFile(
293 large_icon_size.width(), 290 large_icon_filename, large_icon_size.width(), large_icon_size.height()));
294 large_icon_size.height()); 291 ASSERT_TRUE(large_icon.is_valid());
295 ASSERT_NE(large_icon, static_cast<HICON>(NULL)); 292 bitmap.reset(
296 bitmap.reset(IconUtil::CreateSkBitmapFromHICON(large_icon, large_icon_size)); 293 IconUtil::CreateSkBitmapFromHICON(large_icon.get(), large_icon_size));
297 ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL)); 294 ASSERT_NE(bitmap.get(), static_cast<SkBitmap*>(NULL));
298 EXPECT_EQ(bitmap->width(), large_icon_size.width()); 295 EXPECT_EQ(bitmap->width(), large_icon_size.width());
299 EXPECT_EQ(bitmap->height(), large_icon_size.height()); 296 EXPECT_EQ(bitmap->height(), large_icon_size.height());
300 EXPECT_EQ(bitmap->colorType(), kN32_SkColorType); 297 EXPECT_EQ(bitmap->colorType(), kN32_SkColorType);
301 ::DestroyIcon(large_icon);
302 } 298 }
303 299
304 // This test case makes sure that when an HICON is created from an SkBitmap, 300 // This test case makes sure that when an HICON is created from an SkBitmap,
305 // the returned handle is valid and refers to an icon with the expected 301 // the returned handle is valid and refers to an icon with the expected
306 // dimensions color depth etc. 302 // dimensions color depth etc.
307 TEST_F(IconUtilTest, TestBasicCreateHICONFromSkBitmap) { 303 TEST_F(IconUtilTest, TestBasicCreateHICONFromSkBitmap) {
308 SkBitmap bitmap = CreateBlackSkBitmap(kSmallIconWidth, kSmallIconHeight); 304 SkBitmap bitmap = CreateBlackSkBitmap(kSmallIconWidth, kSmallIconHeight);
309 HICON icon = IconUtil::CreateHICONFromSkBitmap(bitmap); 305 ScopedHICON icon(IconUtil::CreateHICONFromSkBitmap(bitmap));
310 EXPECT_NE(icon, static_cast<HICON>(NULL)); 306 EXPECT_TRUE(icon.is_valid());
311 ICONINFO icon_info; 307 ICONINFO icon_info;
312 ASSERT_TRUE(::GetIconInfo(icon, &icon_info)); 308 ASSERT_TRUE(GetIconInfo(icon.get(), &icon_info));
313 EXPECT_TRUE(icon_info.fIcon); 309 EXPECT_TRUE(icon_info.fIcon);
314 310
315 // Now that have the icon information, we should obtain the specification of 311 // Now that have the icon information, we should obtain the specification of
316 // the icon's bitmap and make sure it matches the specification of the 312 // the icon's bitmap and make sure it matches the specification of the
317 // SkBitmap we started with. 313 // SkBitmap we started with.
318 // 314 //
319 // The bitmap handle contained in the icon information is a handle to a 315 // The bitmap handle contained in the icon information is a handle to a
320 // compatible bitmap so we need to call ::GetDIBits() in order to retrieve 316 // compatible bitmap so we need to call ::GetDIBits() in order to retrieve
321 // the bitmap's header information. 317 // the bitmap's header information.
322 BITMAPINFO bitmap_info; 318 BITMAPINFO bitmap_info;
323 ::ZeroMemory(&bitmap_info, sizeof(BITMAPINFO)); 319 ::ZeroMemory(&bitmap_info, sizeof(BITMAPINFO));
324 bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFO); 320 bitmap_info.bmiHeader.biSize = sizeof(BITMAPINFO);
325 HDC hdc = ::GetDC(NULL); 321 HDC hdc = ::GetDC(NULL);
326 int result = ::GetDIBits(hdc, 322 int result = ::GetDIBits(hdc,
327 icon_info.hbmColor, 323 icon_info.hbmColor,
328 0, 324 0,
329 kSmallIconWidth, 325 kSmallIconWidth,
330 NULL, 326 NULL,
331 &bitmap_info, 327 &bitmap_info,
332 DIB_RGB_COLORS); 328 DIB_RGB_COLORS);
333 ASSERT_GT(result, 0); 329 ASSERT_GT(result, 0);
334 EXPECT_EQ(bitmap_info.bmiHeader.biWidth, kSmallIconWidth); 330 EXPECT_EQ(bitmap_info.bmiHeader.biWidth, kSmallIconWidth);
335 EXPECT_EQ(bitmap_info.bmiHeader.biHeight, kSmallIconHeight); 331 EXPECT_EQ(bitmap_info.bmiHeader.biHeight, kSmallIconHeight);
336 EXPECT_EQ(bitmap_info.bmiHeader.biPlanes, 1); 332 EXPECT_EQ(bitmap_info.bmiHeader.biPlanes, 1);
337 EXPECT_EQ(bitmap_info.bmiHeader.biBitCount, 32); 333 EXPECT_EQ(bitmap_info.bmiHeader.biBitCount, 32);
338 ::ReleaseDC(NULL, hdc); 334 ::ReleaseDC(NULL, hdc);
339 ::DestroyIcon(icon);
340 } 335 }
341 336
342 // This test case makes sure that CreateIconFileFromImageFamily creates a 337 // This test case makes sure that CreateIconFileFromImageFamily creates a
343 // valid .ico file given an ImageFamily, and appropriately creates all icon 338 // valid .ico file given an ImageFamily, and appropriately creates all icon
344 // sizes from the given input. 339 // sizes from the given input.
345 TEST_F(IconUtilTest, TestCreateIconFileFromImageFamily) { 340 TEST_F(IconUtilTest, TestCreateIconFileFromImageFamily) {
346 gfx::ImageFamily image_family; 341 gfx::ImageFamily image_family;
347 base::FilePath icon_filename = 342 base::FilePath icon_filename =
348 temp_directory_.path().AppendASCII(kTempIconFilename); 343 temp_directory_.path().AppendASCII(kTempIconFilename);
349 344
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
426 } 421 }
427 422
428 // This tests that kNumIconDimensionsUpToMediumSize has the correct value. 423 // This tests that kNumIconDimensionsUpToMediumSize has the correct value.
429 TEST_F(IconUtilTest, TestNumIconDimensionsUpToMediumSize) { 424 TEST_F(IconUtilTest, TestNumIconDimensionsUpToMediumSize) {
430 ASSERT_LE(IconUtil::kNumIconDimensionsUpToMediumSize, 425 ASSERT_LE(IconUtil::kNumIconDimensionsUpToMediumSize,
431 IconUtil::kNumIconDimensions); 426 IconUtil::kNumIconDimensions);
432 EXPECT_EQ(IconUtil::kMediumIconSize, 427 EXPECT_EQ(IconUtil::kMediumIconSize,
433 IconUtil::kIconDimensions[ 428 IconUtil::kIconDimensions[
434 IconUtil::kNumIconDimensionsUpToMediumSize - 1]); 429 IconUtil::kNumIconDimensionsUpToMediumSize - 1]);
435 } 430 }
OLDNEW
« no previous file with comments | « ui/gfx/icon_util.cc ('k') | ui/gfx/path_win.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698