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