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
3// found in the LICENSE file.
4
5#ifndef UI_GFX_ICON_UTIL_H_
6#define UI_GFX_ICON_UTIL_H_
7
8#include <windows.h>
9#include <string>
10#include <vector>
11
12#include "base/basictypes.h"
13#include "base/gtest_prod_util.h"
14#include "base/memory/scoped_ptr.h"
15#include "ui/gfx/gfx_export.h"
16#include "ui/gfx/point.h"
17#include "ui/gfx/size.h"
18
19namespace base {
20class FilePath;
21}
22
23namespace gfx {
24class ImageFamily;
25class Size;
26}
27class SkBitmap;
28
29///////////////////////////////////////////////////////////////////////////////
30//
31// The IconUtil class contains helper functions for manipulating Windows icons.
32// The class interface contains methods for converting an HICON handle into an
33// SkBitmap object and vice versa. The class can also create a .ico file given
34// a PNG image contained in an SkBitmap object. The following code snippet
35// shows an example usage of IconUtil::CreateHICONFromSkBitmap():
36//
37//   SkBitmap bitmap;
38//
39//   // Fill |bitmap| with valid data
40//   bitmap.setConfig(...);
41//   bitmap.allocPixels();
42//
43//   ...
44//
45//   // Convert the bitmap into a Windows HICON
46//   HICON icon = IconUtil::CreateHICONFromSkBitmap(bitmap);
47//   if (icon == NULL) {
48//     // Handle error
49//     ...
50//   }
51//
52//   // Use the icon with a WM_SETICON message
53//   ::SendMessage(hwnd, WM_SETICON, static_cast<WPARAM>(ICON_BIG),
54//                 reinterpret_cast<LPARAM>(icon));
55//
56//   // Destroy the icon when we are done
57//   ::DestroyIcon(icon);
58//
59///////////////////////////////////////////////////////////////////////////////
60class GFX_EXPORT IconUtil {
61 public:
62  // The size of the large icon entries in .ico files on Windows Vista+.
63  static const int kLargeIconSize = 256;
64  // The size of icons in the medium icons view on Windows Vista+. This is the
65  // maximum size Windows will display an icon that does not have a 256x256
66  // image, even at the large or extra large icons views.
67  static const int kMediumIconSize = 48;
68
69  // The dimensions for icon images in Windows icon files. All sizes are square;
70  // that is, the value 48 means a 48x48 pixel image. Sizes are listed in
71  // ascending order.
72  static const int kIconDimensions[];
73
74  // The number of elements in kIconDimensions.
75  static const size_t kNumIconDimensions;
76  // The number of elements in kIconDimensions <= kMediumIconSize.
77  static const size_t kNumIconDimensionsUpToMediumSize;
78
79  // Given an SkBitmap object, the function converts the bitmap to a Windows
80  // icon and returns the corresponding HICON handle. If the function cannot
81  // convert the bitmap, NULL is returned.
82  //
83  // The client is responsible for destroying the icon when it is no longer
84  // needed by calling ::DestroyIcon().
85  static HICON CreateHICONFromSkBitmap(const SkBitmap& bitmap);
86
87  // Given a valid HICON handle representing an icon, this function converts
88  // the icon into an SkBitmap object containing an ARGB bitmap using the
89  // dimensions specified in |s|. |s| must specify valid dimensions (both
90  // width() an height() must be greater than zero). If the function cannot
91  // convert the icon to a bitmap (most probably due to an invalid parameter),
92  // the return value is NULL.
93  //
94  // The client owns the returned bitmap object and is responsible for deleting
95  // it when it is no longer needed.
96  static SkBitmap* CreateSkBitmapFromHICON(HICON icon, const gfx::Size& s);
97
98  // Loads an icon resource  as a SkBitmap for the specified |size| from a
99  // loaded .dll or .exe |module|. Supports loading smaller icon sizes as well
100  // as the Vista+ 256x256 PNG icon size. If the icon could not be loaded or
101  // found, returns a NULL scoped_ptr.
102  static scoped_ptr<SkBitmap> CreateSkBitmapFromIconResource(HMODULE module,
103                                                             int resource_id,
104                                                             int size);
105
106  // Given a valid HICON handle representing an icon, this function converts
107  // the icon into an SkBitmap object containing an ARGB bitmap using the
108  // dimensions of HICON. If the function cannot convert the icon to a bitmap
109  // (most probably due to an invalid parameter), the return value is NULL.
110  //
111  // The client owns the returned bitmap object and is responsible for deleting
112  // it when it is no longer needed.
113  static SkBitmap* CreateSkBitmapFromHICON(HICON icon);
114
115  // Creates Windows .ico file at |icon_path|. The icon file is created with
116  // multiple BMP representations at varying predefined dimensions (by resizing
117  // an appropriately sized image from |image_family|) because Windows uses
118  // different image sizes when loading icons, depending on where the icon is
119  // drawn (ALT+TAB window, desktop shortcut, Quick Launch, etc.).
120  //
121  // If |image_family| contains an image larger than 48x48, the resulting icon
122  // will contain all sizes up to 256x256. The 256x256 image will be stored in
123  // PNG format inside the .ico file. If not, the resulting icon will contain
124  // all sizes up to 48x48.
125  //
126  // The function returns true on success and false otherwise. Returns false if
127  // |image_family| is empty.
128  static bool CreateIconFileFromImageFamily(
129      const gfx::ImageFamily& image_family,
130      const base::FilePath& icon_path);
131
132  // Creates a cursor of the specified size from the DIB passed in.
133  // Returns the cursor on success or NULL on failure.
134  static HICON CreateCursorFromDIB(const gfx::Size& icon_size,
135                                   const gfx::Point& hotspot,
136                                   const void* dib_bits,
137                                   size_t dib_size);
138
139 private:
140  // The icon format is published in the MSDN but there is no definition of
141  // the icon file structures in any of the Windows header files so we need to
142  // define these structure within the class. We must make sure we use 2 byte
143  // packing so that the structures are layed out properly within the file.
144  // See: http://msdn.microsoft.com/en-us/library/ms997538.aspx
145#pragma pack(push)
146#pragma pack(2)
147
148  // ICONDIRENTRY contains meta data for an individual icon image within a
149  // .ico file.
150  struct ICONDIRENTRY {
151    BYTE bWidth;
152    BYTE bHeight;
153    BYTE bColorCount;
154    BYTE bReserved;
155    WORD wPlanes;
156    WORD wBitCount;
157    DWORD dwBytesInRes;
158    DWORD dwImageOffset;
159  };
160
161  // ICONDIR Contains information about all the icon images contained within a
162  // single .ico file.
163  struct ICONDIR {
164    WORD idReserved;
165    WORD idType;
166    WORD idCount;
167    ICONDIRENTRY idEntries[1];
168  };
169
170  // GRPICONDIRENTRY contains meta data for an individual icon image within a
171  // RT_GROUP_ICON resource in an .exe or .dll.
172  struct GRPICONDIRENTRY {
173    BYTE bWidth;
174    BYTE bHeight;
175    BYTE bColorCount;
176    BYTE bReserved;
177    WORD wPlanes;
178    WORD wBitCount;
179    DWORD dwBytesInRes;
180    WORD nID;
181  };
182
183  // GRPICONDIR Contains information about all the icon images contained within
184  // a RT_GROUP_ICON resource in an .exe or .dll.
185  struct GRPICONDIR {
186    WORD idReserved;
187    WORD idType;
188    WORD idCount;
189    GRPICONDIRENTRY idEntries[1];
190  };
191
192  // Contains the actual icon image.
193  struct ICONIMAGE {
194    BITMAPINFOHEADER icHeader;
195    RGBQUAD icColors[1];
196    BYTE icXOR[1];
197    BYTE icAND[1];
198  };
199#pragma pack(pop)
200
201  friend class IconUtilTest;
202
203  // Used for indicating that the .ico contains an icon (rather than a cursor)
204  // image. This value is set in the |idType| field of the ICONDIR structure.
205  static const int kResourceTypeIcon = 1;
206
207  // Returns true if any pixel in the given pixels buffer has an non-zero alpha.
208  static bool PixelsHaveAlpha(const uint32* pixels, size_t num_pixels);
209
210  // A helper function that initializes a BITMAPV5HEADER structure with a set
211  // of values.
212  static void InitializeBitmapHeader(BITMAPV5HEADER* header, int width,
213                                     int height);
214
215  // Given a single SkBitmap object and pointers to the corresponding icon
216  // structures within the icon data buffer, this function sets the image
217  // information (dimensions, color depth, etc.) in the icon structures and
218  // also copies the underlying icon image into the appropriate location.
219  // The width and height of |bitmap| must be < 256.
220  // (Note that the 256x256 icon is treated specially, as a PNG, and should not
221  // use this method.)
222  //
223  // The function will set the data pointed to by |image_byte_count| with the
224  // number of image bytes written to the buffer. Note that the number of bytes
225  // includes only the image data written into the memory pointed to by
226  // |icon_image|.
227  static void SetSingleIconImageInformation(const SkBitmap& bitmap,
228                                            size_t index,
229                                            ICONDIR* icon_dir,
230                                            ICONIMAGE* icon_image,
231                                            size_t image_offset,
232                                            size_t* image_byte_count);
233
234  // Copies the bits of an SkBitmap object into a buffer holding the bits of
235  // the corresponding image for an icon within the .ico file.
236  static void CopySkBitmapBitsIntoIconBuffer(const SkBitmap& bitmap,
237                                             unsigned char* buffer,
238                                             size_t buffer_size);
239
240  // Given a set of bitmaps with varying dimensions, this function computes
241  // the amount of memory needed in order to store the bitmaps as image icons
242  // in a .ico file.
243  static size_t ComputeIconFileBufferSize(const std::vector<SkBitmap>& set);
244
245  // A helper function for computing various size components of a given bitmap.
246  // The different sizes can be used within the various .ico file structures.
247  //
248  // |xor_mask_size| - the size, in bytes, of the XOR mask in the ICONIMAGE
249  //                   structure.
250  // |and_mask_size| - the size, in bytes, of the AND mask in the ICONIMAGE
251  //                   structure.
252  // |bytes_in_resource| - the total number of bytes set in the ICONIMAGE
253  //                       structure. This value is equal to the sum of the
254  //                       bytes in the AND mask and the XOR mask plus the size
255  //                       of the BITMAPINFOHEADER structure. Note that since
256  //                       only 32bpp are handled by the IconUtil class, the
257  //                       icColors field in the ICONIMAGE structure is ignored
258  //                       and is not accounted for when computing the
259  //                       different size components.
260  static void ComputeBitmapSizeComponents(const SkBitmap& bitmap,
261                                          size_t* xor_mask_size,
262                                          size_t* bytes_in_resource);
263
264  // A helper function of CreateSkBitmapFromHICON.
265  static SkBitmap CreateSkBitmapFromHICONHelper(HICON icon,
266                                                const gfx::Size& s);
267
268  // Prevent clients from instantiating objects of that class by declaring the
269  // ctor/dtor as private.
270  DISALLOW_IMPLICIT_CONSTRUCTORS(IconUtil);
271};
272
273#endif  // UI_GFX_ICON_UTIL_H_
274