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

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: 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.h ('k') | ui/gfx/icon_util_unittest.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) 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 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 48, // Alt+Tab icon size. 154 48, // Alt+Tab icon size.
155 64, // Recommended by the MSDN as a nice to have icon size. 155 64, // Recommended by the MSDN as a nice to have icon size.
156 96, // Recommended by the MSDN as a nice to have icon size. 156 96, // Recommended by the MSDN as a nice to have icon size.
157 128, // Used by the Shell (e.g. for shortcuts). 157 128, // Used by the Shell (e.g. for shortcuts).
158 256 // Used by Vista onwards for large icons. 158 256 // Used by Vista onwards for large icons.
159 }; 159 };
160 160
161 const size_t IconUtil::kNumIconDimensions = arraysize(kIconDimensions); 161 const size_t IconUtil::kNumIconDimensions = arraysize(kIconDimensions);
162 const size_t IconUtil::kNumIconDimensionsUpToMediumSize = 9; 162 const size_t IconUtil::kNumIconDimensionsUpToMediumSize = 9;
163 163
164 HICON IconUtil::CreateHICONFromSkBitmap(const SkBitmap& bitmap) { 164 base::win::ScopedHICON IconUtil::CreateHICONFromSkBitmap(
165 const SkBitmap& bitmap) {
165 // Only 32 bit ARGB bitmaps are supported. We also try to perform as many 166 // Only 32 bit ARGB bitmaps are supported. We also try to perform as many
166 // validations as we can on the bitmap. 167 // validations as we can on the bitmap.
167 SkAutoLockPixels bitmap_lock(bitmap); 168 SkAutoLockPixels bitmap_lock(bitmap);
168 if ((bitmap.colorType() != kN32_SkColorType) || 169 if ((bitmap.colorType() != kN32_SkColorType) ||
169 (bitmap.width() <= 0) || (bitmap.height() <= 0) || 170 (bitmap.width() <= 0) || (bitmap.height() <= 0) ||
170 (bitmap.getPixels() == NULL)) 171 (bitmap.getPixels() == NULL))
171 return NULL; 172 return base::win::ScopedHICON();
172 173
173 // We start by creating a DIB which we'll use later on in order to create 174 // We start by creating a DIB which we'll use later on in order to create
174 // the HICON. We use BITMAPV5HEADER since the bitmap we are about to convert 175 // the HICON. We use BITMAPV5HEADER since the bitmap we are about to convert
175 // may contain an alpha channel and the V5 header allows us to specify the 176 // may contain an alpha channel and the V5 header allows us to specify the
176 // alpha mask for the DIB. 177 // alpha mask for the DIB.
177 BITMAPV5HEADER bitmap_header; 178 BITMAPV5HEADER bitmap_header;
178 InitializeBitmapHeader(&bitmap_header, bitmap.width(), bitmap.height()); 179 InitializeBitmapHeader(&bitmap_header, bitmap.width(), bitmap.height());
179 180
180 void* bits = NULL; 181 void* bits = NULL;
181 HBITMAP dib; 182 HBITMAP dib;
182 183
183 { 184 {
184 base::win::ScopedGetDC hdc(NULL); 185 base::win::ScopedGetDC hdc(NULL);
185 dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&bitmap_header), 186 dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&bitmap_header),
186 DIB_RGB_COLORS, &bits, NULL, 0); 187 DIB_RGB_COLORS, &bits, NULL, 0);
187 } 188 }
188 if (!dib || !bits) 189 if (!dib || !bits)
189 return NULL; 190 return base::win::ScopedHICON();
190 191
191 memcpy(bits, bitmap.getPixels(), bitmap.width() * bitmap.height() * 4); 192 memcpy(bits, bitmap.getPixels(), bitmap.width() * bitmap.height() * 4);
192 193
193 // Icons are generally created using an AND and XOR masks where the AND 194 // Icons are generally created using an AND and XOR masks where the AND
194 // specifies boolean transparency (the pixel is either opaque or 195 // specifies boolean transparency (the pixel is either opaque or
195 // transparent) and the XOR mask contains the actual image pixels. If the XOR 196 // transparent) and the XOR mask contains the actual image pixels. If the XOR
196 // mask bitmap has an alpha channel, the AND monochrome bitmap won't 197 // mask bitmap has an alpha channel, the AND monochrome bitmap won't
197 // actually be used for computing the pixel transparency. Even though all our 198 // actually be used for computing the pixel transparency. Even though all our
198 // bitmap has an alpha channel, Windows might not agree when all alpha values 199 // bitmap has an alpha channel, Windows might not agree when all alpha values
199 // are zero. So the monochrome bitmap is created with all pixels transparent 200 // are zero. So the monochrome bitmap is created with all pixels transparent
(...skipping 18 matching lines...) Expand all
218 HBITMAP mono_bitmap = ::CreateBitmap(bitmap.width(), bitmap.height(), 1, 1, 219 HBITMAP mono_bitmap = ::CreateBitmap(bitmap.width(), bitmap.height(), 1, 1,
219 reinterpret_cast<LPVOID>(mask_bits.get())); 220 reinterpret_cast<LPVOID>(mask_bits.get()));
220 DCHECK(mono_bitmap); 221 DCHECK(mono_bitmap);
221 222
222 ICONINFO icon_info; 223 ICONINFO icon_info;
223 icon_info.fIcon = TRUE; 224 icon_info.fIcon = TRUE;
224 icon_info.xHotspot = 0; 225 icon_info.xHotspot = 0;
225 icon_info.yHotspot = 0; 226 icon_info.yHotspot = 0;
226 icon_info.hbmMask = mono_bitmap; 227 icon_info.hbmMask = mono_bitmap;
227 icon_info.hbmColor = dib; 228 icon_info.hbmColor = dib;
228 HICON icon = ::CreateIconIndirect(&icon_info); 229 base::win::ScopedHICON icon(CreateIconIndirect(&icon_info));
229 ::DeleteObject(dib); 230 ::DeleteObject(dib);
230 ::DeleteObject(mono_bitmap); 231 ::DeleteObject(mono_bitmap);
231 return icon; 232 return icon;
232 } 233 }
233 234
234 SkBitmap* IconUtil::CreateSkBitmapFromHICON(HICON icon, const gfx::Size& s) { 235 SkBitmap* IconUtil::CreateSkBitmapFromHICON(HICON icon, const gfx::Size& s) {
235 // We start with validating parameters. 236 // We start with validating parameters.
236 if (!icon || s.IsEmpty()) 237 if (!icon || s.IsEmpty())
237 return NULL; 238 return NULL;
238 ScopedICONINFO icon_info; 239 ScopedICONINFO icon_info;
(...skipping 23 matching lines...) Expand all
262 reinterpret_cast<const GRPICONDIR*>(icon_dir_data); 263 reinterpret_cast<const GRPICONDIR*>(icon_dir_data);
263 scoped_ptr<gfx::ImageFamily> result(new gfx::ImageFamily); 264 scoped_ptr<gfx::ImageFamily> result(new gfx::ImageFamily);
264 for (size_t i = 0; i < icon_dir->idCount; ++i) { 265 for (size_t i = 0; i < icon_dir->idCount; ++i) {
265 const GRPICONDIRENTRY* entry = &icon_dir->idEntries[i]; 266 const GRPICONDIRENTRY* entry = &icon_dir->idEntries[i];
266 if (entry->bWidth != 0 || entry->bHeight != 0) { 267 if (entry->bWidth != 0 || entry->bHeight != 0) {
267 // Ignore the low-bit-depth versions of the icon. 268 // Ignore the low-bit-depth versions of the icon.
268 if (entry->wBitCount != 32) 269 if (entry->wBitCount != 32)
269 continue; 270 continue;
270 271
271 // For everything except the Vista+ 256x256 icons, use |LoadImage()|. 272 // For everything except the Vista+ 256x256 icons, use |LoadImage()|.
272 HICON icon_handle = static_cast<HICON>(LoadImage( 273 base::win::ScopedHICON icon_handle(static_cast<HICON>(LoadImage(
273 module, MAKEINTRESOURCE(resource_id), IMAGE_ICON, entry->bWidth, 274 module, MAKEINTRESOURCE(resource_id), IMAGE_ICON, entry->bWidth,
274 entry->bHeight, LR_DEFAULTCOLOR | LR_DEFAULTSIZE)); 275 entry->bHeight, LR_DEFAULTCOLOR | LR_DEFAULTSIZE)));
275 scoped_ptr<SkBitmap> bitmap( 276 scoped_ptr<SkBitmap> bitmap(
276 IconUtil::CreateSkBitmapFromHICON(icon_handle)); 277 IconUtil::CreateSkBitmapFromHICON(icon_handle.get()));
277 DestroyIcon(icon_handle);
278 result->Add(gfx::Image::CreateFrom1xBitmap(*bitmap)); 278 result->Add(gfx::Image::CreateFrom1xBitmap(*bitmap));
279 } else { 279 } else {
280 // 256x256 icons are stored with width and height set to 0. 280 // 256x256 icons are stored with width and height set to 0.
281 // See: http://en.wikipedia.org/wiki/ICO_(file_format) 281 // See: http://en.wikipedia.org/wiki/ICO_(file_format)
282 void* png_data = NULL; 282 void* png_data = NULL;
283 size_t png_size = 0; 283 size_t png_size = 0;
284 if (!base::win::GetResourceFromModule(module, entry->nID, RT_ICON, 284 if (!base::win::GetResourceFromModule(module, entry->nID, RT_ICON,
285 &png_data, &png_size)) { 285 &png_data, &png_size)) {
286 return nullptr; 286 return nullptr;
287 } 287 }
(...skipping 18 matching lines...) Expand all
306 if (!::GetIconInfo(icon, &icon_info)) 306 if (!::GetIconInfo(icon, &icon_info))
307 return NULL; 307 return NULL;
308 308
309 if (!::GetObject(icon_info.hbmMask, sizeof(bitmap_info), &bitmap_info)) 309 if (!::GetObject(icon_info.hbmMask, sizeof(bitmap_info), &bitmap_info))
310 return NULL; 310 return NULL;
311 311
312 gfx::Size icon_size(bitmap_info.bmWidth, bitmap_info.bmHeight); 312 gfx::Size icon_size(bitmap_info.bmWidth, bitmap_info.bmHeight);
313 return new SkBitmap(CreateSkBitmapFromHICONHelper(icon, icon_size)); 313 return new SkBitmap(CreateSkBitmapFromHICONHelper(icon, icon_size));
314 } 314 }
315 315
316 HICON IconUtil::CreateCursorFromDIB(const gfx::Size& icon_size, 316 base::win::ScopedHICON IconUtil::CreateCursorFromDIB(const gfx::Size& icon_size,
317 const gfx::Point& hotspot, 317 const gfx::Point& hotspot,
318 const void* dib_bits, 318 const void* dib_bits,
319 size_t dib_size) { 319 size_t dib_size) {
320 BITMAPINFO icon_bitmap_info = {}; 320 BITMAPINFO icon_bitmap_info = {};
321 gfx::CreateBitmapHeader( 321 gfx::CreateBitmapHeader(
322 icon_size.width(), 322 icon_size.width(),
323 icon_size.height(), 323 icon_size.height(),
324 reinterpret_cast<BITMAPINFOHEADER*>(&icon_bitmap_info)); 324 reinterpret_cast<BITMAPINFOHEADER*>(&icon_bitmap_info));
325 325
326 base::win::ScopedGetDC dc(NULL); 326 base::win::ScopedGetDC dc(NULL);
327 base::win::ScopedCreateDC working_dc(CreateCompatibleDC(dc)); 327 base::win::ScopedCreateDC working_dc(CreateCompatibleDC(dc));
328 base::win::ScopedGDIObject<HBITMAP> bitmap_handle( 328 base::win::ScopedGDIObject<HBITMAP> bitmap_handle(
329 CreateDIBSection(dc, 329 CreateDIBSection(dc,
330 &icon_bitmap_info, 330 &icon_bitmap_info,
331 DIB_RGB_COLORS, 331 DIB_RGB_COLORS,
332 0, 332 0,
333 0, 333 0,
334 0)); 334 0));
335 if (dib_size > 0) { 335 if (dib_size > 0) {
336 SetDIBits(0, 336 SetDIBits(0,
337 bitmap_handle, 337 bitmap_handle.get(),
338 0, 338 0,
339 icon_size.height(), 339 icon_size.height(),
340 dib_bits, 340 dib_bits,
341 &icon_bitmap_info, 341 &icon_bitmap_info,
342 DIB_RGB_COLORS); 342 DIB_RGB_COLORS);
343 } 343 }
344 344
345 HBITMAP old_bitmap = reinterpret_cast<HBITMAP>( 345 HBITMAP old_bitmap = reinterpret_cast<HBITMAP>(
346 SelectObject(working_dc.Get(), bitmap_handle)); 346 SelectObject(working_dc.Get(), bitmap_handle.get()));
347 SetBkMode(working_dc.Get(), TRANSPARENT); 347 SetBkMode(working_dc.Get(), TRANSPARENT);
348 SelectObject(working_dc.Get(), old_bitmap); 348 SelectObject(working_dc.Get(), old_bitmap);
349 349
350 base::win::ScopedGDIObject<HBITMAP> mask( 350 base::win::ScopedGDIObject<HBITMAP> mask(
351 CreateBitmap(icon_size.width(), 351 CreateBitmap(icon_size.width(),
352 icon_size.height(), 352 icon_size.height(),
353 1, 353 1,
354 1, 354 1,
355 NULL)); 355 NULL));
356 ICONINFO ii = {0}; 356 ICONINFO ii = {0};
357 ii.fIcon = FALSE; 357 ii.fIcon = FALSE;
358 ii.xHotspot = hotspot.x(); 358 ii.xHotspot = hotspot.x();
359 ii.yHotspot = hotspot.y(); 359 ii.yHotspot = hotspot.y();
360 ii.hbmMask = mask; 360 ii.hbmMask = mask.get();
361 ii.hbmColor = bitmap_handle; 361 ii.hbmColor = bitmap_handle.get();
362 362
363 return CreateIconIndirect(&ii); 363 return base::win::ScopedHICON(CreateIconIndirect(&ii));
364 } 364 }
365 365
366 SkBitmap IconUtil::CreateSkBitmapFromHICONHelper(HICON icon, 366 SkBitmap IconUtil::CreateSkBitmapFromHICONHelper(HICON icon,
367 const gfx::Size& s) { 367 const gfx::Size& s) {
368 DCHECK(icon); 368 DCHECK(icon);
369 DCHECK(!s.IsEmpty()); 369 DCHECK(!s.IsEmpty());
370 370
371 // Allocating memory for the SkBitmap object. We are going to create an ARGB 371 // Allocating memory for the SkBitmap object. We are going to create an ARGB
372 // bitmap so we should set the configuration appropriately. 372 // bitmap so we should set the configuration appropriately.
373 SkBitmap bitmap; 373 SkBitmap bitmap;
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after
688 // Once we compute the size for a singe AND mask scan line, we multiply that 688 // Once we compute the size for a singe AND mask scan line, we multiply that
689 // number by the image height in order to get the total number of bytes for 689 // number by the image height in order to get the total number of bytes for
690 // the AND mask. Thus, for a 15X15 image, we need 15 * 4 which is 60 bytes 690 // the AND mask. Thus, for a 15X15 image, we need 15 * 4 which is 60 bytes
691 // for the monochrome bitmap representing the AND mask. 691 // for the monochrome bitmap representing the AND mask.
692 size_t and_line_length = (bitmap.width() + 7) >> 3; 692 size_t and_line_length = (bitmap.width() + 7) >> 3;
693 and_line_length = (and_line_length + 3) & ~3; 693 and_line_length = (and_line_length + 3) & ~3;
694 size_t and_mask_size = and_line_length * bitmap.height(); 694 size_t and_mask_size = and_line_length * bitmap.height();
695 size_t masks_size = *xor_mask_size + and_mask_size; 695 size_t masks_size = *xor_mask_size + and_mask_size;
696 *bytes_in_resource = masks_size + sizeof(BITMAPINFOHEADER); 696 *bytes_in_resource = masks_size + sizeof(BITMAPINFOHEADER);
697 } 697 }
OLDNEW
« no previous file with comments | « ui/gfx/icon_util.h ('k') | ui/gfx/icon_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698