| 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 |