user32: Use the stored color and mask bitmaps instead of the raw bits in GetIconInfo.
[wine] / dlls / user32 / cursoricon.c
1 /*
2  * Cursor and icon support
3  *
4  * Copyright 1995 Alexandre Julliard
5  *           1996 Martin Von Loewis
6  *           1997 Alex Korobka
7  *           1998 Turchanov Sergey
8  *           2007 Henri Verbeet
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 /*
26  * Theory:
27  *
28  * Cursors and icons are stored in a global heap block, with the
29  * following layout:
30  *
31  * CURSORICONINFO info;
32  * BYTE[]         ANDbits;
33  * BYTE[]         XORbits;
34  *
35  * The bits structures are in the format of a device-dependent bitmap.
36  *
37  * This layout is very sub-optimal, as the bitmap bits are stored in
38  * the X client instead of in the server like other bitmaps; however,
39  * some programs (notably Paint Brush) expect to be able to manipulate
40  * the bits directly :-(
41  */
42
43 #include "config.h"
44 #include "wine/port.h"
45
46 #include <stdarg.h>
47 #include <string.h>
48 #include <stdlib.h>
49
50 #include "windef.h"
51 #include "winbase.h"
52 #include "wingdi.h"
53 #include "winerror.h"
54 #include "wine/winbase16.h"
55 #include "wine/winuser16.h"
56 #include "wine/exception.h"
57 #include "wine/server.h"
58 #include "controls.h"
59 #include "user_private.h"
60 #include "wine/debug.h"
61
62 WINE_DEFAULT_DEBUG_CHANNEL(cursor);
63 WINE_DECLARE_DEBUG_CHANNEL(icon);
64 WINE_DECLARE_DEBUG_CHANNEL(resource);
65
66 #include "pshpack1.h"
67
68 typedef struct {
69     BYTE bWidth;
70     BYTE bHeight;
71     BYTE bColorCount;
72     BYTE bReserved;
73     WORD xHotspot;
74     WORD yHotspot;
75     DWORD dwDIBSize;
76     DWORD dwDIBOffset;
77 } CURSORICONFILEDIRENTRY;
78
79 typedef struct
80 {
81     WORD                idReserved;
82     WORD                idType;
83     WORD                idCount;
84     CURSORICONFILEDIRENTRY  idEntries[1];
85 } CURSORICONFILEDIR;
86
87 #include "poppack.h"
88
89 static RECT CURSOR_ClipRect;       /* Cursor clipping rect */
90
91 static HDC screen_dc;
92
93 static const WCHAR DISPLAYW[] = {'D','I','S','P','L','A','Y',0};
94
95
96 /**********************************************************************
97  * ICONCACHE for cursors/icons loaded with LR_SHARED.
98  *
99  * FIXME: This should not be allocated on the system heap, but on a
100  *        subsystem-global heap (i.e. one for all Win16 processes,
101  *        and one for each Win32 process).
102  */
103 typedef struct tagICONCACHE
104 {
105     struct tagICONCACHE *next;
106
107     HMODULE              hModule;
108     HRSRC                hRsrc;
109     HRSRC                hGroupRsrc;
110     HICON                hIcon;
111
112     INT                  count;
113
114 } ICONCACHE;
115
116 static ICONCACHE *IconAnchor = NULL;
117
118 static CRITICAL_SECTION IconCrst;
119 static CRITICAL_SECTION_DEBUG critsect_debug =
120 {
121     0, 0, &IconCrst,
122     { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
123       0, 0, { (DWORD_PTR)(__FILE__ ": IconCrst") }
124 };
125 static CRITICAL_SECTION IconCrst = { &critsect_debug, -1, 0, 0, 0, 0 };
126
127 static const WORD ICON_HOTSPOT = 0x4242;
128
129
130 /**********************************************************************
131  * User objects management
132  */
133
134 struct cursoricon_object
135 {
136     struct user_object obj;      /* object header */
137     ULONG_PTR          param;    /* opaque param used by 16-bit code */
138     HBITMAP            color;    /* color bitmap */
139     HBITMAP            alpha;    /* pre-multiplied alpha bitmap for 32-bpp icons */
140     HBITMAP            mask;     /* mask bitmap (followed by color for 1-bpp icons) */
141     CURSORICONINFO     data;
142     /* followed by cursor bits in CURSORICONINFO format */
143 };
144
145 static HICON alloc_icon_handle( unsigned int size )
146 {
147     struct cursoricon_object *obj = HeapAlloc( GetProcessHeap(), 0, sizeof(*obj) + size );
148     if (!obj) return 0;
149     obj->param = 0;
150     obj->color = 0;
151     obj->alpha = 0;
152     obj->mask  = 0;
153     return alloc_user_handle( &obj->obj, USER_ICON );
154 }
155
156 static struct cursoricon_object *get_icon_ptr( HICON handle )
157 {
158     struct cursoricon_object *obj = get_user_handle_ptr( handle, USER_ICON );
159     if (obj == OBJ_OTHER_PROCESS)
160     {
161         WARN( "icon handle %p from other process\n", handle );
162         obj = NULL;
163     }
164     return obj;
165 }
166
167 static void release_icon_ptr( HICON handle, struct cursoricon_object *ptr )
168 {
169     release_user_handle_ptr( ptr );
170 }
171
172 static BOOL free_icon_handle( HICON handle )
173 {
174     struct cursoricon_object *obj = free_user_handle( handle, USER_ICON );
175
176     if (obj == OBJ_OTHER_PROCESS) WARN( "icon handle %p from other process\n", handle );
177     else if (obj)
178     {
179         ULONG_PTR param = obj->param;
180         if (obj->color) DeleteObject( obj->color );
181         if (obj->alpha) DeleteObject( obj->alpha );
182         DeleteObject( obj->mask );
183         HeapFree( GetProcessHeap(), 0, obj );
184         if (wow_handlers.free_icon_param && param) wow_handlers.free_icon_param( param );
185         USER_Driver->pDestroyCursorIcon( handle );
186         return TRUE;
187     }
188     return FALSE;
189 }
190
191 ULONG_PTR get_icon_param( HICON handle )
192 {
193     ULONG_PTR ret = 0;
194     struct cursoricon_object *obj = get_user_handle_ptr( handle, USER_ICON );
195
196     if (obj == OBJ_OTHER_PROCESS) WARN( "icon handle %p from other process\n", handle );
197     else if (obj)
198     {
199         ret = obj->param;
200         release_user_handle_ptr( obj );
201     }
202     return ret;
203 }
204
205 ULONG_PTR set_icon_param( HICON handle, ULONG_PTR param )
206 {
207     ULONG_PTR ret = 0;
208     struct cursoricon_object *obj = get_user_handle_ptr( handle, USER_ICON );
209
210     if (obj == OBJ_OTHER_PROCESS) WARN( "icon handle %p from other process\n", handle );
211     else if (obj)
212     {
213         ret = obj->param;
214         obj->param = param;
215         release_user_handle_ptr( obj );
216     }
217     return ret;
218 }
219
220
221 /***********************************************************************
222  *             map_fileW
223  *
224  * Helper function to map a file to memory:
225  *  name                        -       file name
226  *  [RETURN] ptr                -       pointer to mapped file
227  *  [RETURN] filesize           -       pointer size of file to be stored if not NULL
228  */
229 static void *map_fileW( LPCWSTR name, LPDWORD filesize )
230 {
231     HANDLE hFile, hMapping;
232     LPVOID ptr = NULL;
233
234     hFile = CreateFileW( name, GENERIC_READ, FILE_SHARE_READ, NULL,
235                          OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 );
236     if (hFile != INVALID_HANDLE_VALUE)
237     {
238         hMapping = CreateFileMappingW( hFile, NULL, PAGE_READONLY, 0, 0, NULL );
239         if (hMapping)
240         {
241             ptr = MapViewOfFile( hMapping, FILE_MAP_READ, 0, 0, 0 );
242             CloseHandle( hMapping );
243             if (filesize)
244                 *filesize = GetFileSize( hFile, NULL );
245         }
246         CloseHandle( hFile );
247     }
248     return ptr;
249 }
250
251
252 /***********************************************************************
253  *           get_bitmap_width_bytes
254  *
255  * Return number of bytes taken by a scanline of 16-bit aligned Windows DDB
256  * data.
257  */
258 static int get_bitmap_width_bytes( int width, int bpp )
259 {
260     switch(bpp)
261     {
262     case 1:
263         return 2 * ((width+15) / 16);
264     case 4:
265         return 2 * ((width+3) / 4);
266     case 24:
267         width *= 3;
268         /* fall through */
269     case 8:
270         return width + (width & 1);
271     case 16:
272     case 15:
273         return width * 2;
274     case 32:
275         return width * 4;
276     default:
277         WARN("Unknown depth %d, please report.\n", bpp );
278     }
279     return -1;
280 }
281
282
283 /***********************************************************************
284  *          get_dib_width_bytes
285  *
286  * Return the width of a DIB bitmap in bytes. DIB bitmap data is 32-bit aligned.
287  */
288 static int get_dib_width_bytes( int width, int depth )
289 {
290     int words;
291
292     switch(depth)
293     {
294     case 1:  words = (width + 31) / 32; break;
295     case 4:  words = (width + 7) / 8; break;
296     case 8:  words = (width + 3) / 4; break;
297     case 15:
298     case 16: words = (width + 1) / 2; break;
299     case 24: words = (width * 3 + 3)/4; break;
300     default:
301         WARN("(%d): Unsupported depth\n", depth );
302         /* fall through */
303     case 32:
304         words = width;
305     }
306     return 4 * words;
307 }
308
309
310 /***********************************************************************
311  *           bitmap_info_size
312  *
313  * Return the size of the bitmap info structure including color table.
314  */
315 static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
316 {
317     unsigned int colors, size, masks = 0;
318
319     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
320     {
321         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
322         colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
323         return sizeof(BITMAPCOREHEADER) + colors *
324              ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
325     }
326     else  /* assume BITMAPINFOHEADER */
327     {
328         colors = info->bmiHeader.biClrUsed;
329         if (colors > 256) /* buffer overflow otherwise */
330                 colors = 256;
331         if (!colors && (info->bmiHeader.biBitCount <= 8))
332             colors = 1 << info->bmiHeader.biBitCount;
333         if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
334         size = max( info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) );
335         return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
336     }
337 }
338
339
340 /***********************************************************************
341  *             copy_bitmap
342  *
343  * Helper function to duplicate a bitmap.
344  */
345 static HBITMAP copy_bitmap( HBITMAP bitmap )
346 {
347     HDC src, dst;
348     HBITMAP new_bitmap;
349     BITMAP bmp;
350
351     if (!bitmap) return 0;
352     if (!GetObjectW( bitmap, sizeof(bmp), &bmp )) return 0;
353
354     src = CreateCompatibleDC( 0 );
355     dst = CreateCompatibleDC( 0 );
356     SelectObject( src, bitmap );
357     new_bitmap = CreateCompatibleBitmap( src, bmp.bmWidth, bmp.bmHeight );
358     SelectObject( dst, new_bitmap );
359     BitBlt( dst, 0, 0, bmp.bmWidth, bmp.bmHeight, src, 0, 0, SRCCOPY );
360     DeleteDC( dst );
361     DeleteDC( src );
362     return new_bitmap;
363 }
364
365
366 /***********************************************************************
367  *          is_dib_monochrome
368  *
369  * Returns whether a DIB can be converted to a monochrome DDB.
370  *
371  * A DIB can be converted if its color table contains only black and
372  * white. Black must be the first color in the color table.
373  *
374  * Note : If the first color in the color table is white followed by
375  *        black, we can't convert it to a monochrome DDB with
376  *        SetDIBits, because black and white would be inverted.
377  */
378 static BOOL is_dib_monochrome( const BITMAPINFO* info )
379 {
380     if (info->bmiHeader.biBitCount != 1) return FALSE;
381
382     if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
383     {
384         const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors;
385
386         /* Check if the first color is black */
387         if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
388         {
389             rgb++;
390
391             /* Check if the second color is white */
392             return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
393                  && (rgb->rgbtBlue == 0xff));
394         }
395         else return FALSE;
396     }
397     else  /* assume BITMAPINFOHEADER */
398     {
399         const RGBQUAD *rgb = info->bmiColors;
400
401         /* Check if the first color is black */
402         if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
403             (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
404         {
405             rgb++;
406
407             /* Check if the second color is white */
408             return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
409                  && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
410         }
411         else return FALSE;
412     }
413 }
414
415 /***********************************************************************
416  *           DIB_GetBitmapInfo
417  *
418  * Get the info from a bitmap header.
419  * Return 1 for INFOHEADER, 0 for COREHEADER,
420  */
421 static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
422                               LONG *height, WORD *bpp, DWORD *compr )
423 {
424     if (header->biSize == sizeof(BITMAPCOREHEADER))
425     {
426         const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
427         *width  = core->bcWidth;
428         *height = core->bcHeight;
429         *bpp    = core->bcBitCount;
430         *compr  = 0;
431         return 0;
432     }
433     else if (header->biSize >= sizeof(BITMAPINFOHEADER))
434     {
435         *width  = header->biWidth;
436         *height = header->biHeight;
437         *bpp    = header->biBitCount;
438         *compr  = header->biCompression;
439         return 1;
440     }
441     ERR("(%d): unknown/wrong size for header\n", header->biSize );
442     return -1;
443 }
444
445 /**********************************************************************
446  *          CURSORICON_FindSharedIcon
447  */
448 static HICON CURSORICON_FindSharedIcon( HMODULE hModule, HRSRC hRsrc )
449 {
450     HICON hIcon = 0;
451     ICONCACHE *ptr;
452
453     EnterCriticalSection( &IconCrst );
454
455     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
456         if ( ptr->hModule == hModule && ptr->hRsrc == hRsrc )
457         {
458             ptr->count++;
459             hIcon = ptr->hIcon;
460             break;
461         }
462
463     LeaveCriticalSection( &IconCrst );
464
465     return hIcon;
466 }
467
468 /*************************************************************************
469  * CURSORICON_FindCache
470  *
471  * Given a handle, find the corresponding cache element
472  *
473  * PARAMS
474  *      Handle     [I] handle to an Image
475  *
476  * RETURNS
477  *     Success: The cache entry
478  *     Failure: NULL
479  *
480  */
481 static ICONCACHE* CURSORICON_FindCache(HICON hIcon)
482 {
483     ICONCACHE *ptr;
484     ICONCACHE *pRet=NULL;
485     BOOL IsFound = FALSE;
486
487     EnterCriticalSection( &IconCrst );
488
489     for (ptr = IconAnchor; ptr != NULL && !IsFound; ptr = ptr->next)
490     {
491         if ( hIcon == ptr->hIcon )
492         {
493             IsFound = TRUE;
494             pRet = ptr;
495         }
496     }
497
498     LeaveCriticalSection( &IconCrst );
499
500     return pRet;
501 }
502
503 /**********************************************************************
504  *          CURSORICON_AddSharedIcon
505  */
506 static void CURSORICON_AddSharedIcon( HMODULE hModule, HRSRC hRsrc, HRSRC hGroupRsrc, HICON hIcon )
507 {
508     ICONCACHE *ptr = HeapAlloc( GetProcessHeap(), 0, sizeof(ICONCACHE) );
509     if ( !ptr ) return;
510
511     ptr->hModule = hModule;
512     ptr->hRsrc   = hRsrc;
513     ptr->hIcon  = hIcon;
514     ptr->hGroupRsrc = hGroupRsrc;
515     ptr->count   = 1;
516
517     EnterCriticalSection( &IconCrst );
518     ptr->next    = IconAnchor;
519     IconAnchor   = ptr;
520     LeaveCriticalSection( &IconCrst );
521 }
522
523 /**********************************************************************
524  *          CURSORICON_DelSharedIcon
525  */
526 static INT CURSORICON_DelSharedIcon( HICON hIcon )
527 {
528     INT count = -1;
529     ICONCACHE *ptr;
530
531     EnterCriticalSection( &IconCrst );
532
533     for ( ptr = IconAnchor; ptr; ptr = ptr->next )
534         if ( ptr->hIcon == hIcon )
535         {
536             if ( ptr->count > 0 ) ptr->count--;
537             count = ptr->count;
538             break;
539         }
540
541     LeaveCriticalSection( &IconCrst );
542
543     return count;
544 }
545
546 /**********************************************************************
547  *              get_icon_size
548  */
549 BOOL get_icon_size( HICON handle, SIZE *size )
550 {
551     struct cursoricon_object *info;
552
553     if (!(info = get_icon_ptr( handle ))) return FALSE;
554     size->cx = info->data.nWidth;
555     size->cy = info->data.nHeight;
556     release_icon_ptr( handle, info );
557     return TRUE;
558 }
559
560 /*
561  *  The following macro functions account for the irregularities of
562  *   accessing cursor and icon resources in files and resource entries.
563  */
564 typedef BOOL (*fnGetCIEntry)( LPVOID dir, int n,
565                               int *width, int *height, int *bits );
566
567 /**********************************************************************
568  *          CURSORICON_FindBestIcon
569  *
570  * Find the icon closest to the requested size and bit depth.
571  */
572 static int CURSORICON_FindBestIcon( LPVOID dir, fnGetCIEntry get_entry,
573                                     int width, int height, int depth )
574 {
575     int i, cx, cy, bits, bestEntry = -1;
576     UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
577     UINT iTempXDiff, iTempYDiff, iTempColorDiff;
578
579     /* Find Best Fit */
580     iTotalDiff = 0xFFFFFFFF;
581     iColorDiff = 0xFFFFFFFF;
582     for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
583     {
584         iTempXDiff = abs(width - cx);
585         iTempYDiff = abs(height - cy);
586
587         if(iTotalDiff > (iTempXDiff + iTempYDiff))
588         {
589             iXDiff = iTempXDiff;
590             iYDiff = iTempYDiff;
591             iTotalDiff = iXDiff + iYDiff;
592         }
593     }
594
595     /* Find Best Colors for Best Fit */
596     for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
597     {
598         if(abs(width - cx) == iXDiff && abs(height - cy) == iYDiff)
599         {
600             iTempColorDiff = abs(depth - bits);
601             if(iColorDiff > iTempColorDiff)
602             {
603                 bestEntry = i;
604                 iColorDiff = iTempColorDiff;
605             }
606         }
607     }
608
609     return bestEntry;
610 }
611
612 static BOOL CURSORICON_GetResIconEntry( LPVOID dir, int n,
613                                         int *width, int *height, int *bits )
614 {
615     CURSORICONDIR *resdir = dir;
616     ICONRESDIR *icon;
617
618     if ( resdir->idCount <= n )
619         return FALSE;
620     icon = &resdir->idEntries[n].ResInfo.icon;
621     *width = icon->bWidth;
622     *height = icon->bHeight;
623     *bits = resdir->idEntries[n].wBitCount;
624     return TRUE;
625 }
626
627 /**********************************************************************
628  *          CURSORICON_FindBestCursor
629  *
630  * Find the cursor closest to the requested size.
631  *
632  * FIXME: parameter 'color' ignored.
633  */
634 static int CURSORICON_FindBestCursor( LPVOID dir, fnGetCIEntry get_entry,
635                                       int width, int height, int depth )
636 {
637     int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
638
639     /* Double height to account for AND and XOR masks */
640
641     height *= 2;
642
643     /* First find the largest one smaller than or equal to the requested size*/
644
645     maxwidth = maxheight = 0;
646     for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
647     {
648         if ((cx <= width) && (cy <= height) &&
649             (cx > maxwidth) && (cy > maxheight))
650         {
651             bestEntry = i;
652             maxwidth  = cx;
653             maxheight = cy;
654         }
655     }
656     if (bestEntry != -1) return bestEntry;
657
658     /* Now find the smallest one larger than the requested size */
659
660     maxwidth = maxheight = 255;
661     for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
662     {
663         if (((cx < maxwidth) && (cy < maxheight)) || (bestEntry == -1))
664         {
665             bestEntry = i;
666             maxwidth  = cx;
667             maxheight = cy;
668         }
669     }
670
671     return bestEntry;
672 }
673
674 static BOOL CURSORICON_GetResCursorEntry( LPVOID dir, int n,
675                                           int *width, int *height, int *bits )
676 {
677     CURSORICONDIR *resdir = dir;
678     CURSORDIR *cursor;
679
680     if ( resdir->idCount <= n )
681         return FALSE;
682     cursor = &resdir->idEntries[n].ResInfo.cursor;
683     *width = cursor->wWidth;
684     *height = cursor->wHeight;
685     *bits = resdir->idEntries[n].wBitCount;
686     return TRUE;
687 }
688
689 static CURSORICONDIRENTRY *CURSORICON_FindBestIconRes( CURSORICONDIR * dir,
690                                       int width, int height, int depth )
691 {
692     int n;
693
694     n = CURSORICON_FindBestIcon( dir, CURSORICON_GetResIconEntry,
695                                  width, height, depth );
696     if ( n < 0 )
697         return NULL;
698     return &dir->idEntries[n];
699 }
700
701 static CURSORICONDIRENTRY *CURSORICON_FindBestCursorRes( CURSORICONDIR *dir,
702                                       int width, int height, int depth )
703 {
704     int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetResCursorEntry,
705                                    width, height, depth );
706     if ( n < 0 )
707         return NULL;
708     return &dir->idEntries[n];
709 }
710
711 static BOOL CURSORICON_GetFileEntry( LPVOID dir, int n,
712                                      int *width, int *height, int *bits )
713 {
714     CURSORICONFILEDIR *filedir = dir;
715     CURSORICONFILEDIRENTRY *entry;
716     BITMAPINFOHEADER *info;
717
718     if ( filedir->idCount <= n )
719         return FALSE;
720     entry = &filedir->idEntries[n];
721     /* FIXME: check against file size */
722     info = (BITMAPINFOHEADER *)((char *)dir + entry->dwDIBOffset);
723     *width = entry->bWidth;
724     *height = entry->bHeight;
725     *bits = info->biBitCount;
726     return TRUE;
727 }
728
729 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( CURSORICONFILEDIR *dir,
730                                       int width, int height, int depth )
731 {
732     int n = CURSORICON_FindBestCursor( dir, CURSORICON_GetFileEntry,
733                                        width, height, depth );
734     if ( n < 0 )
735         return NULL;
736     return &dir->idEntries[n];
737 }
738
739 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( CURSORICONFILEDIR *dir,
740                                       int width, int height, int depth )
741 {
742     int n = CURSORICON_FindBestIcon( dir, CURSORICON_GetFileEntry,
743                                      width, height, depth );
744     if ( n < 0 )
745         return NULL;
746     return &dir->idEntries[n];
747 }
748
749 /***********************************************************************
750  *          stretch_blt_icon
751  *
752  * A helper function that stretches a bitmap buffer into an HBITMAP.
753  *
754  * PARAMS
755  *      hDest       [I] The handle of the destination bitmap.
756  *      pDestInfo   [I] The BITMAPINFO of the destination bitmap.
757  *      pSrcInfo    [I] The BITMAPINFO of the source bitmap.
758  *      pSrcBits    [I] A pointer to the source bitmap buffer.
759  **/
760 static BOOL stretch_blt_icon(HBITMAP hDest, BITMAPINFO *pDestInfo, BITMAPINFO *pSrcInfo, char *pSrcBits)
761 {
762     HBITMAP hOld;
763     BOOL res = FALSE;
764     HDC hdcMem = CreateCompatibleDC(screen_dc);
765
766     if (hdcMem)
767     {
768         hOld = SelectObject(hdcMem, hDest);
769         res = StretchDIBits(hdcMem,
770                             0, 0, pDestInfo->bmiHeader.biWidth, pDestInfo->bmiHeader.biHeight,
771                             0, 0, pSrcInfo->bmiHeader.biWidth, pSrcInfo->bmiHeader.biHeight,
772                             pSrcBits, pSrcInfo, DIB_RGB_COLORS, SRCCOPY);
773         SelectObject(hdcMem, hOld);
774         DeleteDC( hdcMem );
775     }
776
777     return res;
778 }
779
780 /***********************************************************************
781  *          bmi_has_alpha
782  */
783 static BOOL bmi_has_alpha( const BITMAPINFO *info, const void *bits )
784 {
785     int i;
786     BOOL has_alpha = FALSE;
787     const unsigned char *ptr = bits;
788
789     if (info->bmiHeader.biBitCount != 32) return FALSE;
790     for (i = 0; i < info->bmiHeader.biWidth * abs(info->bmiHeader.biHeight); i++, ptr += 4)
791         if ((has_alpha = (ptr[3] != 0))) break;
792     return has_alpha;
793 }
794
795 /***********************************************************************
796  *          create_alpha_bitmap
797  *
798  * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
799  */
800 static HBITMAP create_alpha_bitmap( HBITMAP color, HBITMAP mask,
801                                     const BITMAPINFO *src_info, const void *color_bits )
802 {
803     HBITMAP alpha = 0;
804     BITMAPINFO *info = NULL;
805     BITMAP bm;
806     HDC hdc;
807     void *bits;
808     unsigned char *ptr;
809     int i;
810
811     if (!GetObjectW( color, sizeof(bm), &bm )) return 0;
812     if (bm.bmBitsPixel != 32) return 0;
813
814     if (!(hdc = CreateCompatibleDC( 0 ))) return 0;
815     if (!(info = HeapAlloc( GetProcessHeap(), 0, FIELD_OFFSET( BITMAPINFO, bmiColors[256] )))) goto done;
816     info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
817     info->bmiHeader.biWidth = bm.bmWidth;
818     info->bmiHeader.biHeight = -bm.bmHeight;
819     info->bmiHeader.biPlanes = 1;
820     info->bmiHeader.biBitCount = 32;
821     info->bmiHeader.biCompression = BI_RGB;
822     info->bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
823     info->bmiHeader.biXPelsPerMeter = 0;
824     info->bmiHeader.biYPelsPerMeter = 0;
825     info->bmiHeader.biClrUsed = 0;
826     info->bmiHeader.biClrImportant = 0;
827     if (!(alpha = CreateDIBSection( hdc, info, DIB_RGB_COLORS, &bits, NULL, 0 ))) goto done;
828
829     if (src_info)
830     {
831         SelectObject( hdc, alpha );
832         StretchDIBits( hdc, 0, 0, bm.bmWidth, bm.bmHeight,
833                        0, 0, src_info->bmiHeader.biWidth, src_info->bmiHeader.biHeight,
834                        color_bits, src_info, DIB_RGB_COLORS, SRCCOPY );
835
836     }
837     else
838     {
839         GetDIBits( hdc, color, 0, bm.bmHeight, bits, info, DIB_RGB_COLORS );
840         if (!bmi_has_alpha( info, bits ))
841         {
842             DeleteObject( alpha );
843             alpha = 0;
844             goto done;
845         }
846     }
847
848     /* pre-multiply by alpha */
849     for (i = 0, ptr = bits; i < bm.bmWidth * bm.bmHeight; i++, ptr += 4)
850     {
851         unsigned int alpha = ptr[3];
852         ptr[0] = ptr[0] * alpha / 255;
853         ptr[1] = ptr[1] * alpha / 255;
854         ptr[2] = ptr[2] * alpha / 255;
855     }
856
857 done:
858     DeleteDC( hdc );
859     HeapFree( GetProcessHeap(), 0, info );
860     return alpha;
861 }
862
863
864 /***********************************************************************
865  *          create_icon_bitmaps
866  *
867  * Create the color, mask and alpha bitmaps from the DIB info.
868  */
869 static BOOL create_icon_bitmaps( const BITMAPINFO *bmi, int width, int height,
870                                  HBITMAP *color, HBITMAP *mask, HBITMAP *alpha )
871 {
872     BOOL monochrome = is_dib_monochrome( bmi );
873     unsigned int size = bitmap_info_size( bmi, DIB_RGB_COLORS );
874     BITMAPINFO *info;
875     void *color_bits, *mask_bits;
876     BOOL ret = FALSE;
877     HDC hdc = 0;
878
879     if (!(info = HeapAlloc( GetProcessHeap(), 0, max( size, FIELD_OFFSET( BITMAPINFO, bmiColors[2] )))))
880         return FALSE;
881     if (!(hdc = CreateCompatibleDC( 0 ))) goto done;
882
883     memcpy( info, bmi, size );
884     info->bmiHeader.biHeight /= 2;
885
886     color_bits = (char *)bmi + size;
887     mask_bits = (char *)color_bits +
888         get_dib_width_bytes( bmi->bmiHeader.biWidth,
889                              bmi->bmiHeader.biBitCount ) * abs(info->bmiHeader.biHeight);
890
891     *alpha = 0;
892     if (monochrome)
893     {
894         if (!(*mask = CreateBitmap( width, height * 2, 1, 1, NULL ))) goto done;
895         *color = 0;
896
897         /* copy color data into second half of mask bitmap */
898         SelectObject( hdc, *mask );
899         StretchDIBits( hdc, 0, height, width, height,
900                        0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
901                        color_bits, info, DIB_RGB_COLORS, SRCCOPY );
902     }
903     else
904     {
905         if (!(*mask = CreateBitmap( width, height, 1, 1, NULL ))) goto done;
906         if (!(*color = CreateBitmap( width, height, GetDeviceCaps( screen_dc, PLANES ),
907                                      GetDeviceCaps( screen_dc, BITSPIXEL ), NULL )))
908         {
909             DeleteObject( *mask );
910             goto done;
911         }
912         SelectObject( hdc, *color );
913         StretchDIBits( hdc, 0, 0, width, height,
914                        0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
915                        color_bits, info, DIB_RGB_COLORS, SRCCOPY );
916
917         if (bmi_has_alpha( info, color_bits ))
918             *alpha = create_alpha_bitmap( *color, *mask, info, color_bits );
919
920         /* convert info to monochrome to copy the mask */
921         info->bmiHeader.biBitCount = 1;
922         if (info->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
923         {
924             RGBQUAD *rgb = info->bmiColors;
925
926             info->bmiHeader.biClrUsed = info->bmiHeader.biClrImportant = 2;
927             rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
928             rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
929             rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
930         }
931         else
932         {
933             RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)info) + 1);
934
935             rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
936             rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
937         }
938     }
939
940     SelectObject( hdc, *mask );
941     StretchDIBits( hdc, 0, 0, width, height,
942                    0, 0, info->bmiHeader.biWidth, info->bmiHeader.biHeight,
943                    mask_bits, info, DIB_RGB_COLORS, SRCCOPY );
944     ret = TRUE;
945
946 done:
947     DeleteDC( hdc );
948     HeapFree( GetProcessHeap(), 0, info );
949     return ret;
950 }
951
952 static HICON CURSORICON_CreateIconFromBMI( BITMAPINFO *bmi,
953                                            POINT16 hotspot, BOOL bIcon,
954                                            DWORD dwVersion,
955                                            INT width, INT height,
956                                            UINT cFlag )
957 {
958     HICON hObj;
959     int sizeAnd, sizeXor;
960     HBITMAP color = 0, mask = 0, alpha = 0, hAndBits = 0, hXorBits = 0; /* error condition for later */
961     BITMAP bmpXor, bmpAnd;
962     BOOL do_stretch;
963     INT size;
964     BITMAPINFO *pSrcInfo, *pDestInfo;
965
966     if (dwVersion == 0x00020000)
967     {
968         FIXME_(cursor)("\t2.xx resources are not supported\n");
969         return 0;
970     }
971
972     /* Check bitmap header */
973
974     if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
975          (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER)  ||
976           bmi->bmiHeader.biCompression != BI_RGB) )
977     {
978           WARN_(cursor)("\tinvalid resource bitmap header.\n");
979           return 0;
980     }
981
982     size = bitmap_info_size( bmi, DIB_RGB_COLORS );
983
984     if (!width) width = bmi->bmiHeader.biWidth;
985     if (!height) height = bmi->bmiHeader.biHeight/2;
986     do_stretch = (bmi->bmiHeader.biHeight/2 != height) ||
987                  (bmi->bmiHeader.biWidth != width);
988
989     /* Scale the hotspot */
990     if (do_stretch && hotspot.x != ICON_HOTSPOT && hotspot.y != ICON_HOTSPOT)
991     {
992         hotspot.x = (hotspot.x * width) / bmi->bmiHeader.biWidth;
993         hotspot.y = (hotspot.y * height) / (bmi->bmiHeader.biHeight / 2);
994     }
995
996     if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
997     if (!screen_dc) return 0;
998
999     if (create_icon_bitmaps( bmi, width, height, &color, &mask, &alpha ))
1000     {
1001         /* Make sure we have room for the monochrome bitmap later on.
1002          * Note that BITMAPINFOINFO and BITMAPCOREHEADER are the same
1003          * up to and including the biBitCount. In-memory icon resource
1004          * format is as follows:
1005          *
1006          *   BITMAPINFOHEADER   icHeader  // DIB header
1007          *   RGBQUAD         icColors[]   // Color table
1008          *   BYTE            icXOR[]      // DIB bits for XOR mask
1009          *   BYTE            icAND[]      // DIB bits for AND mask
1010          */
1011
1012         pSrcInfo = HeapAlloc( GetProcessHeap(), 0,
1013                               max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)));
1014         pDestInfo = HeapAlloc( GetProcessHeap(), 0,
1015                               max(size, sizeof(BITMAPINFOHEADER) + 2*sizeof(RGBQUAD)));
1016         if (pSrcInfo && pDestInfo)
1017         {
1018             memcpy( pSrcInfo, bmi, size );
1019             pSrcInfo->bmiHeader.biHeight /= 2;
1020
1021             memcpy( pDestInfo, bmi, size );
1022             pDestInfo->bmiHeader.biWidth = width;
1023             pDestInfo->bmiHeader.biHeight = height;
1024             pDestInfo->bmiHeader.biSizeImage = 0;
1025
1026             /* Create the XOR bitmap */
1027             if(pSrcInfo->bmiHeader.biBitCount == 32)
1028             {
1029                 void *pDIBBuffer = NULL;
1030                 hXorBits = CreateDIBSection(screen_dc, pDestInfo, DIB_RGB_COLORS, &pDIBBuffer, NULL, 0);
1031
1032                 if(hXorBits)
1033                 {
1034                     if (!stretch_blt_icon(hXorBits, pDestInfo, pSrcInfo, (char*)bmi + size))
1035                     {
1036                         DeleteObject(hXorBits);
1037                         hXorBits = 0;
1038                     }
1039                 }
1040             }
1041             else
1042             {
1043                 if (do_stretch)
1044                 {
1045                     hXorBits = CreateCompatibleBitmap(screen_dc, width, height);
1046                     if (hXorBits)
1047                     {
1048                         if (!stretch_blt_icon(hXorBits, pDestInfo, pSrcInfo, (char*)bmi + size))
1049                         {
1050                             DeleteObject(hXorBits);
1051                             hXorBits = 0;
1052                         }
1053                     }
1054                 }
1055                 else
1056                 {
1057                     if (is_dib_monochrome(bmi))
1058                     {
1059                         hXorBits = CreateBitmap(width, height, 1, 1, NULL);
1060                         SetDIBits(screen_dc, hXorBits, 0, height,
1061                                   (char *)bmi + size, pSrcInfo, DIB_RGB_COLORS);
1062                     }
1063                     else
1064                         hXorBits = CreateDIBitmap(screen_dc, &pSrcInfo->bmiHeader,
1065                                         CBM_INIT, (char *)bmi + size, pSrcInfo, DIB_RGB_COLORS);
1066                 }
1067             }
1068
1069             if( hXorBits )
1070             {
1071                 char* xbits = (char *)bmi + size +
1072                     get_dib_width_bytes( bmi->bmiHeader.biWidth,
1073                                          bmi->bmiHeader.biBitCount ) * abs( bmi->bmiHeader.biHeight ) / 2;
1074
1075                 pSrcInfo->bmiHeader.biBitCount = 1;
1076                 if (pSrcInfo->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
1077                 {
1078                     RGBQUAD *rgb = pSrcInfo->bmiColors;
1079
1080                     pSrcInfo->bmiHeader.biClrUsed = pSrcInfo->bmiHeader.biClrImportant = 2;
1081                     rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
1082                     rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
1083                     rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
1084                 }
1085                 else
1086                 {
1087                     RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)pSrcInfo) + 1);
1088
1089                     rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
1090                     rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
1091                 }
1092
1093                 /* Create the AND bitmap */
1094                 if (do_stretch)
1095                 {
1096                     hAndBits = CreateBitmap(width, height, 1, 1, NULL);
1097
1098                     if (!stretch_blt_icon(hAndBits, pDestInfo, pSrcInfo, xbits))
1099                     {
1100                         DeleteObject(hAndBits);
1101                         hAndBits = 0;
1102                     }
1103                 }
1104                 else
1105                 {
1106                     hAndBits = CreateBitmap(width, height, 1, 1, NULL);
1107                     SetDIBits(screen_dc, hAndBits, 0, height,
1108                               xbits, pSrcInfo, DIB_RGB_COLORS);
1109                 }
1110
1111                 if( !hAndBits )
1112                 {
1113                     DeleteObject( hXorBits );
1114                     hXorBits = 0;
1115                 }
1116             }
1117         }
1118
1119         HeapFree( GetProcessHeap(), 0, pSrcInfo );
1120         HeapFree( GetProcessHeap(), 0, pDestInfo );
1121     }
1122
1123     if( !hXorBits || !hAndBits )
1124     {
1125         WARN_(cursor)("\tunable to create an icon bitmap.\n");
1126         DeleteObject( color );
1127         DeleteObject( alpha );
1128         DeleteObject( mask );
1129         return 0;
1130     }
1131
1132     /* Now create the CURSORICONINFO structure */
1133     GetObjectA( hXorBits, sizeof(bmpXor), &bmpXor );
1134     GetObjectA( hAndBits, sizeof(bmpAnd), &bmpAnd );
1135     sizeXor = bmpXor.bmHeight * bmpXor.bmWidthBytes;
1136     sizeAnd = bmpAnd.bmHeight * bmpAnd.bmWidthBytes;
1137
1138     hObj = alloc_icon_handle( sizeXor + sizeAnd );
1139     if (hObj)
1140     {
1141         struct cursoricon_object *info = get_icon_ptr( hObj );
1142
1143         info->color = color;
1144         info->mask  = mask;
1145         info->alpha = alpha;
1146         info->data.ptHotSpot.x   = hotspot.x;
1147         info->data.ptHotSpot.y   = hotspot.y;
1148         info->data.nWidth        = bmpXor.bmWidth;
1149         info->data.nHeight       = bmpXor.bmHeight;
1150         info->data.nWidthBytes   = bmpXor.bmWidthBytes;
1151         info->data.bPlanes       = bmpXor.bmPlanes;
1152         info->data.bBitsPerPixel = bmpXor.bmBitsPixel;
1153
1154         /* Transfer the bitmap bits to the CURSORICONINFO structure */
1155
1156         GetBitmapBits( hAndBits, sizeAnd, info + 1 );
1157         GetBitmapBits( hXorBits, sizeXor, (char *)(info + 1) + sizeAnd );
1158         release_icon_ptr( hObj, info );
1159         USER_Driver->pCreateCursorIcon( hObj, &info->data );
1160     }
1161     else
1162     {
1163         DeleteObject( color );
1164         DeleteObject( alpha );
1165         DeleteObject( mask );
1166     }
1167
1168     DeleteObject( hAndBits );
1169     DeleteObject( hXorBits );
1170     return hObj;
1171 }
1172
1173
1174 /**********************************************************************
1175  *          .ANI cursor support
1176  */
1177 #define RIFF_FOURCC( c0, c1, c2, c3 ) \
1178         ( (DWORD)(BYTE)(c0) | ( (DWORD)(BYTE)(c1) << 8 ) | \
1179         ( (DWORD)(BYTE)(c2) << 16 ) | ( (DWORD)(BYTE)(c3) << 24 ) )
1180
1181 #define ANI_RIFF_ID RIFF_FOURCC('R', 'I', 'F', 'F')
1182 #define ANI_LIST_ID RIFF_FOURCC('L', 'I', 'S', 'T')
1183 #define ANI_ACON_ID RIFF_FOURCC('A', 'C', 'O', 'N')
1184 #define ANI_anih_ID RIFF_FOURCC('a', 'n', 'i', 'h')
1185 #define ANI_seq__ID RIFF_FOURCC('s', 'e', 'q', ' ')
1186 #define ANI_fram_ID RIFF_FOURCC('f', 'r', 'a', 'm')
1187
1188 #define ANI_FLAG_ICON       0x1
1189 #define ANI_FLAG_SEQUENCE   0x2
1190
1191 typedef struct {
1192     DWORD header_size;
1193     DWORD num_frames;
1194     DWORD num_steps;
1195     DWORD width;
1196     DWORD height;
1197     DWORD bpp;
1198     DWORD num_planes;
1199     DWORD display_rate;
1200     DWORD flags;
1201 } ani_header;
1202
1203 typedef struct {
1204     DWORD           data_size;
1205     const unsigned char   *data;
1206 } riff_chunk_t;
1207
1208 static void dump_ani_header( const ani_header *header )
1209 {
1210     TRACE("     header size: %d\n", header->header_size);
1211     TRACE("          frames: %d\n", header->num_frames);
1212     TRACE("           steps: %d\n", header->num_steps);
1213     TRACE("           width: %d\n", header->width);
1214     TRACE("          height: %d\n", header->height);
1215     TRACE("             bpp: %d\n", header->bpp);
1216     TRACE("          planes: %d\n", header->num_planes);
1217     TRACE("    display rate: %d\n", header->display_rate);
1218     TRACE("           flags: 0x%08x\n", header->flags);
1219 }
1220
1221
1222 /*
1223  * RIFF:
1224  * DWORD "RIFF"
1225  * DWORD size
1226  * DWORD riff_id
1227  * BYTE[] data
1228  *
1229  * LIST:
1230  * DWORD "LIST"
1231  * DWORD size
1232  * DWORD list_id
1233  * BYTE[] data
1234  *
1235  * CHUNK:
1236  * DWORD chunk_id
1237  * DWORD size
1238  * BYTE[] data
1239  */
1240 static void riff_find_chunk( DWORD chunk_id, DWORD chunk_type, const riff_chunk_t *parent_chunk, riff_chunk_t *chunk )
1241 {
1242     const unsigned char *ptr = parent_chunk->data;
1243     const unsigned char *end = parent_chunk->data + (parent_chunk->data_size - (2 * sizeof(DWORD)));
1244
1245     if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) end -= sizeof(DWORD);
1246
1247     while (ptr < end)
1248     {
1249         if ((!chunk_type && *(const DWORD *)ptr == chunk_id )
1250                 || (chunk_type && *(const DWORD *)ptr == chunk_type && *((const DWORD *)ptr + 2) == chunk_id ))
1251         {
1252             ptr += sizeof(DWORD);
1253             chunk->data_size = (*(const DWORD *)ptr + 1) & ~1;
1254             ptr += sizeof(DWORD);
1255             if (chunk_type == ANI_LIST_ID || chunk_type == ANI_RIFF_ID) ptr += sizeof(DWORD);
1256             chunk->data = ptr;
1257
1258             return;
1259         }
1260
1261         ptr += sizeof(DWORD);
1262         ptr += (*(const DWORD *)ptr + 1) & ~1;
1263         ptr += sizeof(DWORD);
1264     }
1265 }
1266
1267
1268 /*
1269  * .ANI layout:
1270  *
1271  * RIFF:'ACON'                  RIFF chunk
1272  *     |- CHUNK:'anih'          Header
1273  *     |- CHUNK:'seq '          Sequence information (optional)
1274  *     \- LIST:'fram'           Frame list
1275  *            |- CHUNK:icon     Cursor frames
1276  *            |- CHUNK:icon
1277  *            |- ...
1278  *            \- CHUNK:icon
1279  */
1280 static HCURSOR CURSORICON_CreateIconFromANI( const LPBYTE bits, DWORD bits_size,
1281     INT width, INT height, INT depth )
1282 {
1283     HCURSOR cursor;
1284     ani_header header = {0};
1285     LPBYTE frame_bits = 0;
1286     POINT16 hotspot;
1287     CURSORICONFILEDIRENTRY *entry;
1288
1289     riff_chunk_t root_chunk = { bits_size, bits };
1290     riff_chunk_t ACON_chunk = {0};
1291     riff_chunk_t anih_chunk = {0};
1292     riff_chunk_t fram_chunk = {0};
1293     const unsigned char *icon_data;
1294
1295     TRACE("bits %p, bits_size %d\n", bits, bits_size);
1296
1297     if (!bits) return 0;
1298
1299     riff_find_chunk( ANI_ACON_ID, ANI_RIFF_ID, &root_chunk, &ACON_chunk );
1300     if (!ACON_chunk.data)
1301     {
1302         ERR("Failed to get root chunk.\n");
1303         return 0;
1304     }
1305
1306     riff_find_chunk( ANI_anih_ID, 0, &ACON_chunk, &anih_chunk );
1307     if (!anih_chunk.data)
1308     {
1309         ERR("Failed to get 'anih' chunk.\n");
1310         return 0;
1311     }
1312     memcpy( &header, anih_chunk.data, sizeof(header) );
1313     dump_ani_header( &header );
1314
1315     riff_find_chunk( ANI_fram_ID, ANI_LIST_ID, &ACON_chunk, &fram_chunk );
1316     if (!fram_chunk.data)
1317     {
1318         ERR("Failed to get icon list.\n");
1319         return 0;
1320     }
1321
1322     /* FIXME: For now, just load the first frame.  Before we can load all the
1323      * frames, we need to write the needed code in wineserver, etc. to handle
1324      * cursors.  Once this code is written, we can extend it to support .ani
1325      * cursors and then update user32 and winex11.drv to load all frames.
1326      *
1327      * Hopefully this will at least make some games (C&C3, etc.) more playable
1328      * in the meantime.
1329      */
1330     FIXME("Loading all frames for .ani cursors not implemented.\n");
1331     icon_data = fram_chunk.data + (2 * sizeof(DWORD));
1332
1333     entry = CURSORICON_FindBestIconFile( (CURSORICONFILEDIR *) icon_data,
1334         width, height, depth );
1335
1336     frame_bits = HeapAlloc( GetProcessHeap(), 0, entry->dwDIBSize );
1337     memcpy( frame_bits, icon_data + entry->dwDIBOffset, entry->dwDIBSize );
1338
1339     if (!header.width || !header.height)
1340     {
1341         header.width = entry->bWidth;
1342         header.height = entry->bHeight;
1343     }
1344
1345     hotspot.x = entry->xHotspot;
1346     hotspot.y = entry->yHotspot;
1347
1348     cursor = CURSORICON_CreateIconFromBMI( (BITMAPINFO *) frame_bits, hotspot,
1349         FALSE, 0x00030000, header.width, header.height, 0 );
1350
1351     HeapFree( GetProcessHeap(), 0, frame_bits );
1352
1353     return cursor;
1354 }
1355
1356
1357 /**********************************************************************
1358  *              CreateIconFromResourceEx (USER32.@)
1359  *
1360  * FIXME: Convert to mono when cFlag is LR_MONOCHROME. Do something
1361  *        with cbSize parameter as well.
1362  */
1363 HICON WINAPI CreateIconFromResourceEx( LPBYTE bits, UINT cbSize,
1364                                        BOOL bIcon, DWORD dwVersion,
1365                                        INT width, INT height,
1366                                        UINT cFlag )
1367 {
1368     POINT16 hotspot;
1369     BITMAPINFO *bmi;
1370
1371     hotspot.x = ICON_HOTSPOT;
1372     hotspot.y = ICON_HOTSPOT;
1373
1374     TRACE_(cursor)("%p (%u bytes), ver %08x, %ix%i %s %s\n",
1375                    bits, cbSize, dwVersion, width, height,
1376                                   bIcon ? "icon" : "cursor", (cFlag & LR_MONOCHROME) ? "mono" : "" );
1377
1378     if (bIcon)
1379         bmi = (BITMAPINFO *)bits;
1380     else /* get the hotspot */
1381     {
1382         POINT16 *pt = (POINT16 *)bits;
1383         hotspot = *pt;
1384         bmi = (BITMAPINFO *)(pt + 1);
1385     }
1386
1387     return CURSORICON_CreateIconFromBMI( bmi, hotspot, bIcon, dwVersion,
1388                                          width, height, cFlag );
1389 }
1390
1391
1392 /**********************************************************************
1393  *              CreateIconFromResource (USER32.@)
1394  */
1395 HICON WINAPI CreateIconFromResource( LPBYTE bits, UINT cbSize,
1396                                            BOOL bIcon, DWORD dwVersion)
1397 {
1398     return CreateIconFromResourceEx( bits, cbSize, bIcon, dwVersion, 0,0,0);
1399 }
1400
1401
1402 static HICON CURSORICON_LoadFromFile( LPCWSTR filename,
1403                              INT width, INT height, INT depth,
1404                              BOOL fCursor, UINT loadflags)
1405 {
1406     CURSORICONFILEDIRENTRY *entry;
1407     CURSORICONFILEDIR *dir;
1408     DWORD filesize = 0;
1409     HICON hIcon = 0;
1410     LPBYTE bits;
1411     POINT16 hotspot;
1412
1413     TRACE("loading %s\n", debugstr_w( filename ));
1414
1415     bits = map_fileW( filename, &filesize );
1416     if (!bits)
1417         return hIcon;
1418
1419     /* Check for .ani. */
1420     if (memcmp( bits, "RIFF", 4 ) == 0)
1421     {
1422         hIcon = CURSORICON_CreateIconFromANI( bits, filesize, width, height,
1423             depth );
1424         goto end;
1425     }
1426
1427     dir = (CURSORICONFILEDIR*) bits;
1428     if ( filesize < sizeof(*dir) )
1429         goto end;
1430
1431     if ( filesize < (sizeof(*dir) + sizeof(dir->idEntries[0])*(dir->idCount-1)) )
1432         goto end;
1433
1434     if ( fCursor )
1435         entry = CURSORICON_FindBestCursorFile( dir, width, height, depth );
1436     else
1437         entry = CURSORICON_FindBestIconFile( dir, width, height, depth );
1438
1439     if ( !entry )
1440         goto end;
1441
1442     /* check that we don't run off the end of the file */
1443     if ( entry->dwDIBOffset > filesize )
1444         goto end;
1445     if ( entry->dwDIBOffset + entry->dwDIBSize > filesize )
1446         goto end;
1447
1448     /* Set the actual hotspot for cursors and ICON_HOTSPOT for icons. */
1449     if ( fCursor )
1450     {
1451         hotspot.x = entry->xHotspot;
1452         hotspot.y = entry->yHotspot;
1453     }
1454     else
1455     {
1456         hotspot.x = ICON_HOTSPOT;
1457         hotspot.y = ICON_HOTSPOT;
1458     }
1459     hIcon = CURSORICON_CreateIconFromBMI( (BITMAPINFO *)&bits[entry->dwDIBOffset],
1460                                           hotspot, !fCursor, 0x00030000,
1461                                           width, height, loadflags );
1462 end:
1463     TRACE("loaded %s -> %p\n", debugstr_w( filename ), hIcon );
1464     UnmapViewOfFile( bits );
1465     return hIcon;
1466 }
1467
1468 /**********************************************************************
1469  *          CURSORICON_Load
1470  *
1471  * Load a cursor or icon from resource or file.
1472  */
1473 static HICON CURSORICON_Load(HINSTANCE hInstance, LPCWSTR name,
1474                              INT width, INT height, INT depth,
1475                              BOOL fCursor, UINT loadflags)
1476 {
1477     HANDLE handle = 0;
1478     HICON hIcon = 0;
1479     HRSRC hRsrc, hGroupRsrc;
1480     CURSORICONDIR *dir;
1481     CURSORICONDIRENTRY *dirEntry;
1482     LPBYTE bits;
1483     WORD wResId;
1484     DWORD dwBytesInRes;
1485
1486     TRACE("%p, %s, %dx%d, depth %d, fCursor %d, flags 0x%04x\n",
1487           hInstance, debugstr_w(name), width, height, depth, fCursor, loadflags);
1488
1489     if ( loadflags & LR_LOADFROMFILE )    /* Load from file */
1490         return CURSORICON_LoadFromFile( name, width, height, depth, fCursor, loadflags );
1491
1492     if (!hInstance) hInstance = user32_module;  /* Load OEM cursor/icon */
1493
1494     /* don't cache 16-bit instances (FIXME: should never get 16-bit instances in the first place) */
1495     if ((ULONG_PTR)hInstance >> 16 == 0) loadflags &= ~LR_SHARED;
1496
1497     /* Get directory resource ID */
1498
1499     if (!(hRsrc = FindResourceW( hInstance, name,
1500                                  (LPWSTR)(fCursor ? RT_GROUP_CURSOR : RT_GROUP_ICON) )))
1501         return 0;
1502     hGroupRsrc = hRsrc;
1503
1504     /* Find the best entry in the directory */
1505
1506     if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
1507     if (!(dir = LockResource( handle ))) return 0;
1508     if (fCursor)
1509         dirEntry = CURSORICON_FindBestCursorRes( dir, width, height, depth );
1510     else
1511         dirEntry = CURSORICON_FindBestIconRes( dir, width, height, depth );
1512     if (!dirEntry) return 0;
1513     wResId = dirEntry->wResId;
1514     dwBytesInRes = dirEntry->dwBytesInRes;
1515     FreeResource( handle );
1516
1517     /* Load the resource */
1518
1519     if (!(hRsrc = FindResourceW(hInstance,MAKEINTRESOURCEW(wResId),
1520                                 (LPWSTR)(fCursor ? RT_CURSOR : RT_ICON) ))) return 0;
1521
1522     /* If shared icon, check whether it was already loaded */
1523     if (    (loadflags & LR_SHARED)
1524          && (hIcon = CURSORICON_FindSharedIcon( hInstance, hRsrc ) ) != 0 )
1525         return hIcon;
1526
1527     if (!(handle = LoadResource( hInstance, hRsrc ))) return 0;
1528     bits = LockResource( handle );
1529     hIcon = CreateIconFromResourceEx( bits, dwBytesInRes,
1530                                       !fCursor, 0x00030000, width, height, loadflags);
1531     FreeResource( handle );
1532
1533     /* If shared icon, add to icon cache */
1534
1535     if ( hIcon && (loadflags & LR_SHARED) )
1536         CURSORICON_AddSharedIcon( hInstance, hRsrc, hGroupRsrc, hIcon );
1537
1538     return hIcon;
1539 }
1540
1541
1542 /*************************************************************************
1543  * CURSORICON_ExtCopy
1544  *
1545  * Copies an Image from the Cache if LR_COPYFROMRESOURCE is specified
1546  *
1547  * PARAMS
1548  *      Handle     [I] handle to an Image
1549  *      nType      [I] Type of Handle (IMAGE_CURSOR | IMAGE_ICON)
1550  *      iDesiredCX [I] The Desired width of the Image
1551  *      iDesiredCY [I] The desired height of the Image
1552  *      nFlags     [I] The flags from CopyImage
1553  *
1554  * RETURNS
1555  *     Success: The new handle of the Image
1556  *
1557  * NOTES
1558  *     LR_COPYDELETEORG and LR_MONOCHROME are currently not implemented.
1559  *     LR_MONOCHROME should be implemented by CreateIconFromResourceEx.
1560  *     LR_COPYFROMRESOURCE will only work if the Image is in the Cache.
1561  *
1562  *
1563  */
1564
1565 static HICON CURSORICON_ExtCopy(HICON hIcon, UINT nType,
1566                                 INT iDesiredCX, INT iDesiredCY,
1567                                 UINT nFlags)
1568 {
1569     HICON hNew=0;
1570
1571     TRACE_(icon)("hIcon %p, nType %u, iDesiredCX %i, iDesiredCY %i, nFlags %u\n",
1572                  hIcon, nType, iDesiredCX, iDesiredCY, nFlags);
1573
1574     if(hIcon == 0)
1575     {
1576         return 0;
1577     }
1578
1579     /* Best Fit or Monochrome */
1580     if( (nFlags & LR_COPYFROMRESOURCE
1581         && (iDesiredCX > 0 || iDesiredCY > 0))
1582         || nFlags & LR_MONOCHROME)
1583     {
1584         ICONCACHE* pIconCache = CURSORICON_FindCache(hIcon);
1585
1586         /* Not Found in Cache, then do a straight copy
1587         */
1588         if(pIconCache == NULL)
1589         {
1590             hNew = CopyIcon( hIcon );
1591             if(nFlags & LR_COPYFROMRESOURCE)
1592             {
1593                 TRACE_(icon)("LR_COPYFROMRESOURCE: Failed to load from cache\n");
1594             }
1595         }
1596         else
1597         {
1598             int iTargetCY = iDesiredCY, iTargetCX = iDesiredCX;
1599             LPBYTE pBits;
1600             HANDLE hMem;
1601             HRSRC hRsrc;
1602             DWORD dwBytesInRes;
1603             WORD wResId;
1604             CURSORICONDIR *pDir;
1605             CURSORICONDIRENTRY *pDirEntry;
1606             BOOL bIsIcon = (nType == IMAGE_ICON);
1607
1608             /* Completing iDesiredCX CY for Monochrome Bitmaps if needed
1609             */
1610             if(((nFlags & LR_MONOCHROME) && !(nFlags & LR_COPYFROMRESOURCE))
1611                 || (iDesiredCX == 0 && iDesiredCY == 0))
1612             {
1613                 iDesiredCY = GetSystemMetrics(bIsIcon ?
1614                     SM_CYICON : SM_CYCURSOR);
1615                 iDesiredCX = GetSystemMetrics(bIsIcon ?
1616                     SM_CXICON : SM_CXCURSOR);
1617             }
1618
1619             /* Retrieve the CURSORICONDIRENTRY
1620             */
1621             if (!(hMem = LoadResource( pIconCache->hModule ,
1622                             pIconCache->hGroupRsrc)))
1623             {
1624                 return 0;
1625             }
1626             if (!(pDir = LockResource( hMem )))
1627             {
1628                 return 0;
1629             }
1630
1631             /* Find Best Fit
1632             */
1633             if(bIsIcon)
1634             {
1635                 pDirEntry = CURSORICON_FindBestIconRes(
1636                                 pDir, iDesiredCX, iDesiredCY, 256 );
1637             }
1638             else
1639             {
1640                 pDirEntry = CURSORICON_FindBestCursorRes(
1641                                 pDir, iDesiredCX, iDesiredCY, 1);
1642             }
1643
1644             wResId = pDirEntry->wResId;
1645             dwBytesInRes = pDirEntry->dwBytesInRes;
1646             FreeResource(hMem);
1647
1648             TRACE_(icon)("ResID %u, BytesInRes %u, Width %d, Height %d DX %d, DY %d\n",
1649                 wResId, dwBytesInRes,  pDirEntry->ResInfo.icon.bWidth,
1650                 pDirEntry->ResInfo.icon.bHeight, iDesiredCX, iDesiredCY);
1651
1652             /* Get the Best Fit
1653             */
1654             if (!(hRsrc = FindResourceW(pIconCache->hModule ,
1655                 MAKEINTRESOURCEW(wResId), (LPWSTR)(bIsIcon ? RT_ICON : RT_CURSOR))))
1656             {
1657                 return 0;
1658             }
1659             if (!(hMem = LoadResource( pIconCache->hModule , hRsrc )))
1660             {
1661                 return 0;
1662             }
1663
1664             pBits = LockResource( hMem );
1665
1666             if(nFlags & LR_DEFAULTSIZE)
1667             {
1668                 iTargetCY = GetSystemMetrics(SM_CYICON);
1669                 iTargetCX = GetSystemMetrics(SM_CXICON);
1670             }
1671
1672             /* Create a New Icon with the proper dimension
1673             */
1674             hNew = CreateIconFromResourceEx( pBits, dwBytesInRes,
1675                        bIsIcon, 0x00030000, iTargetCX, iTargetCY, nFlags);
1676             FreeResource(hMem);
1677         }
1678     }
1679     else hNew = CopyIcon( hIcon );
1680     return hNew;
1681 }
1682
1683
1684 /***********************************************************************
1685  *              CreateCursor (USER32.@)
1686  */
1687 HCURSOR WINAPI CreateCursor( HINSTANCE hInstance,
1688                                  INT xHotSpot, INT yHotSpot,
1689                                  INT nWidth, INT nHeight,
1690                                  LPCVOID lpANDbits, LPCVOID lpXORbits )
1691 {
1692     ICONINFO info;
1693     HCURSOR hCursor;
1694
1695     TRACE_(cursor)("%dx%d spot=%d,%d xor=%p and=%p\n",
1696                     nWidth, nHeight, xHotSpot, yHotSpot, lpXORbits, lpANDbits);
1697
1698     info.fIcon = FALSE;
1699     info.xHotspot = xHotSpot;
1700     info.yHotspot = yHotSpot;
1701     info.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1702     info.hbmColor = CreateBitmap( nWidth, nHeight, 1, 1, lpXORbits );
1703     hCursor = CreateIconIndirect( &info );
1704     DeleteObject( info.hbmMask );
1705     DeleteObject( info.hbmColor );
1706     return hCursor;
1707 }
1708
1709
1710 /***********************************************************************
1711  *              CreateIcon (USER32.@)
1712  *
1713  *  Creates an icon based on the specified bitmaps. The bitmaps must be
1714  *  provided in a device dependent format and will be resized to
1715  *  (SM_CXICON,SM_CYICON) and depth converted to match the screen's color
1716  *  depth. The provided bitmaps must be top-down bitmaps.
1717  *  Although Windows does not support 15bpp(*) this API must support it
1718  *  for Winelib applications.
1719  *
1720  *  (*) Windows does not support 15bpp but it supports the 555 RGB 16bpp
1721  *      format!
1722  *
1723  * RETURNS
1724  *  Success: handle to an icon
1725  *  Failure: NULL
1726  *
1727  * FIXME: Do we need to resize the bitmaps?
1728  */
1729 HICON WINAPI CreateIcon(
1730     HINSTANCE hInstance,  /* [in] the application's hInstance */
1731     INT       nWidth,     /* [in] the width of the provided bitmaps */
1732     INT       nHeight,    /* [in] the height of the provided bitmaps */
1733     BYTE      bPlanes,    /* [in] the number of planes in the provided bitmaps */
1734     BYTE      bBitsPixel, /* [in] the number of bits per pixel of the lpXORbits bitmap */
1735     LPCVOID   lpANDbits,  /* [in] a monochrome bitmap representing the icon's mask */
1736     LPCVOID   lpXORbits)  /* [in] the icon's 'color' bitmap */
1737 {
1738     ICONINFO iinfo;
1739     HICON hIcon;
1740
1741     TRACE_(icon)("%dx%d, planes %d, bpp %d, xor %p, and %p\n",
1742                  nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits, lpANDbits);
1743
1744     iinfo.fIcon = TRUE;
1745     iinfo.xHotspot = ICON_HOTSPOT;
1746     iinfo.yHotspot = ICON_HOTSPOT;
1747     iinfo.hbmMask = CreateBitmap( nWidth, nHeight, 1, 1, lpANDbits );
1748     iinfo.hbmColor = CreateBitmap( nWidth, nHeight, bPlanes, bBitsPixel, lpXORbits );
1749
1750     hIcon = CreateIconIndirect( &iinfo );
1751
1752     DeleteObject( iinfo.hbmMask );
1753     DeleteObject( iinfo.hbmColor );
1754
1755     return hIcon;
1756 }
1757
1758
1759 /***********************************************************************
1760  *              CopyIcon (USER32.@)
1761  */
1762 HICON WINAPI CopyIcon( HICON hIcon )
1763 {
1764     struct cursoricon_object *ptrOld, *ptrNew;
1765     int size;
1766     HICON hNew;
1767
1768     if (!(ptrOld = get_icon_ptr( hIcon ))) return 0;
1769     size = ptrOld->data.nHeight * get_bitmap_width_bytes( ptrOld->data.nWidth, 1 );  /* and bitmap */
1770     size += ptrOld->data.nHeight * ptrOld->data.nWidthBytes;  /* xor bitmap */
1771     hNew = alloc_icon_handle( size );
1772     ptrNew = get_icon_ptr( hNew );
1773     memcpy( &ptrNew->data, &ptrOld->data, sizeof(ptrNew->data) + size );
1774     ptrNew->color = copy_bitmap( ptrOld->color );
1775     ptrNew->alpha = copy_bitmap( ptrOld->alpha );
1776     ptrNew->mask  = copy_bitmap( ptrOld->mask );
1777     release_icon_ptr( hIcon, ptrOld );
1778     release_icon_ptr( hNew, ptrNew );
1779     USER_Driver->pCreateCursorIcon( hNew, &ptrNew->data );
1780     return hNew;
1781 }
1782
1783
1784 /***********************************************************************
1785  *              DestroyIcon (USER32.@)
1786  */
1787 BOOL WINAPI DestroyIcon( HICON hIcon )
1788 {
1789     TRACE_(icon)("%p\n", hIcon );
1790
1791     if (CURSORICON_DelSharedIcon( hIcon ) == -1)
1792         free_icon_handle( hIcon );
1793     return TRUE;
1794 }
1795
1796
1797 /***********************************************************************
1798  *              DestroyCursor (USER32.@)
1799  */
1800 BOOL WINAPI DestroyCursor( HCURSOR hCursor )
1801 {
1802     if (GetCursor() == hCursor)
1803     {
1804         WARN_(cursor)("Destroying active cursor!\n" );
1805         return FALSE;
1806     }
1807     return DestroyIcon( hCursor );
1808 }
1809
1810 /***********************************************************************
1811  *              DrawIcon (USER32.@)
1812  */
1813 BOOL WINAPI DrawIcon( HDC hdc, INT x, INT y, HICON hIcon )
1814 {
1815     return DrawIconEx( hdc, x, y, hIcon, 0, 0, 0, 0, DI_NORMAL | DI_COMPAT | DI_DEFAULTSIZE );
1816 }
1817
1818 /***********************************************************************
1819  *              SetCursor (USER32.@)
1820  *
1821  * Set the cursor shape.
1822  *
1823  * RETURNS
1824  *      A handle to the previous cursor shape.
1825  */
1826 HCURSOR WINAPI DECLSPEC_HOTPATCH SetCursor( HCURSOR hCursor /* [in] Handle of cursor to show */ )
1827 {
1828     HCURSOR hOldCursor;
1829     int show_count;
1830     BOOL ret;
1831
1832     TRACE("%p\n", hCursor);
1833
1834     SERVER_START_REQ( set_cursor )
1835     {
1836         req->flags = SET_CURSOR_HANDLE;
1837         req->handle = wine_server_user_handle( hCursor );
1838         if ((ret = !wine_server_call_err( req )))
1839         {
1840             hOldCursor = wine_server_ptr_handle( reply->prev_handle );
1841             show_count = reply->prev_count;
1842         }
1843     }
1844     SERVER_END_REQ;
1845
1846     if (!ret) return 0;
1847
1848     /* Change the cursor shape only if it is visible */
1849     if (show_count >= 0 && hOldCursor != hCursor) USER_Driver->pSetCursor( hCursor );
1850     return hOldCursor;
1851 }
1852
1853 /***********************************************************************
1854  *              ShowCursor (USER32.@)
1855  */
1856 INT WINAPI DECLSPEC_HOTPATCH ShowCursor( BOOL bShow )
1857 {
1858     HCURSOR cursor;
1859     int increment = bShow ? 1 : -1;
1860     int count;
1861
1862     SERVER_START_REQ( set_cursor )
1863     {
1864         req->flags = SET_CURSOR_COUNT;
1865         req->show_count = increment;
1866         wine_server_call( req );
1867         cursor = wine_server_ptr_handle( reply->prev_handle );
1868         count = reply->prev_count + increment;
1869     }
1870     SERVER_END_REQ;
1871
1872     TRACE("%d, count=%d\n", bShow, count );
1873
1874     if (bShow && !count) USER_Driver->pSetCursor( cursor );
1875     else if (!bShow && count == -1) USER_Driver->pSetCursor( 0 );
1876
1877     return count;
1878 }
1879
1880 /***********************************************************************
1881  *              GetCursor (USER32.@)
1882  */
1883 HCURSOR WINAPI GetCursor(void)
1884 {
1885     HCURSOR ret;
1886
1887     SERVER_START_REQ( set_cursor )
1888     {
1889         req->flags = 0;
1890         wine_server_call( req );
1891         ret = wine_server_ptr_handle( reply->prev_handle );
1892     }
1893     SERVER_END_REQ;
1894     return ret;
1895 }
1896
1897
1898 /***********************************************************************
1899  *              ClipCursor (USER32.@)
1900  */
1901 BOOL WINAPI DECLSPEC_HOTPATCH ClipCursor( const RECT *rect )
1902 {
1903     RECT virt;
1904
1905     SetRect( &virt, 0, 0, GetSystemMetrics( SM_CXVIRTUALSCREEN ),
1906                           GetSystemMetrics( SM_CYVIRTUALSCREEN ) );
1907     OffsetRect( &virt, GetSystemMetrics( SM_XVIRTUALSCREEN ),
1908                        GetSystemMetrics( SM_YVIRTUALSCREEN ) );
1909
1910     TRACE( "Clipping to: %s was: %s screen: %s\n", wine_dbgstr_rect(rect),
1911            wine_dbgstr_rect(&CURSOR_ClipRect), wine_dbgstr_rect(&virt) );
1912
1913     if (!IntersectRect( &CURSOR_ClipRect, &virt, rect ))
1914         CURSOR_ClipRect = virt;
1915
1916     USER_Driver->pClipCursor( rect );
1917     return TRUE;
1918 }
1919
1920
1921 /***********************************************************************
1922  *              GetClipCursor (USER32.@)
1923  */
1924 BOOL WINAPI DECLSPEC_HOTPATCH GetClipCursor( RECT *rect )
1925 {
1926     /* If this is first time - initialize the rect */
1927     if (IsRectEmpty( &CURSOR_ClipRect )) ClipCursor( NULL );
1928
1929     return CopyRect( rect, &CURSOR_ClipRect );
1930 }
1931
1932
1933 /***********************************************************************
1934  *              SetSystemCursor (USER32.@)
1935  */
1936 BOOL WINAPI SetSystemCursor(HCURSOR hcur, DWORD id)
1937 {
1938     FIXME("(%p,%08x),stub!\n",  hcur, id);
1939     return TRUE;
1940 }
1941
1942
1943 /**********************************************************************
1944  *              LookupIconIdFromDirectoryEx (USER32.@)
1945  */
1946 INT WINAPI LookupIconIdFromDirectoryEx( LPBYTE xdir, BOOL bIcon,
1947              INT width, INT height, UINT cFlag )
1948 {
1949     CURSORICONDIR       *dir = (CURSORICONDIR*)xdir;
1950     UINT retVal = 0;
1951     if( dir && !dir->idReserved && (dir->idType & 3) )
1952     {
1953         CURSORICONDIRENTRY* entry;
1954
1955         const HDC hdc = GetDC(0);
1956         const int depth = (cFlag & LR_MONOCHROME) ?
1957             1 : GetDeviceCaps(hdc, BITSPIXEL);
1958         ReleaseDC(0, hdc);
1959
1960         if( bIcon )
1961             entry = CURSORICON_FindBestIconRes( dir, width, height, depth );
1962         else
1963             entry = CURSORICON_FindBestCursorRes( dir, width, height, depth );
1964
1965         if( entry ) retVal = entry->wResId;
1966     }
1967     else WARN_(cursor)("invalid resource directory\n");
1968     return retVal;
1969 }
1970
1971 /**********************************************************************
1972  *              LookupIconIdFromDirectory (USER32.@)
1973  */
1974 INT WINAPI LookupIconIdFromDirectory( LPBYTE dir, BOOL bIcon )
1975 {
1976     return LookupIconIdFromDirectoryEx( dir, bIcon,
1977            bIcon ? GetSystemMetrics(SM_CXICON) : GetSystemMetrics(SM_CXCURSOR),
1978            bIcon ? GetSystemMetrics(SM_CYICON) : GetSystemMetrics(SM_CYCURSOR), bIcon ? 0 : LR_MONOCHROME );
1979 }
1980
1981 /***********************************************************************
1982  *              LoadCursorW (USER32.@)
1983  */
1984 HCURSOR WINAPI LoadCursorW(HINSTANCE hInstance, LPCWSTR name)
1985 {
1986     TRACE("%p, %s\n", hInstance, debugstr_w(name));
1987
1988     return LoadImageW( hInstance, name, IMAGE_CURSOR, 0, 0,
1989                        LR_SHARED | LR_DEFAULTSIZE );
1990 }
1991
1992 /***********************************************************************
1993  *              LoadCursorA (USER32.@)
1994  */
1995 HCURSOR WINAPI LoadCursorA(HINSTANCE hInstance, LPCSTR name)
1996 {
1997     TRACE("%p, %s\n", hInstance, debugstr_a(name));
1998
1999     return LoadImageA( hInstance, name, IMAGE_CURSOR, 0, 0,
2000                        LR_SHARED | LR_DEFAULTSIZE );
2001 }
2002
2003 /***********************************************************************
2004  *              LoadCursorFromFileW (USER32.@)
2005  */
2006 HCURSOR WINAPI LoadCursorFromFileW (LPCWSTR name)
2007 {
2008     TRACE("%s\n", debugstr_w(name));
2009
2010     return LoadImageW( 0, name, IMAGE_CURSOR, 0, 0,
2011                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
2012 }
2013
2014 /***********************************************************************
2015  *              LoadCursorFromFileA (USER32.@)
2016  */
2017 HCURSOR WINAPI LoadCursorFromFileA (LPCSTR name)
2018 {
2019     TRACE("%s\n", debugstr_a(name));
2020
2021     return LoadImageA( 0, name, IMAGE_CURSOR, 0, 0,
2022                        LR_LOADFROMFILE | LR_DEFAULTSIZE );
2023 }
2024
2025 /***********************************************************************
2026  *              LoadIconW (USER32.@)
2027  */
2028 HICON WINAPI LoadIconW(HINSTANCE hInstance, LPCWSTR name)
2029 {
2030     TRACE("%p, %s\n", hInstance, debugstr_w(name));
2031
2032     return LoadImageW( hInstance, name, IMAGE_ICON, 0, 0,
2033                        LR_SHARED | LR_DEFAULTSIZE );
2034 }
2035
2036 /***********************************************************************
2037  *              LoadIconA (USER32.@)
2038  */
2039 HICON WINAPI LoadIconA(HINSTANCE hInstance, LPCSTR name)
2040 {
2041     TRACE("%p, %s\n", hInstance, debugstr_a(name));
2042
2043     return LoadImageA( hInstance, name, IMAGE_ICON, 0, 0,
2044                        LR_SHARED | LR_DEFAULTSIZE );
2045 }
2046
2047 /**********************************************************************
2048  *              GetIconInfo (USER32.@)
2049  */
2050 BOOL WINAPI GetIconInfo(HICON hIcon, PICONINFO iconinfo)
2051 {
2052     struct cursoricon_object *ptr;
2053
2054     if (!(ptr = get_icon_ptr( hIcon ))) return FALSE;
2055
2056     TRACE("%p => %dx%d, %d bpp\n", hIcon,
2057           ptr->data.nWidth, ptr->data.nHeight, ptr->data.bBitsPerPixel);
2058
2059     if ( (ptr->data.ptHotSpot.x == ICON_HOTSPOT) &&
2060          (ptr->data.ptHotSpot.y == ICON_HOTSPOT) )
2061     {
2062       iconinfo->fIcon    = TRUE;
2063       iconinfo->xHotspot = ptr->data.nWidth / 2;
2064       iconinfo->yHotspot = ptr->data.nHeight / 2;
2065     }
2066     else
2067     {
2068       iconinfo->fIcon    = FALSE;
2069       iconinfo->xHotspot = ptr->data.ptHotSpot.x;
2070       iconinfo->yHotspot = ptr->data.ptHotSpot.y;
2071     }
2072
2073     iconinfo->hbmColor = copy_bitmap( ptr->color );
2074     iconinfo->hbmMask  = copy_bitmap( ptr->mask );
2075     release_icon_ptr( hIcon, ptr );
2076
2077     return TRUE;
2078 }
2079
2080 /**********************************************************************
2081  *              CreateIconIndirect (USER32.@)
2082  */
2083 HICON WINAPI CreateIconIndirect(PICONINFO iconinfo)
2084 {
2085     DIBSECTION bmpXor;
2086     BITMAP bmpAnd;
2087     HICON hObj;
2088     HBITMAP color = 0, mask;
2089     int xor_objsize = 0, sizeXor = 0, sizeAnd, width, height, planes, bpp;
2090     HDC src, dst;
2091
2092     TRACE("color %p, mask %p, hotspot %ux%u, fIcon %d\n",
2093            iconinfo->hbmColor, iconinfo->hbmMask,
2094            iconinfo->xHotspot, iconinfo->yHotspot, iconinfo->fIcon);
2095
2096     if (!iconinfo->hbmMask) return 0;
2097
2098     planes = GetDeviceCaps( screen_dc, PLANES );
2099     bpp = GetDeviceCaps( screen_dc, BITSPIXEL );
2100
2101     GetObjectW( iconinfo->hbmMask, sizeof(bmpAnd), &bmpAnd );
2102     TRACE("mask: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
2103            bmpAnd.bmWidth, bmpAnd.bmHeight, bmpAnd.bmWidthBytes,
2104            bmpAnd.bmPlanes, bmpAnd.bmBitsPixel);
2105
2106     if (iconinfo->hbmColor)
2107     {
2108         xor_objsize = GetObjectW( iconinfo->hbmColor, sizeof(bmpXor), &bmpXor );
2109         TRACE("color: width %d, height %d, width bytes %d, planes %u, bpp %u\n",
2110                bmpXor.dsBm.bmWidth, bmpXor.dsBm.bmHeight, bmpXor.dsBm.bmWidthBytes,
2111                bmpXor.dsBm.bmPlanes, bmpXor.dsBm.bmBitsPixel);
2112         /* we can use either depth 1 or screen depth for xor bitmap */
2113         if (bmpXor.dsBm.bmPlanes == 1 && bmpXor.dsBm.bmBitsPixel == 1) planes = bpp = 1;
2114         sizeXor = bmpXor.dsBm.bmHeight * planes * get_bitmap_width_bytes( bmpXor.dsBm.bmWidth, bpp );
2115
2116         width = bmpXor.dsBm.bmWidth;
2117         height = bmpXor.dsBm.bmHeight;
2118         if (bmpXor.dsBm.bmPlanes * bmpXor.dsBm.bmBitsPixel != 1)
2119         {
2120             color = CreateCompatibleBitmap( screen_dc, width, height );
2121             mask = CreateBitmap( width, height, 1, 1, NULL );
2122         }
2123         else mask = CreateBitmap( width, height * 2, 1, 1, NULL );
2124     }
2125     else
2126     {
2127         width = bmpAnd.bmWidth;
2128         height = bmpAnd.bmHeight;
2129         mask = CreateBitmap( width, height, 1, 1, NULL );
2130     }
2131
2132     sizeAnd = height * get_bitmap_width_bytes(width, 1);
2133
2134     src = CreateCompatibleDC( 0 );
2135     dst = CreateCompatibleDC( 0 );
2136
2137     SelectObject( src, iconinfo->hbmMask );
2138     SelectObject( dst, mask );
2139     StretchBlt( dst, 0, 0, width, height, src, 0, 0, bmpAnd.bmWidth, bmpAnd.bmHeight, SRCCOPY );
2140
2141     if (color)
2142     {
2143         SelectObject( src, iconinfo->hbmColor );
2144         SelectObject( dst, color );
2145         BitBlt( dst, 0, 0, width, height, src, 0, 0, SRCCOPY );
2146     }
2147     else if (iconinfo->hbmColor)
2148     {
2149         SelectObject( src, iconinfo->hbmColor );
2150         BitBlt( dst, 0, height, width, height, src, 0, 0, SRCCOPY );
2151     }
2152     DeleteDC( src );
2153     DeleteDC( dst );
2154
2155     hObj = alloc_icon_handle( sizeXor + sizeAnd );
2156     if (hObj)
2157     {
2158         struct cursoricon_object *info = get_icon_ptr( hObj );
2159
2160         info->color = color;
2161         info->mask  = mask;
2162         info->alpha = create_alpha_bitmap( iconinfo->hbmColor, mask, NULL, NULL );
2163
2164         /* If we are creating an icon, the hotspot is unused */
2165         if (iconinfo->fIcon)
2166         {
2167             info->data.ptHotSpot.x   = ICON_HOTSPOT;
2168             info->data.ptHotSpot.y   = ICON_HOTSPOT;
2169         }
2170         else
2171         {
2172             info->data.ptHotSpot.x   = iconinfo->xHotspot;
2173             info->data.ptHotSpot.y   = iconinfo->yHotspot;
2174         }
2175
2176         if (iconinfo->hbmColor)
2177         {
2178             info->data.nWidth        = bmpXor.dsBm.bmWidth;
2179             info->data.nHeight       = bmpXor.dsBm.bmHeight;
2180             info->data.nWidthBytes   = bmpXor.dsBm.bmWidthBytes;
2181             info->data.bPlanes       = planes;
2182             info->data.bBitsPerPixel = bpp;
2183         }
2184         else
2185         {
2186             info->data.nWidth        = bmpAnd.bmWidth;
2187             info->data.nHeight       = bmpAnd.bmHeight / 2;
2188             info->data.nWidthBytes   = get_bitmap_width_bytes(bmpAnd.bmWidth, 1);
2189             info->data.bPlanes       = 1;
2190             info->data.bBitsPerPixel = 1;
2191         }
2192
2193         /* Transfer the bitmap bits to the CURSORICONINFO structure */
2194
2195         GetBitmapBits( mask, sizeAnd, info + 1 );
2196
2197         if (color)
2198         {
2199             char *dst_bits = (char*)(info + 1) + sizeAnd;
2200
2201             if (bmpXor.dsBm.bmPlanes == planes && bmpXor.dsBm.bmBitsPixel == bpp)
2202                 GetBitmapBits( iconinfo->hbmColor, sizeXor, dst_bits );
2203             else
2204             {
2205                 BITMAPINFO bminfo;
2206                 int dib_width = get_dib_width_bytes( info->data.nWidth, info->data.bBitsPerPixel );
2207                 int bitmap_width = get_bitmap_width_bytes( info->data.nWidth, info->data.bBitsPerPixel );
2208
2209                 bminfo.bmiHeader.biSize = sizeof(bminfo);
2210                 bminfo.bmiHeader.biWidth = info->data.nWidth;
2211                 bminfo.bmiHeader.biHeight = info->data.nHeight;
2212                 bminfo.bmiHeader.biPlanes = info->data.bPlanes;
2213                 bminfo.bmiHeader.biBitCount = info->data.bBitsPerPixel;
2214                 bminfo.bmiHeader.biCompression = BI_RGB;
2215                 bminfo.bmiHeader.biSizeImage = info->data.nHeight * dib_width;
2216                 bminfo.bmiHeader.biXPelsPerMeter = 0;
2217                 bminfo.bmiHeader.biYPelsPerMeter = 0;
2218                 bminfo.bmiHeader.biClrUsed = 0;
2219                 bminfo.bmiHeader.biClrImportant = 0;
2220
2221                 /* swap lines for dib sections */
2222                 if (xor_objsize == sizeof(DIBSECTION))
2223                     bminfo.bmiHeader.biHeight = -bminfo.bmiHeader.biHeight;
2224
2225                 if (dib_width != bitmap_width)  /* need to fixup alignment */
2226                 {
2227                     char *src_bits = HeapAlloc( GetProcessHeap(), 0, bminfo.bmiHeader.biSizeImage );
2228
2229                     if (src_bits && GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->data.nHeight,
2230                                                src_bits, &bminfo, DIB_RGB_COLORS ))
2231                     {
2232                         int y;
2233                         for (y = 0; y < info->data.nHeight; y++)
2234                             memcpy( dst_bits + y * bitmap_width, src_bits + y * dib_width, bitmap_width );
2235                     }
2236                     HeapFree( GetProcessHeap(), 0, src_bits );
2237                 }
2238                 else
2239                     GetDIBits( screen_dc, iconinfo->hbmColor, 0, info->data.nHeight,
2240                                dst_bits, &bminfo, DIB_RGB_COLORS );
2241             }
2242         }
2243         release_icon_ptr( hObj, info );
2244         USER_Driver->pCreateCursorIcon( hObj, &info->data );
2245     }
2246     return hObj;
2247 }
2248
2249 /******************************************************************************
2250  *              DrawIconEx (USER32.@) Draws an icon or cursor on device context
2251  *
2252  * NOTES
2253  *    Why is this using SM_CXICON instead of SM_CXCURSOR?
2254  *
2255  * PARAMS
2256  *    hdc     [I] Handle to device context
2257  *    x0      [I] X coordinate of upper left corner
2258  *    y0      [I] Y coordinate of upper left corner
2259  *    hIcon   [I] Handle to icon to draw
2260  *    cxWidth [I] Width of icon
2261  *    cyWidth [I] Height of icon
2262  *    istep   [I] Index of frame in animated cursor
2263  *    hbr     [I] Handle to background brush
2264  *    flags   [I] Icon-drawing flags
2265  *
2266  * RETURNS
2267  *    Success: TRUE
2268  *    Failure: FALSE
2269  */
2270 BOOL WINAPI DrawIconEx( HDC hdc, INT x0, INT y0, HICON hIcon,
2271                             INT cxWidth, INT cyWidth, UINT istep,
2272                             HBRUSH hbr, UINT flags )
2273 {
2274     struct cursoricon_object *ptr;
2275     HDC hdc_dest, hMemDC;
2276     BOOL result = FALSE, DoOffscreen;
2277     HBITMAP hB_off = 0;
2278     COLORREF oldFg, oldBg;
2279     INT x, y, nStretchMode;
2280
2281     TRACE_(icon)("(hdc=%p,pos=%d.%d,hicon=%p,extend=%d.%d,istep=%d,br=%p,flags=0x%08x)\n",
2282                  hdc,x0,y0,hIcon,cxWidth,cyWidth,istep,hbr,flags );
2283
2284     if (!(ptr = get_icon_ptr( hIcon ))) return FALSE;
2285     if (!(hMemDC = CreateCompatibleDC( hdc )))
2286     {
2287         release_icon_ptr( hIcon, ptr );
2288         return FALSE;
2289     }
2290
2291     if (istep)
2292         FIXME_(icon)("Ignoring istep=%d\n", istep);
2293     if (flags & DI_NOMIRROR)
2294         FIXME_(icon)("Ignoring flag DI_NOMIRROR\n");
2295
2296     /* Calculate the size of the destination image.  */
2297     if (cxWidth == 0)
2298     {
2299         if (flags & DI_DEFAULTSIZE)
2300             cxWidth = GetSystemMetrics (SM_CXICON);
2301         else
2302             cxWidth = ptr->data.nWidth;
2303     }
2304     if (cyWidth == 0)
2305     {
2306         if (flags & DI_DEFAULTSIZE)
2307             cyWidth = GetSystemMetrics (SM_CYICON);
2308         else
2309             cyWidth = ptr->data.nHeight;
2310     }
2311
2312     DoOffscreen = (GetObjectType( hbr ) == OBJ_BRUSH);
2313
2314     if (DoOffscreen) {
2315         RECT r;
2316
2317         r.left = 0;
2318         r.top = 0;
2319         r.right = cxWidth;
2320         r.bottom = cxWidth;
2321
2322         if (!(hdc_dest = CreateCompatibleDC(hdc))) goto done;
2323         if (!(hB_off = CreateCompatibleBitmap(hdc, cxWidth, cyWidth)))
2324         {
2325             DeleteDC( hdc_dest );
2326             goto done;
2327         }
2328         SelectObject(hdc_dest, hB_off);
2329         FillRect(hdc_dest, &r, hbr);
2330         x = y = 0;
2331     }
2332     else
2333     {
2334         hdc_dest = hdc;
2335         x = x0;
2336         y = y0;
2337     }
2338
2339     nStretchMode = SetStretchBltMode (hdc, STRETCH_DELETESCANS);
2340
2341     oldFg = SetTextColor( hdc, RGB(0,0,0) );
2342     oldBg = SetBkColor( hdc, RGB(255,255,255) );
2343
2344     if ((flags & DI_MASK) && (!ptr->alpha || !(flags & DI_IMAGE)))
2345     {
2346         SelectObject( hMemDC, ptr->mask );
2347         StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
2348                     hMemDC, 0, 0, ptr->data.nWidth, ptr->data.nHeight, SRCAND );
2349     }
2350
2351     if (flags & DI_IMAGE)
2352     {
2353         if (ptr->alpha)
2354         {
2355             BLENDFUNCTION pixelblend = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
2356
2357             SelectObject( hMemDC, ptr->alpha );
2358             GdiAlphaBlend( hdc_dest, x, y, cxWidth, cyWidth, hMemDC,
2359                            0, 0, ptr->data.nWidth, ptr->data.nHeight, pixelblend );
2360         }
2361         else if (ptr->color)
2362         {
2363             DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
2364             SelectObject( hMemDC, ptr->color );
2365             StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
2366                         hMemDC, 0, 0, ptr->data.nWidth, ptr->data.nHeight, rop );
2367         }
2368         else
2369         {
2370             DWORD rop = (flags & DI_MASK) ? SRCINVERT : SRCCOPY;
2371             SelectObject( hMemDC, ptr->mask );
2372             StretchBlt( hdc_dest, x, y, cxWidth, cyWidth,
2373                         hMemDC, 0, ptr->data.nHeight, ptr->data.nWidth, ptr->data.nHeight, rop );
2374         }
2375     }
2376
2377     if (DoOffscreen) BitBlt( hdc, x0, y0, cxWidth, cyWidth, hdc_dest, 0, 0, SRCCOPY );
2378
2379     SetTextColor( hdc, oldFg );
2380     SetBkColor( hdc, oldBg );
2381     SetStretchBltMode (hdc, nStretchMode);
2382     result = TRUE;
2383     if (hdc_dest != hdc) DeleteDC( hdc_dest );
2384     if (hB_off) DeleteObject(hB_off);
2385 done:
2386     DeleteDC( hMemDC );
2387     release_icon_ptr( hIcon, ptr );
2388     return result;
2389 }
2390
2391 /***********************************************************************
2392  *           DIB_FixColorsToLoadflags
2393  *
2394  * Change color table entries when LR_LOADTRANSPARENT or LR_LOADMAP3DCOLORS
2395  * are in loadflags
2396  */
2397 static void DIB_FixColorsToLoadflags(BITMAPINFO * bmi, UINT loadflags, BYTE pix)
2398 {
2399     int colors;
2400     COLORREF c_W, c_S, c_F, c_L, c_C;
2401     int incr,i;
2402     RGBQUAD *ptr;
2403     int bitmap_type;
2404     LONG width;
2405     LONG height;
2406     WORD bpp;
2407     DWORD compr;
2408
2409     if (((bitmap_type = DIB_GetBitmapInfo((BITMAPINFOHEADER*) bmi, &width, &height, &bpp, &compr)) == -1))
2410     {
2411         WARN_(resource)("Invalid bitmap\n");
2412         return;
2413     }
2414
2415     if (bpp > 8) return;
2416
2417     if (bitmap_type == 0) /* BITMAPCOREHEADER */
2418     {
2419         incr = 3;
2420         colors = 1 << bpp;
2421     }
2422     else
2423     {
2424         incr = 4;
2425         colors = bmi->bmiHeader.biClrUsed;
2426         if (colors > 256) colors = 256;
2427         if (!colors && (bpp <= 8)) colors = 1 << bpp;
2428     }
2429
2430     c_W = GetSysColor(COLOR_WINDOW);
2431     c_S = GetSysColor(COLOR_3DSHADOW);
2432     c_F = GetSysColor(COLOR_3DFACE);
2433     c_L = GetSysColor(COLOR_3DLIGHT);
2434
2435     if (loadflags & LR_LOADTRANSPARENT) {
2436         switch (bpp) {
2437         case 1: pix = pix >> 7; break;
2438         case 4: pix = pix >> 4; break;
2439         case 8: break;
2440         default:
2441             WARN_(resource)("(%d): Unsupported depth\n", bpp);
2442             return;
2443         }
2444         if (pix >= colors) {
2445             WARN_(resource)("pixel has color index greater than biClrUsed!\n");
2446             return;
2447         }
2448         if (loadflags & LR_LOADMAP3DCOLORS) c_W = c_F;
2449         ptr = (RGBQUAD*)((char*)bmi->bmiColors+pix*incr);
2450         ptr->rgbBlue = GetBValue(c_W);
2451         ptr->rgbGreen = GetGValue(c_W);
2452         ptr->rgbRed = GetRValue(c_W);
2453     }
2454     if (loadflags & LR_LOADMAP3DCOLORS)
2455         for (i=0; i<colors; i++) {
2456             ptr = (RGBQUAD*)((char*)bmi->bmiColors+i*incr);
2457             c_C = RGB(ptr->rgbRed, ptr->rgbGreen, ptr->rgbBlue);
2458             if (c_C == RGB(128, 128, 128)) {
2459                 ptr->rgbRed = GetRValue(c_S);
2460                 ptr->rgbGreen = GetGValue(c_S);
2461                 ptr->rgbBlue = GetBValue(c_S);
2462             } else if (c_C == RGB(192, 192, 192)) {
2463                 ptr->rgbRed = GetRValue(c_F);
2464                 ptr->rgbGreen = GetGValue(c_F);
2465                 ptr->rgbBlue = GetBValue(c_F);
2466             } else if (c_C == RGB(223, 223, 223)) {
2467                 ptr->rgbRed = GetRValue(c_L);
2468                 ptr->rgbGreen = GetGValue(c_L);
2469                 ptr->rgbBlue = GetBValue(c_L);
2470             }
2471         }
2472 }
2473
2474
2475 /**********************************************************************
2476  *       BITMAP_Load
2477  */
2478 static HBITMAP BITMAP_Load( HINSTANCE instance, LPCWSTR name,
2479                             INT desiredx, INT desiredy, UINT loadflags )
2480 {
2481     HBITMAP hbitmap = 0, orig_bm;
2482     HRSRC hRsrc;
2483     HGLOBAL handle;
2484     char *ptr = NULL;
2485     BITMAPINFO *info, *fix_info = NULL, *scaled_info = NULL;
2486     int size;
2487     BYTE pix;
2488     char *bits;
2489     LONG width, height, new_width, new_height;
2490     WORD bpp_dummy;
2491     DWORD compr_dummy, offbits = 0;
2492     INT bm_type;
2493     HDC screen_mem_dc = NULL;
2494
2495     if (!(loadflags & LR_LOADFROMFILE))
2496     {
2497         if (!instance)
2498         {
2499             /* OEM bitmap: try to load the resource from user32.dll */
2500             instance = user32_module;
2501         }
2502
2503         if (!(hRsrc = FindResourceW( instance, name, (LPWSTR)RT_BITMAP ))) return 0;
2504         if (!(handle = LoadResource( instance, hRsrc ))) return 0;
2505
2506         if ((info = LockResource( handle )) == NULL) return 0;
2507     }
2508     else
2509     {
2510         BITMAPFILEHEADER * bmfh;
2511
2512         if (!(ptr = map_fileW( name, NULL ))) return 0;
2513         info = (BITMAPINFO *)(ptr + sizeof(BITMAPFILEHEADER));
2514         bmfh = (BITMAPFILEHEADER *)ptr;
2515         if (bmfh->bfType != 0x4d42 /* 'BM' */)
2516         {
2517             WARN("Invalid/unsupported bitmap format!\n");
2518             goto end_close;
2519         }
2520         if (bmfh->bfOffBits) offbits = bmfh->bfOffBits - sizeof(BITMAPFILEHEADER);
2521     }
2522
2523     if (info->bmiHeader.biHeight > 65535 || info->bmiHeader.biWidth > 65535) {
2524         WARN("Broken BitmapInfoHeader!\n");
2525         goto end_close;
2526     }
2527
2528     size = bitmap_info_size(info, DIB_RGB_COLORS);
2529     fix_info = HeapAlloc(GetProcessHeap(), 0, size);
2530     scaled_info = HeapAlloc(GetProcessHeap(), 0, size);
2531
2532     if (!fix_info || !scaled_info) goto end;
2533     memcpy(fix_info, info, size);
2534
2535     pix = *((LPBYTE)info + size);
2536     DIB_FixColorsToLoadflags(fix_info, loadflags, pix);
2537
2538     memcpy(scaled_info, fix_info, size);
2539     bm_type = DIB_GetBitmapInfo( &fix_info->bmiHeader, &width, &height,
2540                                  &bpp_dummy, &compr_dummy);
2541     if(desiredx != 0)
2542         new_width = desiredx;
2543     else
2544         new_width = width;
2545
2546     if(desiredy != 0)
2547         new_height = height > 0 ? desiredy : -desiredy;
2548     else
2549         new_height = height;
2550
2551     if(bm_type == 0)
2552     {
2553         BITMAPCOREHEADER *core = (BITMAPCOREHEADER *)&scaled_info->bmiHeader;
2554         core->bcWidth = new_width;
2555         core->bcHeight = new_height;
2556     }
2557     else
2558     {
2559         scaled_info->bmiHeader.biWidth = new_width;
2560         scaled_info->bmiHeader.biHeight = new_height;
2561     }
2562
2563     if (new_height < 0) new_height = -new_height;
2564
2565     if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2566     if (!(screen_mem_dc = CreateCompatibleDC( screen_dc ))) goto end;
2567
2568     bits = (char *)info + (offbits ? offbits : size);
2569
2570     if (loadflags & LR_CREATEDIBSECTION)
2571     {
2572         scaled_info->bmiHeader.biCompression = 0; /* DIBSection can't be compressed */
2573         hbitmap = CreateDIBSection(screen_dc, scaled_info, DIB_RGB_COLORS, NULL, 0, 0);
2574     }
2575     else
2576     {
2577         if (is_dib_monochrome(fix_info))
2578             hbitmap = CreateBitmap(new_width, new_height, 1, 1, NULL);
2579         else
2580             hbitmap = CreateCompatibleBitmap(screen_dc, new_width, new_height);        
2581     }
2582
2583     orig_bm = SelectObject(screen_mem_dc, hbitmap);
2584     StretchDIBits(screen_mem_dc, 0, 0, new_width, new_height, 0, 0, width, height, bits, fix_info, DIB_RGB_COLORS, SRCCOPY);
2585     SelectObject(screen_mem_dc, orig_bm);
2586
2587 end:
2588     if (screen_mem_dc) DeleteDC(screen_mem_dc);
2589     HeapFree(GetProcessHeap(), 0, scaled_info);
2590     HeapFree(GetProcessHeap(), 0, fix_info);
2591 end_close:
2592     if (loadflags & LR_LOADFROMFILE) UnmapViewOfFile( ptr );
2593
2594     return hbitmap;
2595 }
2596
2597 /**********************************************************************
2598  *              LoadImageA (USER32.@)
2599  *
2600  * See LoadImageW.
2601  */
2602 HANDLE WINAPI LoadImageA( HINSTANCE hinst, LPCSTR name, UINT type,
2603                               INT desiredx, INT desiredy, UINT loadflags)
2604 {
2605     HANDLE res;
2606     LPWSTR u_name;
2607
2608     if (IS_INTRESOURCE(name))
2609         return LoadImageW(hinst, (LPCWSTR)name, type, desiredx, desiredy, loadflags);
2610
2611     __TRY {
2612         DWORD len = MultiByteToWideChar( CP_ACP, 0, name, -1, NULL, 0 );
2613         u_name = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) );
2614         MultiByteToWideChar( CP_ACP, 0, name, -1, u_name, len );
2615     }
2616     __EXCEPT_PAGE_FAULT {
2617         SetLastError( ERROR_INVALID_PARAMETER );
2618         return 0;
2619     }
2620     __ENDTRY
2621     res = LoadImageW(hinst, u_name, type, desiredx, desiredy, loadflags);
2622     HeapFree(GetProcessHeap(), 0, u_name);
2623     return res;
2624 }
2625
2626
2627 /******************************************************************************
2628  *              LoadImageW (USER32.@) Loads an icon, cursor, or bitmap
2629  *
2630  * PARAMS
2631  *    hinst     [I] Handle of instance that contains image
2632  *    name      [I] Name of image
2633  *    type      [I] Type of image
2634  *    desiredx  [I] Desired width
2635  *    desiredy  [I] Desired height
2636  *    loadflags [I] Load flags
2637  *
2638  * RETURNS
2639  *    Success: Handle to newly loaded image
2640  *    Failure: NULL
2641  *
2642  * FIXME: Implementation lacks some features, see LR_ defines in winuser.h
2643  */
2644 HANDLE WINAPI LoadImageW( HINSTANCE hinst, LPCWSTR name, UINT type,
2645                 INT desiredx, INT desiredy, UINT loadflags )
2646 {
2647     TRACE_(resource)("(%p,%s,%d,%d,%d,0x%08x)\n",
2648                      hinst,debugstr_w(name),type,desiredx,desiredy,loadflags);
2649
2650     if (loadflags & LR_DEFAULTSIZE) {
2651         if (type == IMAGE_ICON) {
2652             if (!desiredx) desiredx = GetSystemMetrics(SM_CXICON);
2653             if (!desiredy) desiredy = GetSystemMetrics(SM_CYICON);
2654         } else if (type == IMAGE_CURSOR) {
2655             if (!desiredx) desiredx = GetSystemMetrics(SM_CXCURSOR);
2656             if (!desiredy) desiredy = GetSystemMetrics(SM_CYCURSOR);
2657         }
2658     }
2659     if (loadflags & LR_LOADFROMFILE) loadflags &= ~LR_SHARED;
2660     switch (type) {
2661     case IMAGE_BITMAP:
2662         return BITMAP_Load( hinst, name, desiredx, desiredy, loadflags );
2663
2664     case IMAGE_ICON:
2665         if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
2666         if (screen_dc)
2667         {
2668             return CURSORICON_Load(hinst, name, desiredx, desiredy,
2669                                    GetDeviceCaps(screen_dc, BITSPIXEL),
2670                                    FALSE, loadflags);
2671         }
2672         break;
2673
2674     case IMAGE_CURSOR:
2675         return CURSORICON_Load(hinst, name, desiredx, desiredy,
2676                                1, TRUE, loadflags);
2677     }
2678     return 0;
2679 }
2680
2681 /******************************************************************************
2682  *              CopyImage (USER32.@) Creates new image and copies attributes to it
2683  *
2684  * PARAMS
2685  *    hnd      [I] Handle to image to copy
2686  *    type     [I] Type of image to copy
2687  *    desiredx [I] Desired width of new image
2688  *    desiredy [I] Desired height of new image
2689  *    flags    [I] Copy flags
2690  *
2691  * RETURNS
2692  *    Success: Handle to newly created image
2693  *    Failure: NULL
2694  *
2695  * BUGS
2696  *    Only Windows NT 4.0 supports the LR_COPYRETURNORG flag for bitmaps,
2697  *    all other versions (95/2000/XP have been tested) ignore it.
2698  *
2699  * NOTES
2700  *    If LR_CREATEDIBSECTION is absent, the copy will be monochrome for
2701  *    a monochrome source bitmap or if LR_MONOCHROME is present, otherwise
2702  *    the copy will have the same depth as the screen.
2703  *    The content of the image will only be copied if the bit depth of the
2704  *    original image is compatible with the bit depth of the screen, or
2705  *    if the source is a DIB section.
2706  *    The LR_MONOCHROME flag is ignored if LR_CREATEDIBSECTION is present.
2707  */
2708 HANDLE WINAPI CopyImage( HANDLE hnd, UINT type, INT desiredx,
2709                              INT desiredy, UINT flags )
2710 {
2711     TRACE("hnd=%p, type=%u, desiredx=%d, desiredy=%d, flags=%x\n",
2712           hnd, type, desiredx, desiredy, flags);
2713
2714     switch (type)
2715     {
2716         case IMAGE_BITMAP:
2717         {
2718             HBITMAP res = NULL;
2719             DIBSECTION ds;
2720             int objSize;
2721             BITMAPINFO * bi;
2722
2723             objSize = GetObjectW( hnd, sizeof(ds), &ds );
2724             if (!objSize) return 0;
2725             if ((desiredx < 0) || (desiredy < 0)) return 0;
2726
2727             if (flags & LR_COPYFROMRESOURCE)
2728             {
2729                 FIXME("The flag LR_COPYFROMRESOURCE is not implemented for bitmaps\n");
2730             }
2731
2732             if (desiredx == 0) desiredx = ds.dsBm.bmWidth;
2733             if (desiredy == 0) desiredy = ds.dsBm.bmHeight;
2734
2735             /* Allocate memory for a BITMAPINFOHEADER structure and a
2736                color table. The maximum number of colors in a color table
2737                is 256 which corresponds to a bitmap with depth 8.
2738                Bitmaps with higher depths don't have color tables. */
2739             bi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
2740             if (!bi) return 0;
2741
2742             bi->bmiHeader.biSize        = sizeof(bi->bmiHeader);
2743             bi->bmiHeader.biPlanes      = ds.dsBm.bmPlanes;
2744             bi->bmiHeader.biBitCount    = ds.dsBm.bmBitsPixel;
2745             bi->bmiHeader.biCompression = BI_RGB;
2746
2747             if (flags & LR_CREATEDIBSECTION)
2748             {
2749                 /* Create a DIB section. LR_MONOCHROME is ignored */
2750                 void * bits;
2751                 HDC dc = CreateCompatibleDC(NULL);
2752
2753                 if (objSize == sizeof(DIBSECTION))
2754                 {
2755                     /* The source bitmap is a DIB.
2756                        Get its attributes to create an exact copy */
2757                     memcpy(bi, &ds.dsBmih, sizeof(BITMAPINFOHEADER));
2758                 }
2759
2760                 /* Get the color table or the color masks */
2761                 GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2762
2763                 bi->bmiHeader.biWidth  = desiredx;
2764                 bi->bmiHeader.biHeight = desiredy;
2765                 bi->bmiHeader.biSizeImage = 0;
2766
2767                 res = CreateDIBSection(dc, bi, DIB_RGB_COLORS, &bits, NULL, 0);
2768                 DeleteDC(dc);
2769             }
2770             else
2771             {
2772                 /* Create a device-dependent bitmap */
2773
2774                 BOOL monochrome = (flags & LR_MONOCHROME);
2775
2776                 if (objSize == sizeof(DIBSECTION))
2777                 {
2778                     /* The source bitmap is a DIB section.
2779                        Get its attributes */
2780                     HDC dc = CreateCompatibleDC(NULL);
2781                     bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
2782                     bi->bmiHeader.biBitCount = ds.dsBm.bmBitsPixel;
2783                     GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2784                     DeleteDC(dc);
2785
2786                     if (!monochrome && ds.dsBm.bmBitsPixel == 1)
2787                     {
2788                         /* Look if the colors of the DIB are black and white */
2789
2790                         monochrome = 
2791                               (bi->bmiColors[0].rgbRed == 0xff
2792                             && bi->bmiColors[0].rgbGreen == 0xff
2793                             && bi->bmiColors[0].rgbBlue == 0xff
2794                             && bi->bmiColors[0].rgbReserved == 0
2795                             && bi->bmiColors[1].rgbRed == 0
2796                             && bi->bmiColors[1].rgbGreen == 0
2797                             && bi->bmiColors[1].rgbBlue == 0
2798                             && bi->bmiColors[1].rgbReserved == 0)
2799                             ||
2800                               (bi->bmiColors[0].rgbRed == 0
2801                             && bi->bmiColors[0].rgbGreen == 0
2802                             && bi->bmiColors[0].rgbBlue == 0
2803                             && bi->bmiColors[0].rgbReserved == 0
2804                             && bi->bmiColors[1].rgbRed == 0xff
2805                             && bi->bmiColors[1].rgbGreen == 0xff
2806                             && bi->bmiColors[1].rgbBlue == 0xff
2807                             && bi->bmiColors[1].rgbReserved == 0);
2808                     }
2809                 }
2810                 else if (!monochrome)
2811                 {
2812                     monochrome = ds.dsBm.bmBitsPixel == 1;
2813                 }
2814
2815                 if (monochrome)
2816                 {
2817                     res = CreateBitmap(desiredx, desiredy, 1, 1, NULL);
2818                 }
2819                 else
2820                 {
2821                     HDC screenDC = GetDC(NULL);
2822                     res = CreateCompatibleBitmap(screenDC, desiredx, desiredy);
2823                     ReleaseDC(NULL, screenDC);
2824                 }
2825             }
2826
2827             if (res)
2828             {
2829                 /* Only copy the bitmap if it's a DIB section or if it's
2830                    compatible to the screen */
2831                 BOOL copyContents;
2832
2833                 if (objSize == sizeof(DIBSECTION))
2834                 {
2835                     copyContents = TRUE;
2836                 }
2837                 else
2838                 {
2839                     HDC screenDC = GetDC(NULL);
2840                     int screen_depth = GetDeviceCaps(screenDC, BITSPIXEL);
2841                     ReleaseDC(NULL, screenDC);
2842
2843                     copyContents = (ds.dsBm.bmBitsPixel == 1 || ds.dsBm.bmBitsPixel == screen_depth);
2844                 }
2845
2846                 if (copyContents)
2847                 {
2848                     /* The source bitmap may already be selected in a device context,
2849                        use GetDIBits/StretchDIBits and not StretchBlt  */
2850
2851                     HDC dc;
2852                     void * bits;
2853
2854                     dc = CreateCompatibleDC(NULL);
2855
2856                     bi->bmiHeader.biWidth = ds.dsBm.bmWidth;
2857                     bi->bmiHeader.biHeight = ds.dsBm.bmHeight;
2858                     bi->bmiHeader.biSizeImage = 0;
2859                     bi->bmiHeader.biClrUsed = 0;
2860                     bi->bmiHeader.biClrImportant = 0;
2861
2862                     /* Fill in biSizeImage */
2863                     GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, NULL, bi, DIB_RGB_COLORS);
2864                     bits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, bi->bmiHeader.biSizeImage);
2865
2866                     if (bits)
2867                     {
2868                         HBITMAP oldBmp;
2869
2870                         /* Get the image bits of the source bitmap */
2871                         GetDIBits(dc, hnd, 0, ds.dsBm.bmHeight, bits, bi, DIB_RGB_COLORS);
2872
2873                         /* Copy it to the destination bitmap */
2874                         oldBmp = SelectObject(dc, res);
2875                         StretchDIBits(dc, 0, 0, desiredx, desiredy,
2876                                       0, 0, ds.dsBm.bmWidth, ds.dsBm.bmHeight,
2877                                       bits, bi, DIB_RGB_COLORS, SRCCOPY);
2878                         SelectObject(dc, oldBmp);
2879
2880                         HeapFree(GetProcessHeap(), 0, bits);
2881                     }
2882
2883                     DeleteDC(dc);
2884                 }
2885
2886                 if (flags & LR_COPYDELETEORG)
2887                 {
2888                     DeleteObject(hnd);
2889                 }
2890             }
2891             HeapFree(GetProcessHeap(), 0, bi);
2892             return res;
2893         }
2894         case IMAGE_ICON:
2895                 return CURSORICON_ExtCopy(hnd,type, desiredx, desiredy, flags);
2896         case IMAGE_CURSOR:
2897                 /* Should call CURSORICON_ExtCopy but more testing
2898                  * needs to be done before we change this
2899                  */
2900                 if (flags) FIXME("Flags are ignored\n");
2901                 return CopyCursor(hnd);
2902     }
2903     return 0;
2904 }
2905
2906
2907 /******************************************************************************
2908  *              LoadBitmapW (USER32.@) Loads bitmap from the executable file
2909  *
2910  * RETURNS
2911  *    Success: Handle to specified bitmap
2912  *    Failure: NULL
2913  */
2914 HBITMAP WINAPI LoadBitmapW(
2915     HINSTANCE instance, /* [in] Handle to application instance */
2916     LPCWSTR name)         /* [in] Address of bitmap resource name */
2917 {
2918     return LoadImageW( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2919 }
2920
2921 /**********************************************************************
2922  *              LoadBitmapA (USER32.@)
2923  *
2924  * See LoadBitmapW.
2925  */
2926 HBITMAP WINAPI LoadBitmapA( HINSTANCE instance, LPCSTR name )
2927 {
2928     return LoadImageA( instance, name, IMAGE_BITMAP, 0, 0, 0 );
2929 }