Index: ui/gfx/icon_util.cc |
=================================================================== |
--- ui/gfx/icon_util.cc (revision 175367) |
+++ ui/gfx/icon_util.cc (working copy) |
@@ -13,6 +13,7 @@ |
#include "skia/ext/image_operations.h" |
#include "third_party/skia/include/core/SkBitmap.h" |
#include "ui/gfx/gdi_util.h" |
+#include "ui/gfx/image/image.h" |
#include "ui/gfx/size.h" |
namespace { |
@@ -282,15 +283,25 @@ |
} |
bool IconUtil::CreateIconFileFromSkBitmap(const SkBitmap& bitmap, |
+ const SkBitmap& large_bitmap, |
const FilePath& icon_path) { |
// Only 32 bit ARGB bitmaps are supported. We also make sure the bitmap has |
// been properly initialized. |
SkAutoLockPixels bitmap_lock(bitmap); |
if ((bitmap.config() != SkBitmap::kARGB_8888_Config) || |
(bitmap.height() <= 0) || (bitmap.width() <= 0) || |
- (bitmap.getPixels() == NULL)) |
+ (bitmap.getPixels() == NULL)) { |
return false; |
+ } |
+ // If |large_bitmap| was specified, validate its dimension and convert to PNG. |
+ scoped_refptr<base::RefCountedMemory> png_bytes; |
+ if (!large_bitmap.empty()) { |
+ DCHECK_EQ(256, large_bitmap.width()); |
+ DCHECK_EQ(256, large_bitmap.height()); |
+ png_bytes = gfx::Image(large_bitmap).As1xPNGBytes(); |
+ } |
+ |
// We start by creating the file. |
base::win::ScopedHandle icon_file(::CreateFile(icon_path.value().c_str(), |
GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)); |
@@ -309,21 +320,29 @@ |
// Computing the total size of the buffer we need in order to store the |
// images in the desired icon format. |
size_t buffer_size = ComputeIconFileBufferSize(bitmaps); |
- unsigned char* buffer = new unsigned char[buffer_size]; |
- DCHECK(buffer != NULL); |
- memset(buffer, 0, buffer_size); |
+ // Account for the bytes needed for the PNG entry. |
+ if (png_bytes.get()) |
+ buffer_size += sizeof(ICONDIRENTRY) + png_bytes->size(); |
// Setting the information in the structures residing within the buffer. |
// First, we set the information which doesn't require iterating through the |
// bitmap set and then we set the bitmap specific structures. In the latter |
// step we also copy the actual bits. |
- ICONDIR* icon_dir = reinterpret_cast<ICONDIR*>(buffer); |
+ std::vector<uint8> buffer(buffer_size); |
+ ICONDIR* icon_dir = reinterpret_cast<ICONDIR*>(&buffer[0]); |
icon_dir->idType = kResourceTypeIcon; |
icon_dir->idCount = bitmap_count; |
size_t icon_dir_count = bitmap_count - 1; // Note DCHECK(!bitmaps.empty())! |
+ |
+ // Increment counts if a PNG entry will be added. |
+ if (png_bytes.get()) { |
+ icon_dir->idCount++; |
+ icon_dir_count++; |
+ } |
+ |
size_t offset = sizeof(ICONDIR) + (sizeof(ICONDIRENTRY) * icon_dir_count); |
for (size_t i = 0; i < bitmap_count; i++) { |
- ICONIMAGE* image = reinterpret_cast<ICONIMAGE*>(buffer + offset); |
+ ICONIMAGE* image = reinterpret_cast<ICONIMAGE*>(&buffer[offset]); |
DCHECK_LT(offset, buffer_size); |
size_t icon_image_size = 0; |
SetSingleIconImageInformation(bitmaps[i], i, icon_dir, image, offset, |
@@ -331,17 +350,32 @@ |
DCHECK_GT(icon_image_size, 0U); |
offset += icon_image_size; |
} |
+ |
+ // Add the PNG entry, if necessary. |
+ if (png_bytes.get()) { |
+ ICONDIRENTRY* entry = &icon_dir->idEntries[bitmap_count]; |
+ entry->bWidth = 0; |
+ entry->bHeight = 0; |
+ entry->wPlanes = 1; |
+ entry->wBitCount = 32; |
+ entry->dwBytesInRes = png_bytes->size(); |
+ entry->dwImageOffset = offset; |
+ memcpy(&buffer[offset], png_bytes->front(), png_bytes->size()); |
+ offset += png_bytes->size(); |
+ } |
+ |
DCHECK_EQ(offset, buffer_size); |
- // Finally, writing the data info the file. |
+ // Finally, write the data to the file. |
DWORD bytes_written; |
bool delete_file = false; |
- if (!WriteFile(icon_file.Get(), buffer, buffer_size, &bytes_written, NULL) || |
- bytes_written != buffer_size) |
+ if (!WriteFile(icon_file.Get(), &buffer[0], buffer_size, &bytes_written, |
+ NULL) || |
+ bytes_written != buffer_size) { |
delete_file = true; |
+ } |
::CloseHandle(icon_file.Take()); |
- delete [] buffer; |
if (delete_file) { |
bool success = file_util::Delete(icon_path, false); |
DCHECK(success); |