OLD | NEW |
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/macros.h" |
10 #include "base/memory/scoped_ptr.h" | 11 #include "base/memory/scoped_ptr.h" |
11 #include "base/trace_event/trace_event.h" | 12 #include "base/trace_event/trace_event.h" |
12 #include "base/win/resource_util.h" | 13 #include "base/win/resource_util.h" |
13 #include "base/win/scoped_gdi_object.h" | 14 #include "base/win/scoped_gdi_object.h" |
14 #include "base/win/scoped_handle.h" | 15 #include "base/win/scoped_handle.h" |
15 #include "base/win/scoped_hdc.h" | 16 #include "base/win/scoped_hdc.h" |
16 #include "skia/ext/image_operations.h" | 17 #include "skia/ext/image_operations.h" |
17 #include "third_party/skia/include/core/SkBitmap.h" | 18 #include "third_party/skia/include/core/SkBitmap.h" |
18 #include "ui/gfx/gdi_util.h" | 19 #include "ui/gfx/gdi_util.h" |
19 #include "ui/gfx/geometry/size.h" | 20 #include "ui/gfx/geometry/size.h" |
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 memcpy(bits, bitmap.getPixels(), bitmap.width() * bitmap.height() * 4); | 193 memcpy(bits, bitmap.getPixels(), bitmap.width() * bitmap.height() * 4); |
193 | 194 |
194 // Icons are generally created using an AND and XOR masks where the AND | 195 // Icons are generally created using an AND and XOR masks where the AND |
195 // specifies boolean transparency (the pixel is either opaque or | 196 // specifies boolean transparency (the pixel is either opaque or |
196 // transparent) and the XOR mask contains the actual image pixels. If the XOR | 197 // transparent) and the XOR mask contains the actual image pixels. If the XOR |
197 // mask bitmap has an alpha channel, the AND monochrome bitmap won't | 198 // mask bitmap has an alpha channel, the AND monochrome bitmap won't |
198 // actually be used for computing the pixel transparency. Even though all our | 199 // actually be used for computing the pixel transparency. Even though all our |
199 // bitmap has an alpha channel, Windows might not agree when all alpha values | 200 // bitmap has an alpha channel, Windows might not agree when all alpha values |
200 // are zero. So the monochrome bitmap is created with all pixels transparent | 201 // are zero. So the monochrome bitmap is created with all pixels transparent |
201 // for this case. Otherwise, it is created with all pixels opaque. | 202 // for this case. Otherwise, it is created with all pixels opaque. |
202 bool bitmap_has_alpha_channel = PixelsHaveAlpha( | 203 bool bitmap_has_alpha_channel = |
203 static_cast<const uint32*>(bitmap.getPixels()), | 204 PixelsHaveAlpha(static_cast<const uint32_t*>(bitmap.getPixels()), |
204 bitmap.width() * bitmap.height()); | 205 bitmap.width() * bitmap.height()); |
205 | 206 |
206 scoped_ptr<uint8[]> mask_bits; | 207 scoped_ptr<uint8_t[]> mask_bits; |
207 if (!bitmap_has_alpha_channel) { | 208 if (!bitmap_has_alpha_channel) { |
208 // Bytes per line with paddings to make it word alignment. | 209 // Bytes per line with paddings to make it word alignment. |
209 size_t bytes_per_line = (bitmap.width() + 0xF) / 16 * 2; | 210 size_t bytes_per_line = (bitmap.width() + 0xF) / 16 * 2; |
210 size_t mask_bits_size = bytes_per_line * bitmap.height(); | 211 size_t mask_bits_size = bytes_per_line * bitmap.height(); |
211 | 212 |
212 mask_bits.reset(new uint8[mask_bits_size]); | 213 mask_bits.reset(new uint8_t[mask_bits_size]); |
213 DCHECK(mask_bits.get()); | 214 DCHECK(mask_bits.get()); |
214 | 215 |
215 // Make all pixels transparent. | 216 // Make all pixels transparent. |
216 memset(mask_bits.get(), 0xFF, mask_bits_size); | 217 memset(mask_bits.get(), 0xFF, mask_bits_size); |
217 } | 218 } |
218 | 219 |
219 HBITMAP mono_bitmap = ::CreateBitmap(bitmap.width(), bitmap.height(), 1, 1, | 220 HBITMAP mono_bitmap = ::CreateBitmap(bitmap.width(), bitmap.height(), 1, 1, |
220 reinterpret_cast<LPVOID>(mask_bits.get())); | 221 reinterpret_cast<LPVOID>(mask_bits.get())); |
221 DCHECK(mono_bitmap); | 222 DCHECK(mono_bitmap); |
222 | 223 |
(...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
373 SkBitmap bitmap; | 374 SkBitmap bitmap; |
374 bitmap.allocN32Pixels(s.width(), s.height()); | 375 bitmap.allocN32Pixels(s.width(), s.height()); |
375 bitmap.eraseARGB(0, 0, 0, 0); | 376 bitmap.eraseARGB(0, 0, 0, 0); |
376 SkAutoLockPixels bitmap_lock(bitmap); | 377 SkAutoLockPixels bitmap_lock(bitmap); |
377 | 378 |
378 // Now we should create a DIB so that we can use ::DrawIconEx in order to | 379 // Now we should create a DIB so that we can use ::DrawIconEx in order to |
379 // obtain the icon's image. | 380 // obtain the icon's image. |
380 BITMAPV5HEADER h; | 381 BITMAPV5HEADER h; |
381 InitializeBitmapHeader(&h, s.width(), s.height()); | 382 InitializeBitmapHeader(&h, s.width(), s.height()); |
382 HDC hdc = ::GetDC(NULL); | 383 HDC hdc = ::GetDC(NULL); |
383 uint32* bits; | 384 uint32_t* bits; |
384 HBITMAP dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&h), | 385 HBITMAP dib = ::CreateDIBSection(hdc, reinterpret_cast<BITMAPINFO*>(&h), |
385 DIB_RGB_COLORS, reinterpret_cast<void**>(&bits), NULL, 0); | 386 DIB_RGB_COLORS, reinterpret_cast<void**>(&bits), NULL, 0); |
386 DCHECK(dib); | 387 DCHECK(dib); |
387 HDC dib_dc = CreateCompatibleDC(hdc); | 388 HDC dib_dc = CreateCompatibleDC(hdc); |
388 ::ReleaseDC(NULL, hdc); | 389 ::ReleaseDC(NULL, hdc); |
389 DCHECK(dib_dc); | 390 DCHECK(dib_dc); |
390 HGDIOBJ old_obj = ::SelectObject(dib_dc, dib); | 391 HGDIOBJ old_obj = ::SelectObject(dib_dc, dib); |
391 | 392 |
392 // Windows icons are defined using two different masks. The XOR mask, which | 393 // Windows icons are defined using two different masks. The XOR mask, which |
393 // represents the icon image and an AND mask which is a monochrome bitmap | 394 // represents the icon image and an AND mask which is a monochrome bitmap |
(...skipping 21 matching lines...) Expand all Loading... |
415 for (size_t i = 0; i < num_pixels; ++i) | 416 for (size_t i = 0; i < num_pixels; ++i) |
416 opaque[i] = !bits[i]; | 417 opaque[i] = !bits[i]; |
417 | 418 |
418 // Then draw the image itself which is really the XOR mask. | 419 // Then draw the image itself which is really the XOR mask. |
419 memset(bits, 0, num_pixels * 4); | 420 memset(bits, 0, num_pixels * 4); |
420 ::DrawIconEx(dib_dc, 0, 0, icon, s.width(), s.height(), 0, NULL, DI_NORMAL); | 421 ::DrawIconEx(dib_dc, 0, 0, icon, s.width(), s.height(), 0, NULL, DI_NORMAL); |
421 memcpy(bitmap.getPixels(), static_cast<void*>(bits), num_pixels * 4); | 422 memcpy(bitmap.getPixels(), static_cast<void*>(bits), num_pixels * 4); |
422 | 423 |
423 // Finding out whether the bitmap has an alpha channel. | 424 // Finding out whether the bitmap has an alpha channel. |
424 bool bitmap_has_alpha_channel = PixelsHaveAlpha( | 425 bool bitmap_has_alpha_channel = PixelsHaveAlpha( |
425 static_cast<const uint32*>(bitmap.getPixels()), num_pixels); | 426 static_cast<const uint32_t*>(bitmap.getPixels()), num_pixels); |
426 | 427 |
427 // If the bitmap does not have an alpha channel, we need to build it using | 428 // If the bitmap does not have an alpha channel, we need to build it using |
428 // the previously captured AND mask. Otherwise, we are done. | 429 // the previously captured AND mask. Otherwise, we are done. |
429 if (!bitmap_has_alpha_channel) { | 430 if (!bitmap_has_alpha_channel) { |
430 uint32* p = static_cast<uint32*>(bitmap.getPixels()); | 431 uint32_t* p = static_cast<uint32_t*>(bitmap.getPixels()); |
431 for (size_t i = 0; i < num_pixels; ++p, ++i) { | 432 for (size_t i = 0; i < num_pixels; ++p, ++i) { |
432 DCHECK_EQ((*p & 0xff000000), 0u); | 433 DCHECK_EQ((*p & 0xff000000), 0u); |
433 if (opaque[i]) | 434 if (opaque[i]) |
434 *p |= 0xff000000; | 435 *p |= 0xff000000; |
435 else | 436 else |
436 *p &= 0x00ffffff; | 437 *p &= 0x00ffffff; |
437 } | 438 } |
438 } | 439 } |
439 | 440 |
440 ::SelectObject(dib_dc, old_obj); | 441 ::SelectObject(dib_dc, old_obj); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
472 // images in the desired icon format. | 473 // images in the desired icon format. |
473 size_t buffer_size = ComputeIconFileBufferSize(bitmaps); | 474 size_t buffer_size = ComputeIconFileBufferSize(bitmaps); |
474 // Account for the bytes needed for the PNG entry. | 475 // Account for the bytes needed for the PNG entry. |
475 if (png_bytes.get()) | 476 if (png_bytes.get()) |
476 buffer_size += sizeof(ICONDIRENTRY) + png_bytes->size(); | 477 buffer_size += sizeof(ICONDIRENTRY) + png_bytes->size(); |
477 | 478 |
478 // Setting the information in the structures residing within the buffer. | 479 // Setting the information in the structures residing within the buffer. |
479 // First, we set the information which doesn't require iterating through the | 480 // First, we set the information which doesn't require iterating through the |
480 // bitmap set and then we set the bitmap specific structures. In the latter | 481 // bitmap set and then we set the bitmap specific structures. In the latter |
481 // step we also copy the actual bits. | 482 // step we also copy the actual bits. |
482 std::vector<uint8> buffer(buffer_size); | 483 std::vector<uint8_t> buffer(buffer_size); |
483 ICONDIR* icon_dir = reinterpret_cast<ICONDIR*>(&buffer[0]); | 484 ICONDIR* icon_dir = reinterpret_cast<ICONDIR*>(&buffer[0]); |
484 icon_dir->idType = kResourceTypeIcon; | 485 icon_dir->idType = kResourceTypeIcon; |
485 icon_dir->idCount = static_cast<WORD>(image_count); | 486 icon_dir->idCount = static_cast<WORD>(image_count); |
486 // - 1 because there is already one ICONDIRENTRY in ICONDIR. | 487 // - 1 because there is already one ICONDIRENTRY in ICONDIR. |
487 size_t icon_dir_count = image_count - 1; | 488 size_t icon_dir_count = image_count - 1; |
488 | 489 |
489 size_t offset = sizeof(ICONDIR) + (sizeof(ICONDIRENTRY) * icon_dir_count); | 490 size_t offset = sizeof(ICONDIR) + (sizeof(ICONDIRENTRY) * icon_dir_count); |
490 for (size_t i = 0; i < bitmap_count; i++) { | 491 for (size_t i = 0; i < bitmap_count; i++) { |
491 ICONIMAGE* image = reinterpret_cast<ICONIMAGE*>(&buffer[offset]); | 492 ICONIMAGE* image = reinterpret_cast<ICONIMAGE*>(&buffer[offset]); |
492 DCHECK_LT(offset, buffer_size); | 493 DCHECK_LT(offset, buffer_size); |
(...skipping 27 matching lines...) Expand all Loading... |
520 return true; | 521 return true; |
521 bool delete_success = base::DeleteFile(icon_path, false); | 522 bool delete_success = base::DeleteFile(icon_path, false); |
522 DCHECK(delete_success); | 523 DCHECK(delete_success); |
523 return false; | 524 return false; |
524 } else { | 525 } else { |
525 std::string data(buffer.begin(), buffer.end()); | 526 std::string data(buffer.begin(), buffer.end()); |
526 return base::ImportantFileWriter::WriteFileAtomically(icon_path, data); | 527 return base::ImportantFileWriter::WriteFileAtomically(icon_path, data); |
527 } | 528 } |
528 } | 529 } |
529 | 530 |
530 bool IconUtil::PixelsHaveAlpha(const uint32* pixels, size_t num_pixels) { | 531 bool IconUtil::PixelsHaveAlpha(const uint32_t* pixels, size_t num_pixels) { |
531 for (const uint32* end = pixels + num_pixels; pixels != end; ++pixels) { | 532 for (const uint32_t* end = pixels + num_pixels; pixels != end; ++pixels) { |
532 if ((*pixels & 0xff000000) != 0) | 533 if ((*pixels & 0xff000000) != 0) |
533 return true; | 534 return true; |
534 } | 535 } |
535 | 536 |
536 return false; | 537 return false; |
537 } | 538 } |
538 | 539 |
539 void IconUtil::InitializeBitmapHeader(BITMAPV5HEADER* header, int width, | 540 void IconUtil::InitializeBitmapHeader(BITMAPV5HEADER* header, int width, |
540 int height) { | 541 int height) { |
541 DCHECK(header); | 542 DCHECK(header); |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
688 // Once we compute the size for a singe AND mask scan line, we multiply that | 689 // 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 | 690 // 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 | 691 // 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. | 692 // for the monochrome bitmap representing the AND mask. |
692 size_t and_line_length = (bitmap.width() + 7) >> 3; | 693 size_t and_line_length = (bitmap.width() + 7) >> 3; |
693 and_line_length = (and_line_length + 3) & ~3; | 694 and_line_length = (and_line_length + 3) & ~3; |
694 size_t and_mask_size = and_line_length * bitmap.height(); | 695 size_t and_mask_size = and_line_length * bitmap.height(); |
695 size_t masks_size = *xor_mask_size + and_mask_size; | 696 size_t masks_size = *xor_mask_size + and_mask_size; |
696 *bytes_in_resource = masks_size + sizeof(BITMAPINFOHEADER); | 697 *bytes_in_resource = masks_size + sizeof(BITMAPINFOHEADER); |
697 } | 698 } |
OLD | NEW |