soui 5.0.0.1
Soui5 Doc
 
Loading...
Searching...
No Matches
cursoricon.cpp
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#include <assert.h>
26#include <string.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <algorithm>
30#include <windows.h>
31
32#define WARN printf
33#pragma warning(disable:4018)
34#pragma pack(push,1)
35typedef struct {
36 BYTE bWidth;
37 BYTE bHeight;
38 BYTE bColorCount;
39 BYTE bReserved;
40 WORD xHotspot;
41 WORD yHotspot;
42 DWORD dwDIBSize;
43 DWORD dwDIBOffset;
44} CURSORICONFILEDIRENTRY;
45
46typedef struct
47{
48 WORD idReserved;
49 WORD idType;
50 WORD idCount;
51 CURSORICONFILEDIRENTRY idEntries[1];
52} CURSORICONFILEDIR;
53
54
55typedef struct
56{
57 BYTE bWidth;
58 BYTE bHeight;
59 BYTE bColorCount;
60 BYTE bReserved;
61} ICONRESDIR;
62
63typedef struct
64{
65 WORD wWidth;
66 WORD wHeight;
67} CURSORDIR;
68
69typedef struct
70{ union
71{ ICONRESDIR icon;
72CURSORDIR cursor;
73} ResInfo;
74WORD wPlanes;
75WORD wBitCount;
76DWORD dwBytesInRes;
77WORD wResId;
78} CURSORICONDIRENTRY;
79
80typedef struct
81{
82 WORD idReserved;
83 WORD idType;
84 WORD idCount;
85 CURSORICONDIRENTRY idEntries[1];
86} CURSORICONDIR;
87
88
89#pragma pack(pop)
90
91
92static HDC screen_dc;
93
94static const WCHAR DISPLAYW[] = {'D','I','S','P','L','A','Y',0};
95
96/***********************************************************************
97 * get_dib_image_size
98 *
99 * Return the size of a DIB bitmap in bytes.
100 */
101static int get_dib_image_size( int width, int height, int depth )
102{
103 return (((width * depth + 31) / 8) & ~3) * abs( height );
104}
105
106
107/***********************************************************************
108 * bitmap_info_size
109 *
110 * Return the size of the bitmap info structure including color table.
111 */
112static int bitmap_info_size( const BITMAPINFO * info, WORD coloruse )
113{
114 unsigned int colors, size, masks = 0;
115
116 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
117 {
118 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)info;
119 colors = (core->bcBitCount <= 8) ? 1 << core->bcBitCount : 0;
120 return sizeof(BITMAPCOREHEADER) + colors *
121 ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBTRIPLE) : sizeof(WORD));
122 }
123 else /* assume BITMAPINFOHEADER */
124 {
125 colors = info->bmiHeader.biClrUsed;
126 if (colors > 256) /* buffer overflow otherwise */
127 colors = 256;
128 if (!colors && (info->bmiHeader.biBitCount <= 8))
129 colors = 1 << info->bmiHeader.biBitCount;
130 if (info->bmiHeader.biCompression == BI_BITFIELDS) masks = 3;
131 size = (std::max)((int) info->bmiHeader.biSize, (int)(sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD) ));
132 return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
133 }
134}
135
136/***********************************************************************
137 * is_dib_monochrome
138 *
139 * Returns whether a DIB can be converted to a monochrome DDB.
140 *
141 * A DIB can be converted if its color table contains only black and
142 * white. Black must be the first color in the color table.
143 *
144 * Note : If the first color in the color table is white followed by
145 * black, we can't convert it to a monochrome DDB with
146 * SetDIBits, because black and white would be inverted.
147 */
148static BOOL is_dib_monochrome( const BITMAPINFO* info )
149{
150 if (info->bmiHeader.biBitCount != 1) return FALSE;
151
152 if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
153 {
154 const RGBTRIPLE *rgb = ((const BITMAPCOREINFO*)info)->bmciColors;
155
156 /* Check if the first color is black */
157 if ((rgb->rgbtRed == 0) && (rgb->rgbtGreen == 0) && (rgb->rgbtBlue == 0))
158 {
159 rgb++;
160
161 /* Check if the second color is white */
162 return ((rgb->rgbtRed == 0xff) && (rgb->rgbtGreen == 0xff)
163 && (rgb->rgbtBlue == 0xff));
164 }
165 else return FALSE;
166 }
167 else /* assume BITMAPINFOHEADER */
168 {
169 const RGBQUAD *rgb = info->bmiColors;
170
171 /* Check if the first color is black */
172 if ((rgb->rgbRed == 0) && (rgb->rgbGreen == 0) &&
173 (rgb->rgbBlue == 0) && (rgb->rgbReserved == 0))
174 {
175 rgb++;
176
177 /* Check if the second color is white */
178 return ((rgb->rgbRed == 0xff) && (rgb->rgbGreen == 0xff)
179 && (rgb->rgbBlue == 0xff) && (rgb->rgbReserved == 0));
180 }
181 else return FALSE;
182 }
183}
184
185/***********************************************************************
186 * DIB_GetBitmapInfo
187 *
188 * Get the info from a bitmap header.
189 * Return 1 for INFOHEADER, 0 for COREHEADER, -1 in case of failure.
190 */
191static int DIB_GetBitmapInfo( const BITMAPINFOHEADER *header, LONG *width,
192 LONG *height, WORD *bpp, DWORD *compr )
193{
194 if (header->biSize == sizeof(BITMAPCOREHEADER))
195 {
196 const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *)header;
197 *width = core->bcWidth;
198 *height = core->bcHeight;
199 *bpp = core->bcBitCount;
200 *compr = 0;
201 return 0;
202 }
203 else if (header->biSize == sizeof(BITMAPINFOHEADER) ||
204 header->biSize == sizeof(BITMAPV4HEADER) ||
205 header->biSize == sizeof(BITMAPV5HEADER))
206 {
207 *width = header->biWidth;
208 *height = header->biHeight;
209 *bpp = header->biBitCount;
210 *compr = header->biCompression;
211 return 1;
212 }
213 return -1;
214}
215
216/*
217 * The following macro functions account for the irregularities of
218 * accessing cursor and icon resources in files and resource entries.
219 */
220typedef BOOL (*fnGetCIEntry)( LPCVOID dir, DWORD size, int n,
221 int *width, int *height, int *bits );
222
223/**********************************************************************
224 * CURSORICON_FindBestIcon
225 *
226 * Find the icon closest to the requested size and bit depth.
227 */
228static int CURSORICON_FindBestIcon( LPCVOID dir, DWORD size, fnGetCIEntry get_entry,
229 int width, int height, int depth, UINT loadflags )
230{
231 int i, cx, cy, bits, bestEntry = -1;
232 UINT iTotalDiff, iXDiff=0, iYDiff=0, iColorDiff;
233 UINT iTempXDiff, iTempYDiff, iTempColorDiff;
234
235 /* Find Best Fit */
236 iTotalDiff = 0xFFFFFFFF;
237 iColorDiff = 0xFFFFFFFF;
238
239 if (loadflags & LR_DEFAULTSIZE)
240 {
241 if (!width) width = GetSystemMetrics( SM_CXICON );
242 if (!height) height = GetSystemMetrics( SM_CYICON );
243 }
244 else if (!width && !height)
245 {
246 /* use the size of the first entry */
247 if (!get_entry( dir, size, 0, &width, &height, &bits )) return -1;
248 iTotalDiff = 0;
249 }
250
251 for ( i = 0; iTotalDiff && get_entry( dir, size, i, &cx, &cy, &bits ); i++ )
252 {
253 iTempXDiff = abs(width - cx);
254 iTempYDiff = abs(height - cy);
255
256 if(iTotalDiff > (iTempXDiff + iTempYDiff))
257 {
258 iXDiff = iTempXDiff;
259 iYDiff = iTempYDiff;
260 iTotalDiff = iXDiff + iYDiff;
261 }
262 }
263
264 /* Find Best Colors for Best Fit */
265 for ( i = 0; get_entry( dir, size, i, &cx, &cy, &bits ); i++ )
266 {
267 if(abs(width - cx) == (int)iXDiff && abs(height - cy) == (int)iYDiff)
268 {
269 iTempColorDiff = abs(depth - bits);
270 if(iColorDiff > iTempColorDiff)
271 {
272 bestEntry = i;
273 iColorDiff = iTempColorDiff;
274 }
275 }
276 }
277
278 return bestEntry;
279}
280
281static BOOL CURSORICON_GetResIconEntry( LPCVOID dir, DWORD size, int n,
282 int *width, int *height, int *bits )
283{
284 const CURSORICONDIR *resdir = (const CURSORICONDIR *)dir;
285 const ICONRESDIR *icon;
286
287 if ( resdir->idCount <= n )
288 return FALSE;
289 if ((const char *)&resdir->idEntries[n + 1] - (const char *)dir > size)
290 return FALSE;
291 icon = &resdir->idEntries[n].ResInfo.icon;
292 *width = icon->bWidth;
293 *height = icon->bHeight;
294 *bits = resdir->idEntries[n].wBitCount;
295 return TRUE;
296}
297
298/**********************************************************************
299 * CURSORICON_FindBestCursor
300 *
301 * Find the cursor closest to the requested size.
302 *
303 * FIXME: parameter 'color' ignored.
304 */
305static int CURSORICON_FindBestCursor( LPCVOID dir, DWORD size, fnGetCIEntry get_entry,
306 int width, int height, int depth, UINT loadflags )
307{
308 int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
309
310 if (loadflags & LR_DEFAULTSIZE)
311 {
312 if (!width) width = GetSystemMetrics( SM_CXCURSOR );
313 if (!height) height = GetSystemMetrics( SM_CYCURSOR );
314 }
315 else if (!width && !height)
316 {
317 /* use the first entry */
318 if (!get_entry( dir, size, 0, &width, &height, &bits )) return -1;
319 return 0;
320 }
321
322 /* Double height to account for AND and XOR masks */
323
324 height *= 2;
325
326 /* First find the largest one smaller than or equal to the requested size*/
327
328 maxwidth = maxheight = 0;
329 for ( i = 0; get_entry( dir, size, i, &cx, &cy, &bits ); i++ )
330 {
331 if ((cx <= width) && (cy <= height) &&
332 (cx > maxwidth) && (cy > maxheight))
333 {
334 bestEntry = i;
335 maxwidth = cx;
336 maxheight = cy;
337 }
338 }
339 if (bestEntry != -1) return bestEntry;
340
341 /* Now find the smallest one larger than the requested size */
342
343 maxwidth = maxheight = 255;
344 for ( i = 0; get_entry( dir, size, i, &cx, &cy, &bits ); i++ )
345 {
346 if (((cx < maxwidth) && (cy < maxheight)) || (bestEntry == -1))
347 {
348 bestEntry = i;
349 maxwidth = cx;
350 maxheight = cy;
351 }
352 }
353
354 return bestEntry;
355}
356
357static BOOL CURSORICON_GetResCursorEntry( LPCVOID dir, DWORD size, int n,
358 int *width, int *height, int *bits )
359{
360 const CURSORICONDIR *resdir = (const CURSORICONDIR *)dir;
361 const CURSORDIR *cursor;
362
363 if ( resdir->idCount <= n )
364 return FALSE;
365 if ((const char *)&resdir->idEntries[n + 1] - (const char *)dir > size)
366 return FALSE;
367 cursor = &resdir->idEntries[n].ResInfo.cursor;
368 *width = cursor->wWidth;
369 *height = cursor->wHeight;
370 *bits = resdir->idEntries[n].wBitCount;
371 return TRUE;
372}
373
374static const CURSORICONDIRENTRY *CURSORICON_FindBestIconRes( const CURSORICONDIR * dir, DWORD size,
375 int width, int height, int depth,
376 UINT loadflags )
377{
378 int n;
379
380 n = CURSORICON_FindBestIcon( dir, size, CURSORICON_GetResIconEntry,
381 width, height, depth, loadflags );
382 if ( n < 0 )
383 return NULL;
384 return &dir->idEntries[n];
385}
386
387static const CURSORICONDIRENTRY *CURSORICON_FindBestCursorRes( const CURSORICONDIR *dir, DWORD size,
388 int width, int height, int depth,
389 UINT loadflags )
390{
391 int n = CURSORICON_FindBestCursor( dir, size, CURSORICON_GetResCursorEntry,
392 width, height, depth, loadflags );
393 if ( n < 0 )
394 return NULL;
395 return &dir->idEntries[n];
396}
397
398static BOOL CURSORICON_GetFileEntry( LPCVOID dir, DWORD size, int n,
399 int *width, int *height, int *bits )
400{
401 const CURSORICONFILEDIR *filedir = (const CURSORICONFILEDIR *)dir;
402 const CURSORICONFILEDIRENTRY *entry;
403 const BITMAPINFOHEADER *info;
404
405 if ( filedir->idCount <= n )
406 return FALSE;
407 if ((const char *)&filedir->idEntries[n + 1] - (const char *)dir > size)
408 return FALSE;
409 entry = &filedir->idEntries[n];
410 info = (const BITMAPINFOHEADER *)((const char *)dir + entry->dwDIBOffset);
411 if ((const char *)(info + 1) - (const char *)dir > size) return FALSE;
412 *width = entry->bWidth;
413 *height = entry->bHeight;
414 *bits = info->biBitCount;
415 return TRUE;
416}
417
418static const CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( const CURSORICONFILEDIR *dir, DWORD size,
419 int width, int height, int depth,
420 UINT loadflags )
421{
422 int n = CURSORICON_FindBestCursor( dir, size, CURSORICON_GetFileEntry,
423 width, height, depth, loadflags );
424 if ( n < 0 )
425 return NULL;
426 return &dir->idEntries[n];
427}
428
429static const CURSORICONFILEDIRENTRY *CURSORICON_FindBestIconFile( const CURSORICONFILEDIR *dir, DWORD size,
430 int width, int height, int depth,
431 UINT loadflags )
432{
433 int n = CURSORICON_FindBestIcon( dir, size, CURSORICON_GetFileEntry,
434 width, height, depth, loadflags );
435 if ( n < 0 )
436 return NULL;
437 return &dir->idEntries[n];
438}
439
440/***********************************************************************
441 * bmi_has_alpha
442 */
443static BOOL bmi_has_alpha( const BITMAPINFO *info, const void *bits )
444{
445 int i;
446 BOOL has_alpha = FALSE;
447 const unsigned char *ptr = (const unsigned char *)bits;
448
449 if (info->bmiHeader.biBitCount != 32) return FALSE;
450 for (i = 0; i < info->bmiHeader.biWidth * abs(info->bmiHeader.biHeight); i++, ptr += 4)
451 {
452 has_alpha = (ptr[3] != 0);
453 if ((has_alpha)) break;
454 }
455
456 return has_alpha;
457}
458
459/***********************************************************************
460 * create_alpha_bitmap
461 *
462 * Create the alpha bitmap for a 32-bpp icon that has an alpha channel.
463 */
464static HBITMAP create_alpha_bitmap(const BITMAPINFO *src_info, const void *color_bits,int bmWidth,int bmHeight )
465{
466 HBITMAP alpha = 0;
467 BITMAPINFO *info = NULL;
468 HDC hdc;
469 void *bits;
470 unsigned char *ptr;
471 int i;
472
473 hdc = CreateCompatibleDC(0);
474 if (!(hdc)) return 0;
475 info = (BITMAPINFO *)HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(BITMAPINFO, bmiColors[256]));
476 if (!(info)) goto done;
477 info->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
478 info->bmiHeader.biWidth = bmWidth;
479 info->bmiHeader.biHeight = -bmHeight;
480 info->bmiHeader.biPlanes = 1;
481 info->bmiHeader.biBitCount = 32;
482 info->bmiHeader.biCompression = BI_RGB;
483 info->bmiHeader.biSizeImage = bmWidth * bmHeight * 4;
484 info->bmiHeader.biXPelsPerMeter = 0;
485 info->bmiHeader.biYPelsPerMeter = 0;
486 info->bmiHeader.biClrUsed = 0;
487 info->bmiHeader.biClrImportant = 0;
488 alpha = CreateDIBSection(hdc, info, DIB_RGB_COLORS, &bits, NULL, 0);
489 if (!(alpha)) goto done;
490
491 SelectObject( hdc, alpha );
492 StretchDIBits( hdc, 0, 0,bmWidth, bmHeight,
493 0, 0, src_info->bmiHeader.biWidth, src_info->bmiHeader.biHeight,
494 color_bits, src_info, DIB_RGB_COLORS, SRCCOPY );
495
496
497 /* pre-multiply by alpha */
498 for (i = 0, ptr = (unsigned char *)bits; i <bmWidth * bmHeight; i++, ptr += 4)
499 {
500 unsigned int alpha = ptr[3];
501 ptr[0] = ptr[0] * alpha / 255;
502 ptr[1] = ptr[1] * alpha / 255;
503 ptr[2] = ptr[2] * alpha / 255;
504 }
505
506done:
507 DeleteDC( hdc );
508 HeapFree( GetProcessHeap(), 0, info );
509 return alpha;
510}
511
512
513/***********************************************************************
514 * create_icon_from_bmi
515 *
516 * Create an icon from its BITMAPINFO.
517 */
518static HICON create_icon_from_bmi( const BITMAPINFO *bmi, DWORD maxsize, HMODULE module, LPCWSTR resname,
519 HRSRC rsrc, POINT hotspot, BOOL bIcon, INT width, INT height,
520 UINT cFlag )
521{
522 DWORD size, color_size, mask_size;
523 HBITMAP color = 0, mask = 0, alpha = 0;
524 const void *color_bits, *mask_bits;
525 BITMAPINFO *bmi_copy;
526 BOOL ret = FALSE;
527 BOOL do_stretch;
528 HICON hObj = 0;
529 HDC hdc = 0;
530
531 /* Check bitmap header */
532
533 if (maxsize < sizeof(BITMAPCOREHEADER))
534 {
535 return 0;
536 }
537 if (maxsize < bmi->bmiHeader.biSize)
538 {
539 WARN( "invalid header size %u\n", bmi->bmiHeader.biSize );
540 return 0;
541 }
542 if ( (bmi->bmiHeader.biSize != sizeof(BITMAPCOREHEADER)) &&
543 (bmi->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
544 (bmi->bmiHeader.biCompression != BI_RGB &&
545 bmi->bmiHeader.biCompression != BI_BITFIELDS)) )
546 {
547 WARN( "invalid bitmap header %u\n", bmi->bmiHeader.biSize );
548 return 0;
549 }
550
551 size = bitmap_info_size( bmi, DIB_RGB_COLORS );
552 color_size = get_dib_image_size( bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight / 2,
553 bmi->bmiHeader.biBitCount );
554 mask_size = get_dib_image_size( bmi->bmiHeader.biWidth, bmi->bmiHeader.biHeight / 2, 1 );
555 if (size > maxsize || color_size > maxsize - size)
556 {
557 WARN( "truncated file %u < %u+%u+%u\n", maxsize, size, color_size, mask_size );
558 return 0;
559 }
560 if (mask_size > maxsize - size - color_size) mask_size = 0; /* no mask */
561
562 if (cFlag & LR_DEFAULTSIZE)
563 {
564 if (!width) width = GetSystemMetrics( bIcon ? SM_CXICON : SM_CXCURSOR );
565 if (!height) height = GetSystemMetrics( bIcon ? SM_CYICON : SM_CYCURSOR );
566 }
567 else
568 {
569 if (!width) width = bmi->bmiHeader.biWidth;
570 if (!height) height = bmi->bmiHeader.biHeight/2;
571 }
572 do_stretch = (bmi->bmiHeader.biHeight/2 != height) ||
573 (bmi->bmiHeader.biWidth != width);
574
575 /* Scale the hotspot */
576 if (bIcon)
577 {
578 hotspot.x = width / 2;
579 hotspot.y = height / 2;
580 }
581 else if (do_stretch)
582 {
583 hotspot.x = (hotspot.x * width) / bmi->bmiHeader.biWidth;
584 hotspot.y = (hotspot.y * height) / (bmi->bmiHeader.biHeight / 2);
585 }
586
587 if (!screen_dc) screen_dc = CreateDCW( DISPLAYW, NULL, NULL, NULL );
588 if (!screen_dc) return 0;
589
590 bmi_copy = (BITMAPINFO*)HeapAlloc(GetProcessHeap(), 0, (std::max)((int)size, (int)FIELD_OFFSET(BITMAPINFO, bmiColors[2])));
591
592 if (!(bmi_copy))
593 return 0;
594 hdc = CreateCompatibleDC(0);
595 if (!(hdc)) goto done;
596
597 memcpy( bmi_copy, bmi, size );
598 bmi_copy->bmiHeader.biHeight /= 2;
599
600 color_bits = (const char*)bmi + size;
601 mask_bits = (const char*)color_bits + color_size;
602
603 alpha = 0;
604 if (is_dib_monochrome( bmi ))
605 {
606 mask = CreateBitmap(width, height * 2, 1, 1, NULL);
607 if (!(mask)) goto done;
608 color = 0;
609
610 /* copy color data into second half of mask bitmap */
611 SelectObject( hdc, mask );
612 StretchDIBits( hdc, 0, height, width, height,
613 0, 0, bmi_copy->bmiHeader.biWidth, bmi_copy->bmiHeader.biHeight,
614 color_bits, bmi_copy, DIB_RGB_COLORS, SRCCOPY );
615 }
616 else
617 {
618 mask = CreateBitmap(width, height, 1, 1, NULL);
619 if (!(mask)) goto done;
620 color = CreateBitmap(width, height, GetDeviceCaps(screen_dc, PLANES),
621 GetDeviceCaps(screen_dc, BITSPIXEL), NULL);
622 if (!(color))
623 {
624 DeleteObject( mask );
625 goto done;
626 }
627 SelectObject( hdc, color );
628 StretchDIBits( hdc, 0, 0, width, height,
629 0, 0, bmi_copy->bmiHeader.biWidth, bmi_copy->bmiHeader.biHeight,
630 color_bits, bmi_copy, DIB_RGB_COLORS, SRCCOPY );
631
632 if (bmi_has_alpha( bmi_copy, color_bits ))
633 alpha = create_alpha_bitmap(bmi_copy, color_bits ,width,height);
634
635 /* convert info to monochrome to copy the mask */
636 bmi_copy->bmiHeader.biBitCount = 1;
637 if (bmi_copy->bmiHeader.biSize != sizeof(BITMAPCOREHEADER))
638 {
639 RGBQUAD *rgb = bmi_copy->bmiColors;
640
641 bmi_copy->bmiHeader.biClrUsed = bmi_copy->bmiHeader.biClrImportant = 2;
642 rgb[0].rgbBlue = rgb[0].rgbGreen = rgb[0].rgbRed = 0x00;
643 rgb[1].rgbBlue = rgb[1].rgbGreen = rgb[1].rgbRed = 0xff;
644 rgb[0].rgbReserved = rgb[1].rgbReserved = 0;
645 }
646 else
647 {
648 RGBTRIPLE *rgb = (RGBTRIPLE *)(((BITMAPCOREHEADER *)bmi_copy) + 1);
649
650 rgb[0].rgbtBlue = rgb[0].rgbtGreen = rgb[0].rgbtRed = 0x00;
651 rgb[1].rgbtBlue = rgb[1].rgbtGreen = rgb[1].rgbtRed = 0xff;
652 }
653 }
654
655 if (mask_size)
656 {
657 SelectObject( hdc, mask );
658 StretchDIBits( hdc, 0, 0, width, height,
659 0, 0, bmi_copy->bmiHeader.biWidth, bmi_copy->bmiHeader.biHeight,
660 mask_bits, bmi_copy, DIB_RGB_COLORS, SRCCOPY );
661 }
662 ret = TRUE;
663
664done:
665 DeleteDC( hdc );
666 HeapFree( GetProcessHeap(), 0, bmi_copy );
667 if(ret)
668 {
669 ICONINFO iconInfo={0};
670 iconInfo.fIcon=bIcon;
671 iconInfo.xHotspot=hotspot.x;
672 iconInfo.yHotspot=hotspot.y;
673 if(alpha)
674 {
675 iconInfo.hbmColor=alpha;
676 iconInfo.hbmMask=mask;
677 }
678 else
679 {
680 iconInfo.hbmColor=color;
681 iconInfo.hbmMask=mask;
682 }
683
684 hObj=CreateIconIndirect(&iconInfo);
685 if(color) DeleteObject( color );
686 if(alpha) DeleteObject( alpha );
687 if(mask) DeleteObject( mask );
688 }
689 return hObj;
690}
691
692#define MYFIELD_OFFSET(type, field) ((LONG)(LONG_PTR)&(((type *)0)->field))
693
694HANDLE WINAPI LoadImageBuf(const void* bits, UINT filesize, UINT type,
695 INT width, INT height, UINT loadflags){
696 const CURSORICONFILEDIRENTRY *entry;
697 const CURSORICONFILEDIR *dir;
698 POINT hotspot;
699 INT depth=1;
700 if(type == IMAGE_BITMAP)
701 return 0;
702 BOOL fCursor = type == IMAGE_CURSOR?TRUE:FALSE;
703 /* Check for .ani. */
704 if (memcmp( bits, "RIFF", 4 ) == 0)
705 {//not support
706 return (HCURSOR)CreateIconFromResource((PBYTE)bits,filesize,FALSE,0x00030000);
707 }
708
709 dir = (const CURSORICONFILEDIR*) bits;
710 if ( filesize < MYFIELD_OFFSET( CURSORICONFILEDIR, idEntries[dir->idCount] ))
711 return 0;
712
713 if(!(loadflags & LR_MONOCHROME))
714 {
715 HDC hdc=GetDC(NULL);
716 depth=GetDeviceCaps(hdc,BITSPIXEL);
717 ReleaseDC(NULL,hdc);
718 }
719 if ( fCursor )
720 entry = CURSORICON_FindBestCursorFile( dir, filesize, width, height, depth, loadflags );
721 else
722 entry = CURSORICON_FindBestIconFile( dir, filesize, width, height, depth, loadflags );
723
724 /* check that we don't run off the end of the file */
725 if ( !entry || entry->dwDIBOffset > filesize || entry->dwDIBOffset + entry->dwDIBSize > filesize )
726 return 0;
727
728 hotspot.x = entry->xHotspot;
729 hotspot.y = entry->yHotspot;
730 return (HANDLE)create_icon_from_bmi( (const BITMAPINFO *)&((LPBYTE)bits)[entry->dwDIBOffset], filesize - entry->dwDIBOffset,
731 NULL, NULL, NULL, hotspot, !fCursor, width, height, loadflags );
732}