reshuffling of dlls
[reactos.git] / reactos / dll / user32 / windows / bitmap.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/input.c
23 * PURPOSE: Input
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * UPDATE HISTORY:
26 * 09-05-2001 CSH Created
27 */
28
29 /* INCLUDES ******************************************************************/
30
31 #include <user32.h>
32
33 #include "pshpack1.h"
34
35 typedef 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
46 typedef struct
47 {
48 WORD idReserved;
49 WORD idType;
50 WORD idCount;
51 CURSORICONFILEDIRENTRY idEntries[1];
52 } CURSORICONFILEDIR;
53
54 #include "poppack.h"
55
56 /*forward declerations... actualy in user32\windows\icon.c but usful here****/
57 HICON ICON_CreateCursorFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
58 HICON ICON_CreateIconFromData(HDC hDC, PVOID ImageData, ICONIMAGE* IconImage, int cxDesired, int cyDesired, int xHotspot, int yHotspot);
59 CURSORICONDIRENTRY *CURSORICON_FindBestIcon( CURSORICONDIR *dir, int width, int height, int colors);
60 CURSORICONDIRENTRY *CURSORICON_FindBestCursor( CURSORICONDIR *dir, int width, int height, int colors);
61
62 /* FUNCTIONS *****************************************************************/
63
64 /*
65 * @implemented
66 */
67 HANDLE STDCALL
68 LoadImageA(HINSTANCE hinst,
69 LPCSTR lpszName,
70 UINT uType,
71 int cxDesired,
72 int cyDesired,
73 UINT fuLoad)
74 {
75 LPWSTR lpszWName;
76 HANDLE Handle;
77 UNICODE_STRING NameString;
78
79 if (HIWORD(lpszName))
80 {
81 RtlCreateUnicodeStringFromAsciiz(&NameString, (LPSTR)lpszName);
82 lpszWName = NameString.Buffer;
83 Handle = LoadImageW(hinst, lpszWName, uType, cxDesired,
84 cyDesired, fuLoad);
85 RtlFreeUnicodeString(&NameString);
86 }
87 else
88 {
89 Handle = LoadImageW(hinst, (LPCWSTR)lpszName, uType, cxDesired,
90 cyDesired, fuLoad);
91 }
92
93 return Handle;
94 }
95
96
97 /*
98 * The following macro functions account for the irregularities of
99 * accessing cursor and icon resources in files and resource entries.
100 */
101 typedef BOOL (*fnGetCIEntry)( LPVOID dir, int n,
102 int *width, int *height, int *bits );
103
104 /**********************************************************************
105 * CURSORICON_FindBestCursor2
106 *
107 * Find the cursor closest to the requested size.
108 * FIXME: parameter 'color' ignored and entries with more than 1 bpp
109 * ignored too
110 */
111 static int CURSORICON_FindBestCursor2( LPVOID dir, fnGetCIEntry get_entry,
112 int width, int height, int color )
113 {
114 int i, maxwidth, maxheight, cx, cy, bits, bestEntry = -1;
115
116 /* Double height to account for AND and XOR masks */
117
118 height *= 2;
119
120 /* First find the largest one smaller than or equal to the requested size*/
121
122 maxwidth = maxheight = 0;
123 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
124 {
125 if ((cx <= width) && (cy <= height) &&
126 (cx > maxwidth) && (cy > maxheight) &&
127 (bits == 1))
128 {
129 bestEntry = i;
130 maxwidth = cx;
131 maxheight = cy;
132 }
133 }
134 if (bestEntry != -1) return bestEntry;
135
136 /* Now find the smallest one larger than the requested size */
137
138 maxwidth = maxheight = 255;
139 for ( i = 0; get_entry( dir, i, &cx, &cy, &bits ); i++ )
140 {
141 if (((cx < maxwidth) && (cy < maxheight) && (bits == 1)) ||
142 (bestEntry==-1))
143 {
144 bestEntry = i;
145 maxwidth = cx;
146 maxheight = cy;
147 }
148 }
149
150 return bestEntry;
151 }
152
153 static BOOL CURSORICON_GetFileEntry( LPVOID dir, int n,
154 int *width, int *height, int *bits )
155 {
156 CURSORICONFILEDIR *filedir = dir;
157 CURSORICONFILEDIRENTRY *entry;
158
159 if ( filedir->idCount <= n )
160 return FALSE;
161 entry = &filedir->idEntries[n];
162 *width = entry->bWidth;
163 *height = entry->bHeight;
164 *bits = entry->bColorCount;
165 return TRUE;
166 }
167
168 static CURSORICONFILEDIRENTRY *CURSORICON_FindBestCursorFile( CURSORICONFILEDIR *dir,
169 int width, int height, int color )
170 {
171 int n = CURSORICON_FindBestCursor2( dir, CURSORICON_GetFileEntry,
172 width, height, color );
173 if ( n < 0 )
174 return NULL;
175 return &dir->idEntries[n];
176 }
177
178 static HANDLE
179 LoadCursorIconImage(
180 HINSTANCE hinst,
181 LPCWSTR lpszName,
182 INT width,
183 INT height,
184 UINT fuLoad,
185 ULONG uType)
186 {
187 HANDLE hResource;
188 HANDLE h2Resource;
189 HANDLE hfRes;
190 HANDLE hFile;
191 HANDLE hSection;
192 CURSORICONFILEDIR *IconDIR;
193 HDC hScreenDc;
194 HICON hIcon;
195 ULONG HeaderSize;
196 ULONG ColorCount;
197 ULONG ColorBits;
198 PVOID Data;
199 CURSORICONFILEDIRENTRY* dirEntry;
200 ICONIMAGE* SafeIconImage = NULL;
201 GRPCURSORICONDIR* IconResDir;
202 INT id;
203 ICONIMAGE *ResIcon;
204 BOOL Icon = (uType == IMAGE_ICON);
205 DWORD filesize = 0;
206
207 if (!(fuLoad & LR_LOADFROMFILE))
208 {
209 if (hinst == NULL)
210 hinst = User32Instance;
211
212 hResource = hfRes = FindResourceW(hinst, lpszName,
213 Icon ? RT_GROUP_ICON : RT_GROUP_CURSOR);
214 if (hResource == NULL)
215 return NULL;
216
217 if (fuLoad & LR_SHARED)
218 {
219 hIcon = NtUserFindExistingCursorIcon(hinst, (HRSRC)hfRes, width, height);
220 if (hIcon)
221 return hIcon;
222 }
223
224 hResource = LoadResource(hinst, hResource);
225 if (hResource == NULL)
226 return NULL;
227
228 IconResDir = LockResource(hResource);
229 if (IconResDir == NULL)
230 return NULL;
231
232 /*
233 * Find the best fitting in the IconResDir for this resolution
234 */
235
236 id = LookupIconIdFromDirectoryEx((PBYTE)IconResDir, Icon, width, height,
237 fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
238
239 h2Resource = FindResourceW(hinst, MAKEINTRESOURCEW(id),
240 Icon ? MAKEINTRESOURCEW(RT_ICON) :
241 MAKEINTRESOURCEW(RT_CURSOR));
242 if (h2Resource == NULL)
243 return NULL;
244
245 hResource = LoadResource(hinst, h2Resource);
246 if (hResource == NULL)
247 return NULL;
248
249 ResIcon = LockResource(hResource);
250 if (ResIcon == NULL)
251 return NULL;
252
253 hIcon = CreateIconFromResourceEx((PBYTE)ResIcon,
254 SizeofResource(hinst, h2Resource),
255 Icon, 0x00030000, width, height,
256 fuLoad & (LR_DEFAULTCOLOR | LR_MONOCHROME));
257 if (hIcon && 0 != (fuLoad & LR_SHARED))
258 {
259 NtUserSetCursorIconData((HICON)hIcon, NULL, NULL, hinst, (HRSRC)hfRes,
260 (HRSRC)NULL);
261 }
262
263 return hIcon;
264 }
265
266 if (fuLoad & LR_SHARED)
267 {
268 DbgPrint("FIXME: need LR_SHARED support for loading icon images from files\n");
269 }
270
271 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
272 OPEN_EXISTING, 0, NULL);
273 if (hFile == INVALID_HANDLE_VALUE)
274 return NULL;
275
276 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
277 filesize = GetFileSize( hFile, NULL );
278 CloseHandle(hFile);
279 if (hSection == NULL)
280 return NULL;
281
282 IconDIR = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
283 CloseHandle(hSection);
284 if (IconDIR == NULL)
285 return NULL;
286
287 if (0 != IconDIR->idReserved ||
288 (IMAGE_ICON != IconDIR->idType && IMAGE_CURSOR != IconDIR->idType))
289 {
290 UnmapViewOfFile(IconDIR);
291 return NULL;
292 }
293
294 /* Get a handle to the screen dc, the icon we create is going to be
295 * compatable with this. */
296 hScreenDc = CreateDCW(NULL, NULL, NULL, NULL);
297 if (hScreenDc == NULL)
298 {
299 UnmapViewOfFile(IconDIR);
300 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
301 return NULL;
302 }
303
304 if (fuLoad & LR_MONOCHROME)
305 {
306 ColorBits = 1;
307 }
308 else
309 {
310 ColorBits = GetDeviceCaps(hScreenDc, BITSPIXEL);
311 /*
312 * FIXME:
313 * Remove this after proper support for alpha icons will be finished.
314 */
315 if (ColorBits > 8)
316 ColorBits = 8;
317 }
318
319 /* Pick the best size. */
320 dirEntry = CURSORICON_FindBestCursorFile( IconDIR, width, height, ColorBits );
321 if (!dirEntry)
322 {
323 DeleteDC(hScreenDc);
324 UnmapViewOfFile(IconDIR);
325 return NULL;
326 }
327
328 if ( dirEntry->dwDIBOffset > filesize )
329 {
330 DeleteDC(hScreenDc);
331 UnmapViewOfFile(IconDIR);
332 return NULL;
333 }
334
335 if ( dirEntry->dwDIBOffset + dirEntry->dwDIBSize > filesize ){
336 DeleteDC(hScreenDc);
337 UnmapViewOfFile(IconDIR);
338 return NULL;
339 }
340
341 SafeIconImage = RtlAllocateHeap(GetProcessHeap(), 0, dirEntry->dwDIBSize);
342 if (SafeIconImage == NULL)
343 {
344 DeleteDC(hScreenDc);
345 UnmapViewOfFile(IconDIR);
346 return NULL;
347 }
348
349 memcpy(SafeIconImage, ((PBYTE)IconDIR) + dirEntry->dwDIBOffset, dirEntry->dwDIBSize);
350 UnmapViewOfFile(IconDIR);
351
352 /* At this point we have a copy of the icon image to play with. */
353
354 SafeIconImage->icHeader.biHeight = SafeIconImage->icHeader.biHeight /2;
355
356 if (SafeIconImage->icHeader.biSize == sizeof(BITMAPCOREHEADER))
357 {
358 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)SafeIconImage;
359 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
360 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
361 }
362 else
363 {
364 ColorCount = SafeIconImage->icHeader.biClrUsed;
365 if (ColorCount == 0 && SafeIconImage->icHeader.biBitCount <= 8)
366 ColorCount = 1 << SafeIconImage->icHeader.biBitCount;
367 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
368 }
369
370 /* Make data point to the start of the XOR image data. */
371 Data = (PBYTE)SafeIconImage + HeaderSize;
372
373 hIcon = ICON_CreateIconFromData(hScreenDc, Data, SafeIconImage, width, height, width/2, height/2);
374 RtlFreeHeap(GetProcessHeap(), 0, SafeIconImage);
375 DeleteDC(hScreenDc);
376
377 return hIcon;
378 }
379
380
381 static HANDLE
382 LoadBitmapImage(HINSTANCE hInstance, LPCWSTR lpszName, UINT fuLoad)
383 {
384 HANDLE hResource;
385 HANDLE hFile;
386 HANDLE hSection;
387 LPBITMAPINFO BitmapInfo;
388 LPBITMAPINFO PrivateInfo;
389 HDC hScreenDc;
390 HANDLE hBitmap;
391 ULONG HeaderSize;
392 ULONG ColorCount;
393 PVOID Data;
394
395 if (!(fuLoad & LR_LOADFROMFILE))
396 {
397 if (hInstance == NULL)
398 hInstance = User32Instance;
399
400 hResource = FindResourceW(hInstance, lpszName, RT_BITMAP);
401 if (hResource == NULL)
402 return NULL;
403 hResource = LoadResource(hInstance, hResource);
404 if (hResource == NULL)
405 return NULL;
406 BitmapInfo = LockResource(hResource);
407 if (BitmapInfo == NULL)
408 return NULL;
409 }
410 else
411 {
412 hFile = CreateFileW(lpszName, GENERIC_READ, FILE_SHARE_READ, NULL,
413 OPEN_EXISTING, 0, NULL);
414 if (hFile == INVALID_HANDLE_VALUE)
415 return NULL;
416
417 hSection = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
418 CloseHandle(hFile);
419 if (hSection == NULL)
420 return NULL;
421
422 BitmapInfo = MapViewOfFile(hSection, FILE_MAP_READ, 0, 0, 0);
423 CloseHandle(hSection);
424 if (BitmapInfo == NULL)
425 return NULL;
426
427 BitmapInfo = (LPBITMAPINFO)((ULONG_PTR)BitmapInfo + sizeof(BITMAPFILEHEADER));
428 }
429
430 if (BitmapInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
431 {
432 BITMAPCOREHEADER* Core = (BITMAPCOREHEADER*)BitmapInfo;
433 ColorCount = (Core->bcBitCount <= 8) ? (1 << Core->bcBitCount) : 0;
434 HeaderSize = sizeof(BITMAPCOREHEADER) + ColorCount * sizeof(RGBTRIPLE);
435 }
436 else
437 {
438 ColorCount = BitmapInfo->bmiHeader.biClrUsed;
439 if (ColorCount == 0 && BitmapInfo->bmiHeader.biBitCount <= 8)
440 ColorCount = 1 << BitmapInfo->bmiHeader.biBitCount;
441 HeaderSize = sizeof(BITMAPINFOHEADER) + ColorCount * sizeof(RGBQUAD);
442 }
443 Data = (PVOID)((ULONG_PTR)BitmapInfo + HeaderSize);
444
445 PrivateInfo = RtlAllocateHeap(GetProcessHeap(), 0, HeaderSize);
446 if (PrivateInfo == NULL)
447 {
448 if (fuLoad & LR_LOADFROMFILE)
449 UnmapViewOfFile(BitmapInfo);
450 return NULL;
451 }
452 memcpy(PrivateInfo, BitmapInfo, HeaderSize);
453
454 /* FIXME: Handle color conversion and transparency. */
455
456 hScreenDc = CreateCompatibleDC(NULL);
457 if (hScreenDc == NULL)
458 {
459 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
460 if (fuLoad & LR_LOADFROMFILE)
461 UnmapViewOfFile(BitmapInfo);
462 return NULL;
463 }
464
465 if (fuLoad & LR_CREATEDIBSECTION)
466 {
467 DIBSECTION Dib;
468
469 hBitmap = CreateDIBSection(hScreenDc, PrivateInfo, DIB_RGB_COLORS, NULL,
470 0, 0);
471 GetObjectA(hBitmap, sizeof(DIBSECTION), &Dib);
472 SetDIBits(hScreenDc, hBitmap, 0, Dib.dsBm.bmHeight, Data, BitmapInfo,
473 DIB_RGB_COLORS);
474 }
475 else
476 {
477 hBitmap = CreateDIBitmap(hScreenDc, &PrivateInfo->bmiHeader, CBM_INIT,
478 Data, PrivateInfo, DIB_RGB_COLORS);
479 }
480
481 RtlFreeHeap(GetProcessHeap(), 0, PrivateInfo);
482 DeleteDC(hScreenDc);
483 if (fuLoad & LR_LOADFROMFILE)
484 UnmapViewOfFile(BitmapInfo);
485
486 return hBitmap;
487 }
488
489 HANDLE STDCALL
490 LoadImageW(
491 IN HINSTANCE hinst,
492 IN LPCWSTR lpszName,
493 IN UINT uType,
494 IN INT cxDesired,
495 IN INT cyDesired,
496 IN UINT fuLoad)
497 {
498 if (fuLoad & LR_DEFAULTSIZE)
499 {
500 if (uType == IMAGE_ICON)
501 {
502 if (cxDesired == 0)
503 cxDesired = GetSystemMetrics(SM_CXICON);
504 if (cyDesired == 0)
505 cyDesired = GetSystemMetrics(SM_CYICON);
506 }
507 else if (uType == IMAGE_CURSOR)
508 {
509 if (cxDesired == 0)
510 cxDesired = GetSystemMetrics(SM_CXCURSOR);
511 if (cyDesired == 0)
512 cyDesired = GetSystemMetrics(SM_CYCURSOR);
513 }
514 }
515
516 switch (uType)
517 {
518 case IMAGE_BITMAP:
519 return LoadBitmapImage(hinst, lpszName, fuLoad);
520 case IMAGE_CURSOR:
521 case IMAGE_ICON:
522 return LoadCursorIconImage(hinst, lpszName, cxDesired, cyDesired,
523 fuLoad, uType);
524 default:
525 break;
526 }
527
528 return NULL;
529 }
530
531
532 /*
533 * @implemented
534 */
535 HBITMAP STDCALL
536 LoadBitmapA(HINSTANCE hInstance, LPCSTR lpBitmapName)
537 {
538 return LoadImageA(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
539 }
540
541
542 /*
543 * @implemented
544 */
545 HBITMAP STDCALL
546 LoadBitmapW(HINSTANCE hInstance, LPCWSTR lpBitmapName)
547 {
548 return LoadImageW(hInstance, lpBitmapName, IMAGE_BITMAP, 0, 0, 0);
549 }
550
551
552 /*
553 * @unimplemented
554 */
555 HANDLE WINAPI
556 CopyImage(
557 IN HANDLE hnd,
558 IN UINT type,
559 IN INT desiredx,
560 IN INT desiredy,
561 IN UINT flags)
562 {
563 HBITMAP res;
564 BITMAP bm;
565
566 switch (type)
567 {
568 case IMAGE_BITMAP:
569 {
570 DbgPrint("WARNING: Incomplete implementation of CopyImage!\n");
571 /*
572 * FIXME: Support flags LR_COPYDELETEORG, LR_COPYFROMRESOURCE,
573 * LR_COPYRETURNORG, LR_CREATEDIBSECTION and LR_MONOCHROME.
574 */
575 if (!GetObjectW(hnd, sizeof(bm), &bm))
576 return NULL;
577 bm.bmBits = NULL;
578 if ((res = CreateBitmapIndirect(&bm)))
579 {
580 char *buf = HeapAlloc(GetProcessHeap(), 0, bm.bmWidthBytes * bm.bmHeight);
581 if (buf == NULL)
582 {
583 DeleteObject(res);
584 return NULL;
585 }
586 GetBitmapBits(hnd, bm.bmWidthBytes * bm.bmHeight, buf);
587 SetBitmapBits(res, bm.bmWidthBytes * bm.bmHeight, buf);
588 HeapFree(GetProcessHeap(), 0, buf);
589 }
590 return res;
591 }
592
593 case IMAGE_ICON:
594 {
595 static BOOL IconMsgDisplayed = FALSE;
596 /* FIXME: support loading the image as shared from an instance */
597 if (!IconMsgDisplayed)
598 {
599 DbgPrint("FIXME: CopyImage doesn't support IMAGE_ICON correctly!\n");
600 IconMsgDisplayed = TRUE;
601 }
602 return CopyIcon(hnd);
603 }
604
605 case IMAGE_CURSOR:
606 {
607 static BOOL IconMsgDisplayed = FALSE;
608 /* FIXME: support loading the image as shared from an instance */
609 if (!IconMsgDisplayed)
610 {
611 DbgPrint("FIXME: CopyImage doesn't support IMAGE_CURSOR correctly!\n");
612 IconMsgDisplayed = TRUE;
613 }
614 return CopyCursor(hnd);
615 }
616 }
617
618 return NULL;
619 }