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

Side by Side Diff: ui/gfx/icon_util.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: Use ScopedHICON instead of HICON. Created 5 years, 1 month 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
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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 "base/files/file_util.h" 7 #include "base/files/file_util.h"
8 #include "base/files/important_file_writer.h" 8 #include "base/files/important_file_writer.h"
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h" 10 #include "base/memory/scoped_ptr.h"
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 48, // Alt+Tab icon size. 156 48, // Alt+Tab icon size.
157 64, // Recommended by the MSDN as a nice to have icon size. 157 64, // Recommended by the MSDN as a nice to have icon size.
158 96, // Recommended by the MSDN as a nice to have icon size. 158 96, // Recommended by the MSDN as a nice to have icon size.
159 128, // Used by the Shell (e.g. for shortcuts). 159 128, // Used by the Shell (e.g. for shortcuts).
160 256 // Used by Vista onwards for large icons. 160 256 // Used by Vista onwards for large icons.
161 }; 161 };
162 162
163 const size_t IconUtil::kNumIconDimensions = arraysize(kIconDimensions); 163 const size_t IconUtil::kNumIconDimensions = arraysize(kIconDimensions);
164 const size_t IconUtil::kNumIconDimensionsUpToMediumSize = 9; 164 const size_t IconUtil::kNumIconDimensionsUpToMediumSize = 9;
165 165
166 HICON IconUtil::CreateHICONFromSkBitmap(const SkBitmap& bitmap) { 166 base::win::ScopedHICON IconUtil::CreateHICONFromSkBitmap(
167 const SkBitmap& bitmap) {
167 // Only 32 bit ARGB bitmaps are supported. We also try to perform as many 168 // Only 32 bit ARGB bitmaps are supported. We also try to perform as many
168 // validations as we can on the bitmap. 169 // validations as we can on the bitmap.
169 SkAutoLockPixels bitmap_lock(bitmap); 170 SkAutoLockPixels bitmap_lock(bitmap);
170 if ((bitmap.colorType() != kN32_SkColorType) || 171 if ((bitmap.colorType() != kN32_SkColorType) ||
171 (bitmap.width() <= 0) || (bitmap.height() <= 0) || 172 (bitmap.width() <= 0) || (bitmap.height() <= 0) ||
172 (bitmap.getPixels() == NULL)) 173 (bitmap.getPixels() == NULL))
173 return NULL; 174 return base::win::ScopedHICON();
174 175
175 // We start by creating a DIB which we'll use later on in order to create 176 // We start by creating a DIB which we'll use later on in order to create
176 // the HICON. We use BITMAPV5HEADER since the bitmap we are about to convert 177 // the HICON. We use BITMAPV5HEADER since the bitmap we are about to convert
177 // may contain an alpha channel and the V5 header allows us to specify the 178 // may contain an alpha channel and the V5 header allows us to specify the
178 // alpha mask for the DIB. 179 // alpha mask for the DIB.
179 BITMAPV5HEADER bitmap_header; 180 BITMAPV5HEADER bitmap_header;
180 InitializeBitmapHeader(&bitmap_header, bitmap.width(), bitmap.height()); 181 InitializeBitmapHeader(&bitmap_header, bitmap.width(), bitmap.height());
181 182
182 void* bits = NULL; 183 void* bits = NULL;
183 HBITMAP dib; 184 HBITMAP dib;
184 185
185 { 186 {
186 base::win::ScopedGetDC hdc(NULL); 187 base::win::ScopedGetDC hdc(NULL);
187 dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&bitmap_header), 188 dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&bitmap_header),
188 DIB_RGB_COLORS, &bits, NULL, 0); 189 DIB_RGB_COLORS, &bits, NULL, 0);
189 } 190 }
190 if (!dib || !bits) 191 if (!dib || !bits)
191 return NULL; 192 return base::win::ScopedHICON();
192 193
193 memcpy(bits, bitmap.getPixels(), bitmap.width() * bitmap.height() * 4); 194 memcpy(bits, bitmap.getPixels(), bitmap.width() * bitmap.height() * 4);
194 195
195 // Icons are generally created using an AND and XOR masks where the AND 196 // Icons are generally created using an AND and XOR masks where the AND
196 // specifies boolean transparency (the pixel is either opaque or 197 // specifies boolean transparency (the pixel is either opaque or
197 // transparent) and the XOR mask contains the actual image pixels. If the XOR 198 // transparent) and the XOR mask contains the actual image pixels. If the XOR
198 // mask bitmap has an alpha channel, the AND monochrome bitmap won't 199 // mask bitmap has an alpha channel, the AND monochrome bitmap won't
199 // actually be used for computing the pixel transparency. Even though all our 200 // actually be used for computing the pixel transparency. Even though all our
200 // bitmap has an alpha channel, Windows might not agree when all alpha values 201 // bitmap has an alpha channel, Windows might not agree when all alpha values
201 // are zero. So the monochrome bitmap is created with all pixels transparent 202 // are zero. So the monochrome bitmap is created with all pixels transparent
(...skipping 18 matching lines...) Expand all
220 HBITMAP mono_bitmap = ::CreateBitmap(bitmap.width(), bitmap.height(), 1, 1, 221 HBITMAP mono_bitmap = ::CreateBitmap(bitmap.width(), bitmap.height(), 1, 1,
221 reinterpret_cast<LPVOID>(mask_bits.get())); 222 reinterpret_cast<LPVOID>(mask_bits.get()));
222 DCHECK(mono_bitmap); 223 DCHECK(mono_bitmap);
223 224
224 ICONINFO icon_info; 225 ICONINFO icon_info;
225 icon_info.fIcon = TRUE; 226 icon_info.fIcon = TRUE;
226 icon_info.xHotspot = 0; 227 icon_info.xHotspot = 0;
227 icon_info.yHotspot = 0; 228 icon_info.yHotspot = 0;
228 icon_info.hbmMask = mono_bitmap; 229 icon_info.hbmMask = mono_bitmap;
229 icon_info.hbmColor = dib; 230 icon_info.hbmColor = dib;
230 HICON icon = ::CreateIconIndirect(&icon_info); 231 base::win::ScopedHICON icon(CreateIconIndirect(&icon_info));
231 ::DeleteObject(dib); 232 ::DeleteObject(dib);
232 ::DeleteObject(mono_bitmap); 233 ::DeleteObject(mono_bitmap);
233 return icon; 234 return icon.Pass();
234 } 235 }
235 236
236 SkBitmap* IconUtil::CreateSkBitmapFromHICON(HICON icon, const gfx::Size& s) { 237 SkBitmap* IconUtil::CreateSkBitmapFromHICON(HICON icon, const gfx::Size& s) {
237 // We start with validating parameters. 238 // We start with validating parameters.
238 if (!icon || s.IsEmpty()) 239 if (!icon || s.IsEmpty())
239 return NULL; 240 return NULL;
240 ScopedICONINFO icon_info; 241 ScopedICONINFO icon_info;
241 if (!::GetIconInfo(icon, &icon_info)) 242 if (!::GetIconInfo(icon, &icon_info))
242 return NULL; 243 return NULL;
243 if (!icon_info.fIcon) 244 if (!icon_info.fIcon)
244 return NULL; 245 return NULL;
245 return new SkBitmap(CreateSkBitmapFromHICONHelper(icon, s)); 246 return new SkBitmap(CreateSkBitmapFromHICONHelper(icon, s));
246 } 247 }
247 248
248 scoped_ptr<SkBitmap> IconUtil::CreateSkBitmapFromIconResource(HMODULE module, 249 scoped_ptr<SkBitmap> IconUtil::CreateSkBitmapFromIconResource(HMODULE module,
249 int resource_id, 250 int resource_id,
250 int size) { 251 int size) {
251 DCHECK_LE(size, kLargeIconSize); 252 DCHECK_LE(size, kLargeIconSize);
252 253
253 // For everything except the Vista+ 256x256 icons, use |LoadImage()|. 254 // For everything except the Vista+ 256x256 icons, use |LoadImage()|.
254 if (size != kLargeIconSize) { 255 if (size != kLargeIconSize) {
255 HICON icon_handle = 256 base::win::ScopedHICON icon(
256 static_cast<HICON>(LoadImage(module, MAKEINTRESOURCE(resource_id), 257 static_cast<HICON>(LoadImage(module, MAKEINTRESOURCE(resource_id),
257 IMAGE_ICON, size, size, 258 IMAGE_ICON, size, size,
258 LR_DEFAULTCOLOR | LR_DEFAULTSIZE)); 259 LR_DEFAULTCOLOR | LR_DEFAULTSIZE)));
259 scoped_ptr<SkBitmap> bitmap(IconUtil::CreateSkBitmapFromHICON(icon_handle)); 260 scoped_ptr<SkBitmap> bitmap(IconUtil::CreateSkBitmapFromHICON(icon.get()));
grt (UTC plus 2) 2015/11/10 16:44:43 return make_scoped_ptr(CreateSkBitmapFromHICON(ico
260 DestroyIcon(icon_handle);
261 return bitmap.Pass(); 261 return bitmap.Pass();
262 } 262 }
263 263
264 // For Vista+ 256x256 PNG icons, read the resource directly and find 264 // For Vista+ 256x256 PNG icons, read the resource directly and find
265 // the corresponding icon entry to get its PNG bytes. 265 // the corresponding icon entry to get its PNG bytes.
266 void* icon_dir_data = NULL; 266 void* icon_dir_data = NULL;
267 size_t icon_dir_size = 0; 267 size_t icon_dir_size = 0;
268 if (!base::win::GetResourceFromModule(module, resource_id, RT_GROUP_ICON, 268 if (!base::win::GetResourceFromModule(module, resource_id, RT_GROUP_ICON,
269 &icon_dir_data, &icon_dir_size)) { 269 &icon_dir_data, &icon_dir_size)) {
270 return nullptr; 270 return nullptr;
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
312 if (!::GetIconInfo(icon, &icon_info)) 312 if (!::GetIconInfo(icon, &icon_info))
313 return NULL; 313 return NULL;
314 314
315 if (!::GetObject(icon_info.hbmMask, sizeof(bitmap_info), &bitmap_info)) 315 if (!::GetObject(icon_info.hbmMask, sizeof(bitmap_info), &bitmap_info))
316 return NULL; 316 return NULL;
317 317
318 gfx::Size icon_size(bitmap_info.bmWidth, bitmap_info.bmHeight); 318 gfx::Size icon_size(bitmap_info.bmWidth, bitmap_info.bmHeight);
319 return new SkBitmap(CreateSkBitmapFromHICONHelper(icon, icon_size)); 319 return new SkBitmap(CreateSkBitmapFromHICONHelper(icon, icon_size));
320 } 320 }
321 321
322 HICON IconUtil::CreateCursorFromDIB(const gfx::Size& icon_size, 322 base::win::ScopedHICON IconUtil::CreateCursorFromDIB(const gfx::Size& icon_size,
323 const gfx::Point& hotspot, 323 const gfx::Point& hotspot,
324 const void* dib_bits, 324 const void* dib_bits,
325 size_t dib_size) { 325 size_t dib_size) {
326 BITMAPINFO icon_bitmap_info = {}; 326 BITMAPINFO icon_bitmap_info = {};
327 gfx::CreateBitmapHeader( 327 gfx::CreateBitmapHeader(
328 icon_size.width(), 328 icon_size.width(),
329 icon_size.height(), 329 icon_size.height(),
330 reinterpret_cast<BITMAPINFOHEADER*>(&icon_bitmap_info)); 330 reinterpret_cast<BITMAPINFOHEADER*>(&icon_bitmap_info));
331 331
332 base::win::ScopedGetDC dc(NULL); 332 base::win::ScopedGetDC dc(NULL);
333 base::win::ScopedCreateDC working_dc(CreateCompatibleDC(dc)); 333 base::win::ScopedCreateDC working_dc(CreateCompatibleDC(dc));
334 base::win::ScopedGDIObject<HBITMAP> bitmap_handle( 334 base::win::ScopedGDIObject<HBITMAP> bitmap_handle(
335 CreateDIBSection(dc, 335 CreateDIBSection(dc,
336 &icon_bitmap_info, 336 &icon_bitmap_info,
337 DIB_RGB_COLORS, 337 DIB_RGB_COLORS,
338 0, 338 0,
339 0, 339 0,
340 0)); 340 0));
341 if (dib_size > 0) { 341 if (dib_size > 0) {
342 SetDIBits(0, 342 SetDIBits(0,
343 bitmap_handle, 343 bitmap_handle.get(),
344 0, 344 0,
345 icon_size.height(), 345 icon_size.height(),
346 dib_bits, 346 dib_bits,
347 &icon_bitmap_info, 347 &icon_bitmap_info,
348 DIB_RGB_COLORS); 348 DIB_RGB_COLORS);
349 } 349 }
350 350
351 HBITMAP old_bitmap = reinterpret_cast<HBITMAP>( 351 HBITMAP old_bitmap = reinterpret_cast<HBITMAP>(
352 SelectObject(working_dc.Get(), bitmap_handle)); 352 SelectObject(working_dc.Get(), bitmap_handle.get()));
353 SetBkMode(working_dc.Get(), TRANSPARENT); 353 SetBkMode(working_dc.Get(), TRANSPARENT);
354 SelectObject(working_dc.Get(), old_bitmap); 354 SelectObject(working_dc.Get(), old_bitmap);
355 355
356 base::win::ScopedGDIObject<HBITMAP> mask( 356 base::win::ScopedGDIObject<HBITMAP> mask(
357 CreateBitmap(icon_size.width(), 357 CreateBitmap(icon_size.width(),
358 icon_size.height(), 358 icon_size.height(),
359 1, 359 1,
360 1, 360 1,
361 NULL)); 361 NULL));
362 ICONINFO ii = {0}; 362 ICONINFO ii = {0};
363 ii.fIcon = FALSE; 363 ii.fIcon = FALSE;
364 ii.xHotspot = hotspot.x(); 364 ii.xHotspot = hotspot.x();
365 ii.yHotspot = hotspot.y(); 365 ii.yHotspot = hotspot.y();
366 ii.hbmMask = mask; 366 ii.hbmMask = mask.get();
367 ii.hbmColor = bitmap_handle; 367 ii.hbmColor = bitmap_handle.get();
368 368
369 return CreateIconIndirect(&ii); 369 return base::win::ScopedHICON(CreateIconIndirect(&ii)).Pass();
grt (UTC plus 2) 2015/11/10 16:44:43 can you remove .Pass() here?
370 } 370 }
371 371
372 SkBitmap IconUtil::CreateSkBitmapFromHICONHelper(HICON icon, 372 SkBitmap IconUtil::CreateSkBitmapFromHICONHelper(HICON icon,
373 const gfx::Size& s) { 373 const gfx::Size& s) {
374 DCHECK(icon); 374 DCHECK(icon);
375 DCHECK(!s.IsEmpty()); 375 DCHECK(!s.IsEmpty());
376 376
377 // Allocating memory for the SkBitmap object. We are going to create an ARGB 377 // Allocating memory for the SkBitmap object. We are going to create an ARGB
378 // bitmap so we should set the configuration appropriately. 378 // bitmap so we should set the configuration appropriately.
379 SkBitmap bitmap; 379 SkBitmap bitmap;
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
694 // Once we compute the size for a singe AND mask scan line, we multiply that 694 // Once we compute the size for a singe AND mask scan line, we multiply that
695 // number by the image height in order to get the total number of bytes for 695 // number by the image height in order to get the total number of bytes for
696 // the AND mask. Thus, for a 15X15 image, we need 15 * 4 which is 60 bytes 696 // the AND mask. Thus, for a 15X15 image, we need 15 * 4 which is 60 bytes
697 // for the monochrome bitmap representing the AND mask. 697 // for the monochrome bitmap representing the AND mask.
698 size_t and_line_length = (bitmap.width() + 7) >> 3; 698 size_t and_line_length = (bitmap.width() + 7) >> 3;
699 and_line_length = (and_line_length + 3) & ~3; 699 and_line_length = (and_line_length + 3) & ~3;
700 size_t and_mask_size = and_line_length * bitmap.height(); 700 size_t and_mask_size = and_line_length * bitmap.height();
701 size_t masks_size = *xor_mask_size + and_mask_size; 701 size_t masks_size = *xor_mask_size + and_mask_size;
702 *bytes_in_resource = masks_size + sizeof(BITMAPINFOHEADER); 702 *bytes_in_resource = masks_size + sizeof(BITMAPINFOHEADER);
703 } 703 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698