- Fixed few more bugs reported by Wine user32 window test. 4/373 tests fails now...
[reactos.git] / reactos / subsys / win32k / objects / bitmaps.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 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: bitmaps.c,v 1.44 2003/10/29 16:25:00 navaraf Exp $ */
20 #undef WIN32_LEAN_AND_MEAN
21 #include <windows.h>
22 #include <stdlib.h>
23 #include <win32k/color.h>
24 #include <win32k/gdiobj.h>
25 #include <win32k/bitmaps.h>
26 #include <win32k/brush.h>
27 //#include <win32k/debug.h>
28 #include "../eng/handle.h"
29 #include <include/inteng.h>
30 #include <include/eng.h>
31 #include <include/error.h>
32 #include <include/surface.h>
33 #include <include/palette.h>
34
35 #define NDEBUG
36 #include <win32k/debug1.h>
37
38 BOOL STDCALL NtGdiBitBlt(HDC hDCDest,
39 INT XDest,
40 INT YDest,
41 INT Width,
42 INT Height,
43 HDC hDCSrc,
44 INT XSrc,
45 INT YSrc,
46 DWORD ROP)
47 {
48 PDC DCDest = NULL;
49 PDC DCSrc = NULL;
50 PSURFOBJ SurfDest, SurfSrc;
51 PSURFGDI SurfGDIDest, SurfGDISrc;
52 RECTL DestRect;
53 POINTL SourcePoint;
54 BOOL Status;
55 PPALGDI PalDestGDI, PalSourceGDI;
56 PXLATEOBJ XlateObj = NULL;
57 HPALETTE SourcePalette, DestPalette;
58 ULONG SourceMode, DestMode;
59 PBRUSHOBJ BrushObj;
60 BOOL UsesSource = ((ROP & 0xCC0000) >> 2) != (ROP & 0x330000);
61 BOOL UsesPattern = ((ROP & 0xF00000) >> 4) != (ROP & 0x0F0000);
62
63 DCDest = DC_LockDc(hDCDest);
64 if (NULL == DCDest)
65 {
66 DPRINT1("Invalid destination dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCDest);
67 SetLastWin32Error(ERROR_INVALID_HANDLE);
68 return FALSE;
69 }
70
71 if (UsesSource)
72 {
73 if (hDCSrc != hDCDest)
74 {
75 DCSrc = DC_LockDc(hDCSrc);
76 if (NULL == DCSrc)
77 {
78 DC_UnlockDc(hDCDest);
79 DPRINT1("Invalid source dc handle (0x%08x) passed to NtGdiBitBlt\n", hDCSrc);
80 SetLastWin32Error(ERROR_INVALID_HANDLE);
81 return FALSE;
82 }
83 }
84 else
85 {
86 DCSrc = DCDest;
87 }
88 }
89 else
90 {
91 DCSrc = NULL;
92 }
93
94 /* Offset the destination and source by the origin of their DCs. */
95 XDest += DCDest->w.DCOrgX;
96 YDest += DCDest->w.DCOrgY;
97 if (UsesSource)
98 {
99 XSrc += DCSrc->w.DCOrgX;
100 YSrc += DCSrc->w.DCOrgY;
101 }
102
103 DestRect.left = XDest;
104 DestRect.top = YDest;
105 DestRect.right = XDest+Width;
106 DestRect.bottom = YDest+Height;
107
108 SourcePoint.x = XSrc;
109 SourcePoint.y = YSrc;
110
111 /* Determine surfaces to be used in the bitblt */
112 SurfDest = (PSURFOBJ)AccessUserObject((ULONG)DCDest->Surface);
113 SurfGDIDest = (PSURFGDI)AccessInternalObjectFromUserObject(SurfDest);
114 if (UsesSource)
115 {
116 SurfSrc = (PSURFOBJ)AccessUserObject((ULONG)DCSrc->Surface);
117 SurfGDISrc = (PSURFGDI)AccessInternalObjectFromUserObject(SurfSrc);
118 }
119 else
120 {
121 SurfSrc = NULL;
122 SurfGDISrc = NULL;
123 }
124
125 if (UsesPattern)
126 {
127 BrushObj = BRUSHOBJ_LockBrush(DCDest->w.hBrush);
128 if (NULL == BrushObj)
129 {
130 if (UsesSource && hDCSrc != hDCDest)
131 {
132 DC_UnlockDc(hDCSrc);
133 }
134 DC_UnlockDc(hDCDest);
135 SetLastWin32Error(ERROR_INVALID_HANDLE);
136 return FALSE;
137 }
138 }
139 else
140 {
141 BrushObj = NULL;
142 }
143
144 if (DCDest->w.hPalette != 0)
145 {
146 DestPalette = DCDest->w.hPalette;
147 }
148 else
149 {
150 DestPalette = NtGdiGetStockObject(DEFAULT_PALETTE);
151 }
152
153 if (UsesSource && DCSrc->w.hPalette != 0)
154 {
155 SourcePalette = DCSrc->w.hPalette;
156 }
157 else
158 {
159 SourcePalette = NtGdiGetStockObject(DEFAULT_PALETTE);
160 }
161
162 PalSourceGDI = PALETTE_LockPalette(SourcePalette);
163 if (NULL == PalSourceGDI)
164 {
165 if (UsesSource && hDCSrc != hDCDest)
166 {
167 DC_UnlockDc(hDCSrc);
168 }
169 DC_UnlockDc(hDCDest);
170 SetLastWin32Error(ERROR_INVALID_HANDLE);
171 return FALSE;
172 }
173 SourceMode = PalSourceGDI->Mode;
174 PALETTE_UnlockPalette(SourcePalette);
175
176 if (DestPalette == SourcePalette)
177 {
178 DestMode = SourceMode;
179 }
180 else
181 {
182 PalDestGDI = PALETTE_LockPalette(DestPalette);
183 if (NULL == PalDestGDI)
184 {
185 if (UsesSource && hDCSrc != hDCDest)
186 {
187 DC_UnlockDc(hDCSrc);
188 }
189 DC_UnlockDc(hDCDest);
190 SetLastWin32Error(ERROR_INVALID_HANDLE);
191 return FALSE;
192 }
193 DestMode = PalDestGDI->Mode;
194 PALETTE_UnlockPalette(DestPalette);
195 }
196
197 XlateObj = (PXLATEOBJ)IntEngCreateXlate(DestMode, SourceMode, DestPalette, SourcePalette);
198 if (NULL == XlateObj)
199 {
200 if (UsesSource && hDCSrc != hDCDest)
201 {
202 DC_UnlockDc(hDCSrc);
203 }
204 DC_UnlockDc(hDCDest);
205 SetLastWin32Error(ERROR_NO_SYSTEM_RESOURCES);
206 return FALSE;
207 }
208
209 /* Perform the bitblt operation */
210 Status = IntEngBitBlt(SurfDest, SurfSrc, NULL, DCDest->CombinedClip, XlateObj,
211 &DestRect, &SourcePoint, NULL, BrushObj, NULL, ROP);
212
213 EngDeleteXlate(XlateObj);
214 if (UsesPattern)
215 {
216 BRUSHOBJ_UnlockBrush(DCDest->w.hBrush);
217 }
218 if (UsesSource && hDCSrc != hDCDest)
219 {
220 DC_UnlockDc(hDCSrc);
221 }
222 DC_UnlockDc(hDCDest);
223
224 return Status;
225 }
226
227 HBITMAP STDCALL NtGdiCreateBitmap(INT Width,
228 INT Height,
229 UINT Planes,
230 UINT BitsPerPel,
231 CONST VOID *Bits)
232 {
233 PBITMAPOBJ bmp;
234 HBITMAP hBitmap;
235
236 Planes = (BYTE) Planes;
237 BitsPerPel = (BYTE) BitsPerPel;
238
239 /* Check parameters */
240 if (!Height || !Width)
241 {
242 return 0;
243 }
244 if (Planes != 1)
245 {
246 UNIMPLEMENTED;
247 return 0;
248 }
249 if (Height < 0)
250 {
251 Height = -Height;
252 }
253 if (Width < 0)
254 {
255 Width = -Width;
256 }
257
258 /* Create the BITMAPOBJ */
259 hBitmap = BITMAPOBJ_AllocBitmap ();
260 if (!hBitmap)
261 {
262 DPRINT("NtGdiCreateBitmap: BITMAPOBJ_AllocBitmap returned 0\n");
263 return 0;
264 }
265
266 bmp = BITMAPOBJ_LockBitmap( hBitmap );
267
268 DPRINT("NtGdiCreateBitmap:%dx%d, %d (%d BPP) colors returning %08x\n", Width, Height,
269 1 << (Planes * BitsPerPel), BitsPerPel, bmp);
270
271 bmp->size.cx = Width;
272 bmp->size.cy = Height;
273 bmp->bitmap.bmType = 0;
274 bmp->bitmap.bmWidth = Width;
275 bmp->bitmap.bmHeight = Height;
276 bmp->bitmap.bmPlanes = Planes;
277 bmp->bitmap.bmBitsPixel = BitsPerPel;
278 bmp->bitmap.bmWidthBytes = BITMAPOBJ_GetWidthBytes (Width, BitsPerPel);
279 bmp->bitmap.bmBits = NULL;
280 bmp->DDBitmap = NULL;
281 bmp->dib = NULL;
282
283 // Allocate memory for bitmap bits
284 bmp->bitmap.bmBits = ExAllocatePool(PagedPool, bmp->bitmap.bmWidthBytes * bmp->bitmap.bmHeight);
285
286 BITMAPOBJ_UnlockBitmap( hBitmap );
287
288 if (Bits) /* Set bitmap bits */
289 {
290 NtGdiSetBitmapBits(hBitmap, Height * bmp->bitmap.bmWidthBytes, Bits);
291 }
292
293 return hBitmap;
294 }
295
296 BOOL FASTCALL Bitmap_InternalDelete( PBITMAPOBJ pBmp )
297 {
298 ASSERT( pBmp );
299
300 if (NULL != pBmp->bitmap.bmBits)
301 {
302 if (NULL != pBmp->dib)
303 {
304 if (NULL == pBmp->dib->dshSection)
305 {
306 EngFreeUserMem(pBmp->bitmap.bmBits);
307 }
308 else
309 {
310 /* This is a file-mapped section */
311 UNIMPLEMENTED;
312 }
313 }
314 else
315 {
316 ExFreePool(pBmp->bitmap.bmBits);
317 }
318 }
319
320 return TRUE;
321 }
322
323
324 HBITMAP STDCALL NtGdiCreateCompatibleBitmap(HDC hDC,
325 INT Width,
326 INT Height)
327 {
328 HBITMAP hbmpRet;
329 PDC dc;
330
331 hbmpRet = 0;
332 dc = DC_LockDc(hDC);
333
334 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n", hDC, Width, Height, dc->w.bitsPerPixel);
335
336 if (!dc)
337 {
338 return 0;
339 }
340 if ((Width >= 0x10000) || (Height >= 0x10000))
341 {
342 DPRINT("got bad width %d or height %d, please look for reason\n", Width, Height);
343 }
344 else
345 {
346 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
347 if (!Width || !Height)
348 {
349 hbmpRet = NtGdiCreateBitmap (1, 1, 1, 1, NULL);
350 }
351 else
352 {
353 hbmpRet = NtGdiCreateBitmap(Width, Height, 1, dc->w.bitsPerPixel, NULL);
354 }
355 }
356 DPRINT ("\t\t%04x\n", hbmpRet);
357 DC_UnlockDc( hDC );
358 return hbmpRet;
359 }
360
361 HBITMAP STDCALL NtGdiCreateBitmapIndirect(CONST BITMAP *BM)
362 {
363 return NtGdiCreateBitmap (BM->bmWidth,
364 BM->bmHeight,
365 BM->bmPlanes,
366 BM->bmBitsPixel,
367 BM->bmBits);
368 }
369
370 HBITMAP STDCALL NtGdiCreateDiscardableBitmap(HDC hDC,
371 INT Width,
372 INT Height)
373 {
374 /* FIXME: this probably should do something else */
375 return NtGdiCreateCompatibleBitmap(hDC, Width, Height);
376 }
377
378 BOOL STDCALL NtGdiExtFloodFill(HDC hDC,
379 INT XStart,
380 INT YStart,
381 COLORREF Color,
382 UINT FillType)
383 {
384 UNIMPLEMENTED;
385 }
386
387 BOOL STDCALL NtGdiFloodFill(HDC hDC,
388 INT XStart,
389 INT YStart,
390 COLORREF Fill)
391 {
392 UNIMPLEMENTED;
393 }
394
395 BOOL STDCALL NtGdiGetBitmapDimensionEx(HBITMAP hBitmap,
396 LPSIZE Dimension)
397 {
398 PBITMAPOBJ bmp;
399
400 bmp = BITMAPOBJ_LockBitmap(hBitmap);
401 if (bmp == NULL)
402 {
403 return FALSE;
404 }
405
406 *Dimension = bmp->size;
407
408 BITMAPOBJ_UnlockBitmap(hBitmap);
409
410 return TRUE;
411 }
412
413 COLORREF STDCALL NtGdiGetPixel(HDC hDC,
414 INT XPos,
415 INT YPos)
416 {
417 PDC dc = NULL;
418 COLORREF cr = (COLORREF) 0;
419
420 dc = DC_LockDc (hDC);
421 if (NULL == dc)
422 {
423 return (COLORREF) CLR_INVALID;
424 }
425 //FIXME: get actual pixel RGB value
426 DC_UnlockDc (hDC);
427 return cr;
428 }
429
430 BOOL STDCALL NtGdiMaskBlt(HDC hDCDest,
431 INT XDest,
432 INT YDest,
433 INT Width,
434 INT Height,
435 HDC hDCSrc,
436 INT XSrc,
437 INT YSrc,
438 HBITMAP hMaskBitmap,
439 INT xMask,
440 INT yMask,
441 DWORD ROP)
442 {
443 UNIMPLEMENTED;
444 }
445
446 BOOL STDCALL NtGdiPlgBlt(HDC hDCDest,
447 CONST POINT *Point,
448 HDC hDCSrc,
449 INT XSrc,
450 INT YSrc,
451 INT Width,
452 INT Height,
453 HBITMAP hMaskBitmap,
454 INT xMask,
455 INT yMask)
456 {
457 UNIMPLEMENTED;
458 }
459
460 LONG STDCALL NtGdiSetBitmapBits(HBITMAP hBitmap,
461 DWORD Bytes,
462 CONST VOID *Bits)
463 {
464 LONG height, ret;
465 PBITMAPOBJ bmp;
466
467 bmp = BITMAPOBJ_LockBitmap(hBitmap);
468 if (bmp == NULL || Bits == NULL)
469 {
470 return 0;
471 }
472
473 if (Bytes < 0)
474 {
475 DPRINT ("(%ld): Negative number of bytes passed???\n", Bytes );
476 Bytes = -Bytes;
477 }
478
479 /* Only get entire lines */
480 height = Bytes / bmp->bitmap.bmWidthBytes;
481 if (height > bmp->bitmap.bmHeight)
482 {
483 height = bmp->bitmap.bmHeight;
484 }
485 Bytes = height * bmp->bitmap.bmWidthBytes;
486 DPRINT ("(%08x, bytes:%ld, bits:%p) %dx%d %d colors fetched height: %ld\n",
487 hBitmap,
488 Bytes,
489 Bits,
490 bmp->bitmap.bmWidth,
491 bmp->bitmap.bmHeight,
492 1 << bmp->bitmap.bmBitsPixel,
493 height);
494
495 #if 0
496 /* FIXME: call DDI specific function here if available */
497 if(bmp->DDBitmap)
498 {
499 DPRINT ("Calling device specific BitmapBits\n");
500 if (bmp->DDBitmap->funcs->pBitmapBits)
501 {
502 ret = bmp->DDBitmap->funcs->pBitmapBits(hBitmap, (void *) Bits, Bytes, DDB_SET);
503 }
504 else
505 {
506 DPRINT ("BitmapBits == NULL??\n");
507 ret = 0;
508 }
509 }
510 else
511 #endif
512 {
513 /* FIXME: Alloc enough for entire bitmap */
514 if (bmp->bitmap.bmBits == NULL)
515 {
516 bmp->bitmap.bmBits = ExAllocatePool (PagedPool, Bytes);
517 }
518 if(!bmp->bitmap.bmBits)
519 {
520 DPRINT ("Unable to allocate bit buffer\n");
521 ret = 0;
522 }
523 else
524 {
525 memcpy(bmp->bitmap.bmBits, Bits, Bytes);
526 ret = Bytes;
527 }
528 }
529
530 BITMAPOBJ_UnlockBitmap(hBitmap);
531
532 return ret;
533 }
534
535 BOOL STDCALL NtGdiSetBitmapDimensionEx(HBITMAP hBitmap,
536 INT Width,
537 INT Height,
538 LPSIZE Size)
539 {
540 PBITMAPOBJ bmp;
541
542 bmp = BITMAPOBJ_LockBitmap(hBitmap);
543 if (bmp == NULL)
544 {
545 return FALSE;
546 }
547
548 if (Size)
549 {
550 *Size = bmp->size;
551 }
552 bmp->size.cx = Width;
553 bmp->size.cy = Height;
554
555 BITMAPOBJ_UnlockBitmap (hBitmap);
556
557 return TRUE;
558 }
559
560 COLORREF STDCALL NtGdiSetPixel(HDC hDC,
561 INT X,
562 INT Y,
563 COLORREF Color)
564 {
565 COLORREF cr = NtGdiGetPixel(hDC,X,Y);
566 if(cr != CLR_INVALID && NtGdiSetPixelV(hDC,X,Y,Color))
567 {
568 return(cr);
569 }
570 return ((COLORREF) -1);
571 }
572
573 BOOL STDCALL NtGdiSetPixelV(HDC hDC,
574 INT X,
575 INT Y,
576 COLORREF Color)
577 {
578 HBRUSH NewBrush = NtGdiCreateSolidBrush(Color);
579 HGDIOBJ OldBrush;
580
581 if (NewBrush == NULL)
582 return(FALSE);
583 OldBrush = NtGdiSelectObject(hDC, NewBrush);
584 if (OldBrush == NULL)
585 return(FALSE);
586 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
587 NtGdiSelectObject(hDC, OldBrush);
588 NtGdiDeleteObject(NewBrush);
589 return TRUE;
590 }
591
592 BOOL STDCALL NtGdiStretchBlt(HDC hDCDest,
593 INT XOriginDest,
594 INT YOriginDest,
595 INT WidthDest,
596 INT HeightDest,
597 HDC hDCSrc,
598 INT XOriginSrc,
599 INT YOriginSrc,
600 INT WidthSrc,
601 INT HeightSrc,
602 DWORD ROP)
603 {
604 UNIMPLEMENTED;
605 }
606
607 /* Internal Functions */
608
609 INT FASTCALL
610 BITMAPOBJ_GetWidthBytes (INT bmWidth, INT bpp)
611 {
612 #if 0
613 switch(bpp)
614 {
615 case 1:
616 return 2 * ((bmWidth+15) >> 4);
617
618 case 24:
619 bmWidth *= 3; /* fall through */
620 case 8:
621 return bmWidth + (bmWidth & 1);
622
623 case 32:
624 return bmWidth * 4;
625
626 case 16:
627 case 15:
628 return bmWidth * 2;
629
630 case 4:
631 return 2 * ((bmWidth+3) >> 2);
632
633 default:
634 DPRINT ("stub");
635 }
636
637 return -1;
638 #endif
639
640 return ((bmWidth * bpp + 31) & ~31) >> 3;
641 }
642
643 HBITMAP FASTCALL BITMAPOBJ_CopyBitmap(HBITMAP hBitmap)
644 {
645 PBITMAPOBJ bmp;
646 HBITMAP res;
647 BITMAP bm;
648
649 bmp = BITMAPOBJ_LockBitmap(hBitmap);
650 if (bmp == NULL)
651 {
652 return 0;
653 }
654 res = 0;
655
656 bm = bmp->bitmap;
657 bm.bmBits = NULL;
658 BITMAPOBJ_UnlockBitmap(hBitmap);
659 res = NtGdiCreateBitmapIndirect(&bm);
660 if(res)
661 {
662 char *buf;
663
664 buf = ExAllocatePool (NonPagedPool, bm.bmWidthBytes * bm.bmHeight);
665 NtGdiGetBitmapBits (hBitmap, bm.bmWidthBytes * bm.bmHeight, buf);
666 NtGdiSetBitmapBits (res, bm.bmWidthBytes * bm.bmHeight, buf);
667 ExFreePool (buf);
668 }
669
670 return res;
671 }
672
673 INT STDCALL BITMAP_GetObject(BITMAPOBJ * bmp, INT count, LPVOID buffer)
674 {
675 if(bmp->dib)
676 {
677 if(count < (INT) sizeof(DIBSECTION))
678 {
679 if (count > (INT) sizeof(BITMAP)) count = sizeof(BITMAP);
680 }
681 else
682 {
683 if (count > (INT) sizeof(DIBSECTION)) count = sizeof(DIBSECTION);
684 }
685 memcpy(buffer, bmp->dib, count);
686 return count;
687 }
688 else
689 {
690 if (count > (INT) sizeof(BITMAP)) count = sizeof(BITMAP);
691 memcpy(buffer, &bmp->bitmap, count);
692 return count;
693 }
694 }
695 /* EOF */