| 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/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/files/important_file_writer.h" |
| 8 #include "base/logging.h" | 9 #include "base/logging.h" |
| 9 #include "base/memory/scoped_ptr.h" | 10 #include "base/memory/scoped_ptr.h" |
| 10 #include "base/win/resource_util.h" | 11 #include "base/win/resource_util.h" |
| 11 #include "base/win/scoped_gdi_object.h" | 12 #include "base/win/scoped_gdi_object.h" |
| 12 #include "base/win/scoped_handle.h" | 13 #include "base/win/scoped_handle.h" |
| 13 #include "base/win/scoped_hdc.h" | 14 #include "base/win/scoped_hdc.h" |
| 14 #include "skia/ext/image_operations.h" | 15 #include "skia/ext/image_operations.h" |
| 15 #include "third_party/skia/include/core/SkBitmap.h" | 16 #include "third_party/skia/include/core/SkBitmap.h" |
| 16 #include "ui/gfx/gdi_util.h" | 17 #include "ui/gfx/gdi_util.h" |
| 17 #include "ui/gfx/image/image.h" | 18 #include "ui/gfx/image/image.h" |
| 18 #include "ui/gfx/image/image_family.h" | 19 #include "ui/gfx/image/image_family.h" |
| 19 #include "ui/gfx/size.h" | 20 #include "ui/gfx/size.h" |
| 20 | 21 |
| 21 namespace { | 22 namespace { |
| 22 | 23 |
| 24 const base::FilePath::CharType kIconChecksumFileExt[] = |
| 25 FILE_PATH_LITERAL(".ico.md5"); |
| 26 |
| 23 struct ScopedICONINFO : ICONINFO { | 27 struct ScopedICONINFO : ICONINFO { |
| 24 ScopedICONINFO() { | 28 ScopedICONINFO() { |
| 25 hbmColor = NULL; | 29 hbmColor = NULL; |
| 26 hbmMask = NULL; | 30 hbmMask = NULL; |
| 27 } | 31 } |
| 28 | 32 |
| 29 ~ScopedICONINFO() { | 33 ~ScopedICONINFO() { |
| 30 if (hbmColor) | 34 if (hbmColor) |
| 31 ::DeleteObject(hbmColor); | 35 ::DeleteObject(hbmColor); |
| 32 if (hbmMask) | 36 if (hbmMask) |
| (...skipping 430 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 463 if (!ConvertImageFamilyToBitmaps(resized_image_family, &bitmaps, &png_bytes)) | 467 if (!ConvertImageFamilyToBitmaps(resized_image_family, &bitmaps, &png_bytes)) |
| 464 return false; | 468 return false; |
| 465 | 469 |
| 466 // Guaranteed true because BuildResizedImageFamily will provide at least one | 470 // Guaranteed true because BuildResizedImageFamily will provide at least one |
| 467 // image < 256x256. | 471 // image < 256x256. |
| 468 DCHECK(!bitmaps.empty()); | 472 DCHECK(!bitmaps.empty()); |
| 469 size_t bitmap_count = bitmaps.size(); // Not including PNG image. | 473 size_t bitmap_count = bitmaps.size(); // Not including PNG image. |
| 470 // Including PNG image, if any. | 474 // Including PNG image, if any. |
| 471 size_t image_count = bitmap_count + (png_bytes.get() ? 1 : 0); | 475 size_t image_count = bitmap_count + (png_bytes.get() ? 1 : 0); |
| 472 | 476 |
| 473 // Now that basic checks are done, we can create the file. | |
| 474 base::win::ScopedHandle icon_file(::CreateFile(icon_path.value().c_str(), | |
| 475 GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); | |
| 476 | |
| 477 if (!icon_file.IsValid()) | |
| 478 return false; | |
| 479 | |
| 480 // Computing the total size of the buffer we need in order to store the | 477 // Computing the total size of the buffer we need in order to store the |
| 481 // images in the desired icon format. | 478 // images in the desired icon format. |
| 482 size_t buffer_size = ComputeIconFileBufferSize(bitmaps); | 479 size_t buffer_size = ComputeIconFileBufferSize(bitmaps); |
| 483 // Account for the bytes needed for the PNG entry. | 480 // Account for the bytes needed for the PNG entry. |
| 484 if (png_bytes.get()) | 481 if (png_bytes.get()) |
| 485 buffer_size += sizeof(ICONDIRENTRY) + png_bytes->size(); | 482 buffer_size += sizeof(ICONDIRENTRY) + png_bytes->size(); |
| 486 | 483 |
| 487 // Setting the information in the structures residing within the buffer. | 484 // Setting the information in the structures residing within the buffer. |
| 488 // First, we set the information which doesn't require iterating through the | 485 // First, we set the information which doesn't require iterating through the |
| 489 // bitmap set and then we set the bitmap specific structures. In the latter | 486 // bitmap set and then we set the bitmap specific structures. In the latter |
| (...skipping 24 matching lines...) Expand all Loading... |
| 514 entry->wPlanes = 1; | 511 entry->wPlanes = 1; |
| 515 entry->wBitCount = 32; | 512 entry->wBitCount = 32; |
| 516 entry->dwBytesInRes = static_cast<DWORD>(png_bytes->size()); | 513 entry->dwBytesInRes = static_cast<DWORD>(png_bytes->size()); |
| 517 entry->dwImageOffset = static_cast<DWORD>(offset); | 514 entry->dwImageOffset = static_cast<DWORD>(offset); |
| 518 memcpy(&buffer[offset], png_bytes->front(), png_bytes->size()); | 515 memcpy(&buffer[offset], png_bytes->front(), png_bytes->size()); |
| 519 offset += png_bytes->size(); | 516 offset += png_bytes->size(); |
| 520 } | 517 } |
| 521 | 518 |
| 522 DCHECK_EQ(offset, buffer_size); | 519 DCHECK_EQ(offset, buffer_size); |
| 523 | 520 |
| 524 // Finally, write the data to the file. | 521 std::string data(buffer.begin(), buffer.end()); |
| 525 DWORD bytes_written; | 522 return base::ImportantFileWriter::WriteFileAtomically(icon_path, data); |
| 526 bool delete_file = false; | |
| 527 if (!WriteFile(icon_file.Get(), &buffer[0], buffer_size, &bytes_written, | |
| 528 NULL) || | |
| 529 bytes_written != buffer_size) { | |
| 530 delete_file = true; | |
| 531 } | |
| 532 | |
| 533 ::CloseHandle(icon_file.Take()); | |
| 534 if (delete_file) { | |
| 535 bool success = file_util::Delete(icon_path, false); | |
| 536 DCHECK(success); | |
| 537 } | |
| 538 | |
| 539 return !delete_file; | |
| 540 } | 523 } |
| 541 | 524 |
| 542 bool IconUtil::PixelsHaveAlpha(const uint32* pixels, size_t num_pixels) { | 525 bool IconUtil::PixelsHaveAlpha(const uint32* pixels, size_t num_pixels) { |
| 543 for (const uint32* end = pixels + num_pixels; pixels != end; ++pixels) { | 526 for (const uint32* end = pixels + num_pixels; pixels != end; ++pixels) { |
| 544 if ((*pixels & 0xff000000) != 0) | 527 if ((*pixels & 0xff000000) != 0) |
| 545 return true; | 528 return true; |
| 546 } | 529 } |
| 547 | 530 |
| 548 return false; | 531 return false; |
| 549 } | 532 } |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 700 // Once we compute the size for a singe AND mask scan line, we multiply that | 683 // Once we compute the size for a singe AND mask scan line, we multiply that |
| 701 // number by the image height in order to get the total number of bytes for | 684 // number by the image height in order to get the total number of bytes for |
| 702 // the AND mask. Thus, for a 15X15 image, we need 15 * 4 which is 60 bytes | 685 // the AND mask. Thus, for a 15X15 image, we need 15 * 4 which is 60 bytes |
| 703 // for the monochrome bitmap representing the AND mask. | 686 // for the monochrome bitmap representing the AND mask. |
| 704 size_t and_line_length = (bitmap.width() + 7) >> 3; | 687 size_t and_line_length = (bitmap.width() + 7) >> 3; |
| 705 and_line_length = (and_line_length + 3) & ~3; | 688 and_line_length = (and_line_length + 3) & ~3; |
| 706 size_t and_mask_size = and_line_length * bitmap.height(); | 689 size_t and_mask_size = and_line_length * bitmap.height(); |
| 707 size_t masks_size = *xor_mask_size + and_mask_size; | 690 size_t masks_size = *xor_mask_size + and_mask_size; |
| 708 *bytes_in_resource = masks_size + sizeof(BITMAPINFOHEADER); | 691 *bytes_in_resource = masks_size + sizeof(BITMAPINFOHEADER); |
| 709 } | 692 } |
| 693 |
| 694 void IconUtil::GetImageCheckSum(const gfx::ImageFamily& image, |
| 695 base::MD5Digest* digest) { |
| 696 DCHECK(digest); |
| 697 base::MD5Context md5_context; |
| 698 base::MD5Init(&md5_context); |
| 699 |
| 700 for (gfx::ImageFamily::const_iterator it = image.begin(); it != image.end(); |
| 701 ++it) { |
| 702 SkBitmap bitmap = it->AsBitmap(); |
| 703 |
| 704 SkAutoLockPixels image_lock(bitmap); |
| 705 base::StringPiece image_data( |
| 706 reinterpret_cast<const char*>(bitmap.getPixels()), bitmap.getSize()); |
| 707 base::MD5Update(&md5_context, image_data); |
| 708 } |
| 709 |
| 710 base::MD5Final(digest, &md5_context); |
| 711 } |
| 712 |
| 713 bool IconUtil::SaveIconWithCheckSum(const base::FilePath& icon_file, |
| 714 const gfx::ImageFamily& image) { |
| 715 if (!CreateIconFileFromImageFamily(image, icon_file)) |
| 716 return false; |
| 717 |
| 718 base::MD5Digest digest; |
| 719 GetImageCheckSum(image, &digest); |
| 720 |
| 721 base::FilePath cheksum_file(icon_file.ReplaceExtension(kIconChecksumFileExt)); |
| 722 return file_util::WriteFile(cheksum_file, |
| 723 reinterpret_cast<const char*>(&digest), |
| 724 sizeof(digest)) == sizeof(digest); |
| 725 } |
| 726 |
| 727 bool IconUtil::ShouldUpdateIcon(const base::FilePath& icon_file, |
| 728 const gfx::ImageFamily& image) { |
| 729 base::FilePath checksum_file( |
| 730 icon_file.ReplaceExtension(kIconChecksumFileExt)); |
| 731 |
| 732 // Returns true if icon_file or checksum file is missing. |
| 733 if (!file_util::PathExists(icon_file) || |
| 734 !file_util::PathExists(checksum_file)) |
| 735 return true; |
| 736 |
| 737 base::MD5Digest persisted_image_checksum; |
| 738 if (sizeof(persisted_image_checksum) != file_util::ReadFile(checksum_file, |
| 739 reinterpret_cast<char*>(&persisted_image_checksum), |
| 740 sizeof(persisted_image_checksum))) |
| 741 return true; |
| 742 |
| 743 base::MD5Digest downloaded_image_checksum; |
| 744 GetImageCheckSum(image, &downloaded_image_checksum); |
| 745 |
| 746 // Update icon if checksums are not equal. |
| 747 return memcmp(&persisted_image_checksum, &downloaded_image_checksum, |
| 748 sizeof(base::MD5Digest)) != 0; |
| 749 } |
| OLD | NEW |