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