// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef UI_GFX_ICON_UTIL_H_
#define UI_GFX_ICON_UTIL_H_
#include <windows.h>
#include <stddef.h>
#include <stdint.h>
#include <memory>
#include <vector>
#include "base/win/scoped_gdi_object.h"
#include "ui/gfx/geometry/point.h"
#include "ui/gfx/geometry/size.h"
#include "ui/gfx/gfx_export.h"
namespace base {
class FilePath;
}
namespace gfx {
class ImageFamily;
class Size;
}
class SkBitmap;
///////////////////////////////////////////////////////////////////////////////
//
// The IconUtil class contains helper functions for manipulating Windows icons.
// The class interface contains methods for converting an HICON handle into an
// SkBitmap object and vice versa. The class can also create a .ico file given
// a PNG image contained in an SkBitmap object. The following code snippet
// shows an example usage of IconUtil::CreateHICONFromSkBitmap():
//
// SkBitmap bitmap;
//
// // Fill |bitmap| with valid data
// bitmap.setConfig(...);
// bitmap.allocPixels();
//
// ...
//
// // Convert the bitmap into a Windows HICON
// base::win::ScopedHICON icon(IconUtil::CreateHICONFromSkBitmap(bitmap));
// if (!icon.is_valid()) {
// // Handle error
// ...
// }
//
// // Use the icon with a WM_SETICON message
// ::SendMessage(hwnd, WM_SETICON, static_cast<WPARAM>(ICON_BIG),
// reinterpret_cast<LPARAM>(icon.get()));
//
///////////////////////////////////////////////////////////////////////////////
class GFX_EXPORT IconUtil {
public:
// ATOMIC_WRITE ensures that a partially written icon won't be created even if
// Chrome crashes part way through, but ATOMIC_WRITE is more expensive than
// NORMAL_WRITE. See CreateIconFileFromImageFamily. ATOMIC_WRITE is the
// default for historical reasons.
enum WriteType { ATOMIC_WRITE, NORMAL_WRITE };
// The size of the large icon entries in .ico files on Windows Vista+.
enum { kLargeIconSize = 256 };
// The size of icons in the medium icons view on Windows Vista+. This is the
// maximum size Windows will display an icon that does not have a 256x256
// image, even at the large or extra large icons views.
enum { kMediumIconSize = 48 };
// The dimensions for icon images in Windows icon files. All sizes are square;
// that is, the value 48 means a 48x48 pixel image. Sizes are listed in
// ascending order.
static const int kIconDimensions[];
// The number of elements in kIconDimensions.
static const size_t kNumIconDimensions;
// The number of elements in kIconDimensions <= kMediumIconSize.
static const size_t kNumIconDimensionsUpToMediumSize;
// Prevent clients from instantiating objects of that class.
IconUtil() = delete;
IconUtil(const IconUtil&) = delete;
IconUtil& operator=(const IconUtil&) = delete;
// Given an SkBitmap object, the function converts the bitmap to a Windows
// icon and returns the corresponding HICON handle if conversion succeeds.
static base::win::ScopedHICON CreateHICONFromSkBitmap(const SkBitmap& bitmap);
// Given a valid HICON handle representing an icon, this function converts
// the icon into an SkBitmap object containing an ARGB bitmap using the
// dimensions specified in |s|. |s| must specify valid dimensions (both
// width() an height() must be greater than zero). If the function cannot
// convert the icon to a bitmap (most probably due to an invalid parameter),
// the returned SkBitmap's isNull() method will return true.
static SkBitmap CreateSkBitmapFromHICON(HICON icon, const gfx::Size& s);
// Loads an icon resource as a SkBitmap for the specified |size| from a
// loaded .dll or .exe |module|. Supports loading smaller icon sizes as well
// as the Vista+ 256x256 PNG icon size. If the icon could not be loaded or
// found, returns a NULL scoped_ptr.
static std::unique_ptr<gfx::ImageFamily> CreateImageFamilyFromIconResource(
HMODULE module,
int resource_id);
// Given a valid HICON handle representing an icon, this function converts
// the icon into an SkBitmap object containing an ARGB bitmap using the
// dimensions of HICON. If the function cannot convert the icon to a bitmap
// (most probably due to an invalid parameter), the returned SkBitmap's
// isNull() method will return true.
static SkBitmap CreateSkBitmapFromHICON(HICON icon);
// Creates Windows .ico file at |icon_path|. The icon file is created with
// multiple BMP representations at varying predefined dimensions (by resizing
// an appropriately sized image from |image_family|) because Windows uses
// different image sizes when loading icons, depending on where the icon is
// drawn (ALT+TAB window, desktop shortcut, Quick Launch, etc.).
//
// If |image_family| contains an image larger than 48x48, the resulting icon
// will contain all sizes up to 256x256. The 256x256 image will be stored in
// PNG format inside the .ico file. If not, the resulting icon will contain
// all sizes up to 48x48.
//
// The function returns true on success and false otherwise. Returns false if
// |image_family| is empty.
static bool CreateIconFileFromImageFamily(
const gfx::ImageFamily& image_family,
const base::FilePath& icon_path,
WriteType write_type = ATOMIC_WRITE);
// Creates a cursor of the specified size from the SkBitmap passed in.
// Returns the cursor on success or NULL on failure.
static base::win::ScopedHICON CreateCursorFromSkBitmap(
const SkBitmap& bitmap,
const gfx::Point& hotspot);
// Given a valid HICON handle representing an icon, this function retrieves
// the hot spot of the icon.
static gfx::Point GetHotSpotFromHICON(HICON icon);
private:
// The icon format is published in the MSDN but there is no definition of
// the icon file structures in any of the Windows header files so we need to
// define these structure within the class. We must make sure we use 2 byte
// packing so that the structures are laid out properly within the file.
// See: http://msdn.microsoft.com/en-us/library/ms997538.aspx
#pragma pack(push)
#pragma pack(2)
// ICONDIRENTRY contains meta data for an individual icon image within a
// .ico file.
struct ICONDIRENTRY {
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
DWORD dwImageOffset;
};
// ICONDIR Contains information about all the icon images contained within a
// single .ico file.
struct ICONDIR {
WORD idReserved;
WORD idType;
WORD idCount;
ICONDIRENTRY idEntries[1];
};
// GRPICONDIRENTRY contains meta data for an individual icon image within a
// RT_GROUP_ICON resource in an .exe or .dll.
struct GRPICONDIRENTRY {
BYTE bWidth;
BYTE bHeight;
BYTE bColorCount;
BYTE bReserved;
WORD wPlanes;
WORD wBitCount;
DWORD dwBytesInRes;
WORD nID;
};
// GRPICONDIR Contains information about all the icon images contained within
// a RT_GROUP_ICON resource in an .exe or .dll.
struct GRPICONDIR {
WORD idReserved;
WORD idType;
WORD idCount;
GRPICONDIRENTRY idEntries[1];
};
// Contains the actual icon image.
struct ICONIMAGE {
BITMAPINFOHEADER icHeader;
RGBQUAD icColors[1];
BYTE icXOR[1];
BYTE icAND[1];
};
#pragma pack(pop)
friend class IconUtilTest;
// Returns true if any pixel in the given pixels buffer has an non-zero alpha.
static bool PixelsHaveAlpha(const uint32_t* pixels, size_t num_pixels);
// A helper function that initializes a BITMAPV5HEADER structure with a set
// of values.
static void InitializeBitmapHeader(BITMAPV5HEADER* header, int width,
int height);
// Given a single SkBitmap object and pointers to the corresponding icon
// structures within the icon data buffer, this function sets the image
// information (dimensions, color depth, etc.) in the icon structures and
// also copies the underlying icon image into the appropriate location.
// The width and height of |bitmap| must be < 256.
// (Note that the 256x256 icon is treated specially, as a PNG, and should not
// use this method.)
//
// The function will set the data pointed to by |image_byte_count| with the
// number of image bytes written to the buffer. Note that the number of bytes
// includes only the image data written into the memory pointed to by
// |icon_image|.
static void SetSingleIconImageInformation(const SkBitmap& bitmap,
size_t index,
ICONDIR* icon_dir,
ICONIMAGE* icon_image,
DWORD image_offset,
size_t* image_byte_count);
// Copies the bits of an SkBitmap object into a buffer holding the bits of
// the corresponding image for an icon within the .ico file.
static void CopySkBitmapBitsIntoIconBuffer(const SkBitmap& bitmap,
unsigned char* buffer,
size_t buffer_size);
// Given a set of bitmaps with varying dimensions, this function computes
// the amount of memory needed in order to store the bitmaps as image icons
// in a .ico file.
static size_t ComputeIconFileBufferSize(const std::vector<SkBitmap>& set);
// A helper function for computing various size components of a given bitmap.
// The different sizes can be used within the various .ico file structures.
//
// |xor_mask_size| - the size, in bytes, of the XOR mask in the ICONIMAGE
// structure.
// |and_mask_size| - the size, in bytes, of the AND mask in the ICONIMAGE
// structure.
// |bytes_in_resource| - the total number of bytes set in the ICONIMAGE
// structure. This value is equal to the sum of the
// bytes in the AND mask and the XOR mask plus the size
// of the BITMAPINFOHEADER structure. Note that since
// only 32bpp are handled by the IconUtil class, the
// icColors field in the ICONIMAGE structure is ignored
// and is not accounted for when computing the
// different size components.
static void ComputeBitmapSizeComponents(const SkBitmap& bitmap,
size_t* xor_mask_size,
DWORD* bytes_in_resource);
// A helper function of CreateSkBitmapFromHICON.
static SkBitmap CreateSkBitmapFromHICONHelper(HICON icon,
const gfx::Size& s);
};
#endif // UI_GFX_ICON_UTIL_H_