Bye, bye, GDIOBJ header! You've served us well, but now the time has come for you...
[reactos.git] / reactos / subsystems / win32 / 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$ */
20
21 #include <w32k.h>
22
23 #define NDEBUG
24 #include <debug.h>
25
26 #define IN_RECT(r,x,y) \
27 ( \
28 (x) >= (r).left && \
29 (y) >= (r).top && \
30 (x) < (r).right && \
31 (y) < (r).bottom \
32 )
33
34 HBITMAP STDCALL
35 IntGdiCreateBitmap(
36 INT Width,
37 INT Height,
38 UINT Planes,
39 UINT BitsPixel,
40 IN OPTIONAL LPBYTE pBits)
41 {
42 HBITMAP hBitmap;
43 SIZEL Size;
44 LONG WidthBytes;
45
46 /* NOTE: Windows also doesn't store nr. of planes separately! */
47 BitsPixel = BITMAPOBJ_GetRealBitsPixel(BitsPixel * Planes);
48
49 /* Check parameters */
50 if (BitsPixel == 0 || Width < 0)
51 {
52 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n", Width, Height, BitsPixel);
53 SetLastWin32Error(ERROR_INVALID_PARAMETER);
54 return 0;
55 }
56
57 WidthBytes = BITMAPOBJ_GetWidthBytes(Width, Planes * BitsPixel);
58
59 Size.cx = abs(Width);
60 Size.cy = abs(Height);
61
62 /* Create the bitmap object. */
63 hBitmap = IntCreateBitmap(Size, WidthBytes,
64 BitmapFormat(BitsPixel, BI_RGB),
65 (Height < 0 ? BMF_TOPDOWN : 0) |
66 (NULL == pBits ? 0 : BMF_NOZEROINIT), NULL);
67 if (!hBitmap)
68 {
69 DPRINT("IntGdiCreateBitmap: returned 0\n");
70 return 0;
71 }
72
73 PBITMAPOBJ bmp = BITMAPOBJ_LockBitmap( hBitmap );
74 if (bmp == NULL)
75 {
76 NtGdiDeleteObject(hBitmap);
77 return NULL;
78 }
79
80 bmp->flFlags = BITMAPOBJ_IS_APIBITMAP;
81
82 if (NULL != pBits)
83 {
84 IntSetBitmapBits(bmp, bmp->SurfObj.cjBits, pBits);
85 }
86
87 BITMAPOBJ_UnlockBitmap( bmp );
88
89 DPRINT("IntGdiCreateBitmap : %dx%d, %d BPP colors, topdown %d, returning %08x\n",
90 Size.cx, Size.cy, BitsPixel, (Height < 0 ? 1 : 0), hBitmap);
91
92 return hBitmap;
93 }
94
95
96 HBITMAP STDCALL
97 NtGdiCreateBitmap(
98 INT Width,
99 INT Height,
100 UINT Planes,
101 UINT BitsPixel,
102 IN OPTIONAL LPBYTE pUnsafeBits)
103 {
104 HBITMAP hBitmap;
105
106 _SEH_TRY
107 {
108 if (pUnsafeBits)
109 {
110 UINT cjBits = BITMAPOBJ_GetWidthBytes(Width, BitsPixel) * abs(Height);
111 ProbeForRead(pUnsafeBits, cjBits, 1);
112 }
113
114 if (0 == Width || 0 == Height)
115 {
116 hBitmap = IntGdiCreateBitmap (1, 1, 1, 1, NULL);
117 }
118 else
119 {
120 hBitmap = IntGdiCreateBitmap(Width, Height, Planes, BitsPixel, pUnsafeBits);
121 }
122 }
123 _SEH_HANDLE
124 {
125 hBitmap = 0;
126 }
127 _SEH_END
128
129 return hBitmap;
130 }
131
132 BOOL INTERNAL_CALL
133 BITMAP_Cleanup(PVOID ObjectBody)
134 {
135 PBITMAPOBJ pBmp = (PBITMAPOBJ)ObjectBody;
136 if (pBmp->SurfObj.pvBits != NULL &&
137 (pBmp->flFlags & BITMAPOBJ_IS_APIBITMAP))
138 {
139 if (pBmp->dib == NULL)
140 {
141 if (pBmp->SurfObj.pvBits != NULL)
142 ExFreePool(pBmp->SurfObj.pvBits);
143 }
144 else
145 {
146 if (pBmp->SurfObj.pvBits != NULL)
147 EngFreeUserMem(pBmp->SurfObj.pvBits);
148 }
149 if (pBmp->hDIBPalette != NULL)
150 {
151 NtGdiDeleteObject(pBmp->hDIBPalette);
152 }
153 }
154
155 if (NULL != pBmp->BitsLock)
156 {
157 ExFreePoolWithTag(pBmp->BitsLock, TAG_BITMAPOBJ);
158 pBmp->BitsLock = NULL;
159 }
160
161 return TRUE;
162 }
163
164
165 HBITMAP FASTCALL
166 IntCreateCompatibleBitmap(
167 PDC Dc,
168 INT Width,
169 INT Height)
170 {
171 HBITMAP Bmp;
172
173 Bmp = NULL;
174
175 if ((Width >= 0x10000) || (Height >= 0x10000))
176 {
177 DPRINT1("got bad width %d or height %d, please look for reason\n", Width, Height);
178 return NULL;
179 }
180
181 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
182 if (0 == Width || 0 == Height)
183 {
184 Bmp = IntGdiCreateBitmap (1, 1, 1, 1, NULL);
185 }
186 else
187 {
188 Bmp = IntGdiCreateBitmap(abs(Width), abs(Height), 1, Dc->w.bitsPerPixel, NULL);
189 }
190
191 return Bmp;
192 }
193
194 HBITMAP STDCALL
195 NtGdiCreateCompatibleBitmap(
196 HDC hDC,
197 INT Width,
198 INT Height)
199 {
200 HBITMAP Bmp;
201 PDC Dc;
202
203 Dc = DC_LockDc(hDC);
204
205 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n", hDC, Width, Height, Dc->w.bitsPerPixel);
206
207 if (NULL == Dc)
208 {
209 SetLastWin32Error(ERROR_INVALID_HANDLE);
210 return NULL;
211 }
212
213 Bmp = IntCreateCompatibleBitmap(Dc, Width, Height);
214
215 DPRINT ("\t\t%04x\n", Bmp);
216 DC_UnlockDc(Dc);
217 return Bmp;
218 }
219
220 BOOL STDCALL
221 NtGdiGetBitmapDimension(
222 HBITMAP hBitmap,
223 LPSIZE Dimension)
224 {
225 PBITMAPOBJ bmp;
226
227 bmp = BITMAPOBJ_LockBitmap(hBitmap);
228 if (bmp == NULL)
229 {
230 return FALSE;
231 }
232
233 *Dimension = bmp->dimension;
234
235 BITMAPOBJ_UnlockBitmap(bmp);
236
237 return TRUE;
238 }
239
240 COLORREF STDCALL
241 NtGdiGetPixel(HDC hDC, INT XPos, INT YPos)
242 {
243 PDC dc = NULL;
244 COLORREF Result = (COLORREF)CLR_INVALID; // default to failure
245 BOOL bInRect = FALSE;
246 BITMAPOBJ *BitmapObject;
247 SURFOBJ *SurfaceObject;
248 HPALETTE Pal = 0;
249 XLATEOBJ *XlateObj;
250 HBITMAP hBmpTmp;
251
252 dc = DC_LockDc (hDC);
253
254 if ( !dc )
255 {
256 SetLastWin32Error(ERROR_INVALID_HANDLE);
257 return Result;
258 }
259 if (dc->DC_Type == DC_TYPE_INFO)
260 {
261 DC_UnlockDc(dc);
262 return Result;
263 }
264 XPos += dc->w.DCOrgX;
265 YPos += dc->w.DCOrgY;
266 if ( IN_RECT(dc->CombinedClip->rclBounds,XPos,YPos) )
267 {
268 bInRect = TRUE;
269 BitmapObject = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
270 SurfaceObject = &BitmapObject->SurfObj;
271 if ( BitmapObject )
272 {
273 if ( dc->w.hPalette != 0 )
274 Pal = dc->w.hPalette;
275 /* FIXME: Verify if it shouldn't be PAL_BGR! */
276 XlateObj = (XLATEOBJ*)IntEngCreateXlate ( PAL_RGB, 0, NULL, Pal );
277 if ( XlateObj )
278 {
279 // check if this DC has a DIB behind it...
280 if ( SurfaceObject->pvScan0 ) // STYPE_BITMAP == SurfaceObject->iType
281 {
282 ASSERT ( SurfaceObject->lDelta );
283 Result = XLATEOBJ_iXlate(XlateObj,
284 DibFunctionsForBitmapFormat[SurfaceObject->iBitmapFormat].DIB_GetPixel ( SurfaceObject, XPos, YPos ) );
285 }
286 EngDeleteXlate(XlateObj);
287 }
288 BITMAPOBJ_UnlockBitmap(BitmapObject);
289 }
290 }
291 DC_UnlockDc(dc);
292
293 // if Result is still CLR_INVALID, then the "quick" method above didn't work
294 if ( bInRect && Result == CLR_INVALID )
295 {
296 // FIXME: create a 1x1 32BPP DIB, and blit to it
297 HDC hDCTmp = NtGdiCreateCompatibleDC(hDC);
298 if ( hDCTmp )
299 {
300 static const BITMAPINFOHEADER bih = { sizeof(BITMAPINFOHEADER), 1, 1, 1, 32, BI_RGB, 0, 0, 0, 0, 0 };
301 BITMAPINFO bi;
302 RtlMoveMemory ( &(bi.bmiHeader), &bih, sizeof(bih) );
303 hBmpTmp = NtGdiCreateDIBitmap ( hDC, &bi.bmiHeader, 0, NULL, &bi, DIB_RGB_COLORS );
304 //HBITMAP hBmpTmp = IntGdiCreateBitmap ( 1, 1, 1, 32, NULL);
305 if ( hBmpTmp )
306 {
307 HBITMAP hBmpOld = (HBITMAP)NtGdiSelectBitmap ( hDCTmp, hBmpTmp );
308 if ( hBmpOld )
309 {
310 PBITMAPOBJ bmpobj;
311
312 NtGdiBitBlt ( hDCTmp, 0, 0, 1, 1, hDC, XPos, YPos, SRCCOPY, 0, 0 );
313 NtGdiSelectBitmap ( hDCTmp, hBmpOld );
314
315 // our bitmap is no longer selected, so we can access it's stuff...
316 bmpobj = BITMAPOBJ_LockBitmap ( hBmpTmp );
317 if ( bmpobj )
318 {
319 Result = *(COLORREF*)bmpobj->SurfObj.pvScan0;
320 BITMAPOBJ_UnlockBitmap ( bmpobj );
321 }
322 }
323 NtGdiDeleteObject ( hBmpTmp );
324 }
325 NtGdiDeleteObjectApp ( hDCTmp );
326 }
327 }
328
329 return Result;
330 }
331
332
333 LONG STDCALL
334 IntGetBitmapBits(
335 PBITMAPOBJ bmp,
336 DWORD Bytes,
337 OUT PBYTE Bits)
338 {
339 LONG ret;
340
341 ASSERT(Bits);
342
343 /* Don't copy more bytes than the buffer has */
344 Bytes = min(Bytes, bmp->SurfObj.cjBits);
345
346 #if 0
347 /* FIXME: Call DDI CopyBits here if available */
348 if(bmp->DDBitmap)
349 {
350 DPRINT("Calling device specific BitmapBits\n");
351 if(bmp->DDBitmap->funcs->pBitmapBits)
352 {
353 ret = bmp->DDBitmap->funcs->pBitmapBits(hbitmap, bits, count, DDB_GET);
354 }
355 else
356 {
357 ERR_(bitmap)("BitmapBits == NULL??\n");
358 ret = 0;
359 }
360 }
361 else
362 #endif
363 {
364 RtlCopyMemory(Bits, bmp->SurfObj.pvBits, Bytes);
365 ret = Bytes;
366 }
367 return ret;
368 }
369
370 LONG STDCALL
371 NtGdiGetBitmapBits(HBITMAP hBitmap,
372 ULONG Bytes,
373 OUT OPTIONAL PBYTE pUnsafeBits)
374 {
375 PBITMAPOBJ bmp;
376 LONG ret;
377
378 if (pUnsafeBits != NULL && Bytes == 0)
379 {
380 return 0;
381 }
382
383 bmp = BITMAPOBJ_LockBitmap (hBitmap);
384 if (!bmp)
385 {
386 SetLastWin32Error(ERROR_INVALID_HANDLE);
387 return 0;
388 }
389
390 /* If the bits vector is null, the function should return the read size */
391 if (pUnsafeBits == NULL)
392 {
393 ret = bmp->SurfObj.cjBits;
394 BITMAPOBJ_UnlockBitmap (bmp);
395 return ret;
396 }
397
398 /* Don't copy more bytes than the buffer has */
399 Bytes = min(Bytes, bmp->SurfObj.cjBits);
400
401 _SEH_TRY
402 {
403 ProbeForWrite(pUnsafeBits, Bytes, 1);
404 ret = IntGetBitmapBits(bmp, Bytes, pUnsafeBits);
405 }
406 _SEH_HANDLE
407 {
408 ret = 0;
409 }
410 _SEH_END
411
412 BITMAPOBJ_UnlockBitmap (bmp);
413
414 return ret;
415 }
416
417
418 LONG STDCALL
419 IntSetBitmapBits(
420 PBITMAPOBJ bmp,
421 DWORD Bytes,
422 IN PBYTE Bits)
423 {
424 LONG ret;
425
426 /* Don't copy more bytes than the buffer has */
427 Bytes = min(Bytes, bmp->SurfObj.cjBits);
428
429 #if 0
430 /* FIXME: call DDI specific function here if available */
431 if(bmp->DDBitmap)
432 {
433 DPRINT ("Calling device specific BitmapBits\n");
434 if (bmp->DDBitmap->funcs->pBitmapBits)
435 {
436 ret = bmp->DDBitmap->funcs->pBitmapBits(hBitmap, (void *) Bits, Bytes, DDB_SET);
437 }
438 else
439 {
440 DPRINT ("BitmapBits == NULL??\n");
441 ret = 0;
442 }
443 }
444 else
445 #endif
446 {
447 RtlCopyMemory(bmp->SurfObj.pvBits, Bits, Bytes);
448 ret = Bytes;
449 }
450
451 return ret;
452 }
453
454
455 LONG STDCALL
456 NtGdiSetBitmapBits(
457 HBITMAP hBitmap,
458 DWORD Bytes,
459 IN PBYTE pUnsafeBits)
460 {
461 LONG ret;
462 PBITMAPOBJ bmp;
463
464 if (pUnsafeBits == NULL || Bytes == 0)
465 {
466 return 0;
467 }
468
469 bmp = BITMAPOBJ_LockBitmap(hBitmap);
470 if (bmp == NULL)
471 {
472 SetLastWin32Error(ERROR_INVALID_HANDLE);
473 return 0;
474 }
475
476 _SEH_TRY
477 {
478 ProbeForRead(pUnsafeBits, Bytes, 1);
479 ret = IntSetBitmapBits(bmp, Bytes, pUnsafeBits);
480 }
481 _SEH_HANDLE
482 {
483 ret = 0;
484 }
485 _SEH_END
486
487 BITMAPOBJ_UnlockBitmap(bmp);
488
489 return ret;
490 }
491
492 BOOL STDCALL
493 NtGdiSetBitmapDimension(
494 HBITMAP hBitmap,
495 INT Width,
496 INT Height,
497 LPSIZE Size)
498 {
499 PBITMAPOBJ bmp;
500
501 bmp = BITMAPOBJ_LockBitmap(hBitmap);
502 if (bmp == NULL)
503 {
504 return FALSE;
505 }
506
507 if (Size)
508 {
509 *Size = bmp->dimension;
510 }
511 bmp->dimension.cx = Width;
512 bmp->dimension.cy = Height;
513
514 BITMAPOBJ_UnlockBitmap (bmp);
515
516 return TRUE;
517 }
518
519 BOOL STDCALL
520 GdiSetPixelV(
521 HDC hDC,
522 INT X,
523 INT Y,
524 COLORREF Color)
525 {
526 HBRUSH NewBrush = NtGdiCreateSolidBrush(Color, NULL);
527 HGDIOBJ OldBrush;
528
529 if (NewBrush == NULL)
530 return(FALSE);
531 OldBrush = NtGdiSelectBrush(hDC, NewBrush);
532 if (OldBrush == NULL)
533 {
534 NtGdiDeleteObject(NewBrush);
535 return(FALSE);
536 }
537 NtGdiPatBlt(hDC, X, Y, 1, 1, PATCOPY);
538 NtGdiSelectBrush(hDC, OldBrush);
539 NtGdiDeleteObject(NewBrush);
540 return TRUE;
541 }
542
543 COLORREF STDCALL
544 NtGdiSetPixel(
545 HDC hDC,
546 INT X,
547 INT Y,
548 COLORREF Color)
549 {
550 DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);
551
552 if (GdiSetPixelV(hDC,X,Y,Color))
553 {
554 Color = NtGdiGetPixel(hDC,X,Y);
555 DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);
556 return Color;
557 }
558
559 Color = ((COLORREF) CLR_INVALID);
560 DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n",X,Y,Color);
561 return Color;
562 }
563
564
565 /* Internal Functions */
566
567 INT FASTCALL
568 BITMAPOBJ_GetRealBitsPixel(INT nBitsPixel)
569 {
570 if (nBitsPixel < 0)
571 return 0;
572 if (nBitsPixel <= 1)
573 return 1;
574 if (nBitsPixel <= 2)
575 return 2;
576 if (nBitsPixel <= 4)
577 return 4;
578 if (nBitsPixel <= 8)
579 return 8;
580 if (nBitsPixel <= 16)
581 return 16;
582 if (nBitsPixel <= 24)
583 return 24;
584 if (nBitsPixel <= 32)
585 return 32;
586
587 return 0;
588 }
589
590 INT FASTCALL
591 BITMAPOBJ_GetWidthBytes (INT bmWidth, INT bpp)
592 {
593 #if 0
594 switch(bpp)
595 {
596 case 1:
597 return 2 * ((bmWidth+15) >> 4);
598
599 case 24:
600 bmWidth *= 3; /* fall through */
601 case 8:
602 return bmWidth + (bmWidth & 1);
603
604 case 32:
605 return bmWidth * 4;
606
607 case 16:
608 case 15:
609 return bmWidth * 2;
610
611 case 4:
612 return 2 * ((bmWidth+3) >> 2);
613
614 default:
615 DPRINT ("stub");
616 }
617
618 return -1;
619 #endif
620
621 return ((bmWidth * bpp + 15) & ~15) >> 3;
622 }
623
624 HBITMAP FASTCALL
625 BITMAPOBJ_CopyBitmap(HBITMAP hBitmap)
626 {
627 HBITMAP res;
628 BITMAP bm;
629 BITMAPOBJ *Bitmap, *resBitmap;
630 SIZEL Size;
631
632 if (hBitmap == NULL)
633 {
634 return 0;
635 }
636
637 Bitmap = GDIOBJ_LockObj(hBitmap, GDI_OBJECT_TYPE_BITMAP);
638 if (Bitmap == NULL)
639 {
640 return 0;
641 }
642
643 BITMAP_GetObject(Bitmap, sizeof(BITMAP), &bm);
644 bm.bmBits = NULL;
645 if (Bitmap->SurfObj.lDelta >= 0)
646 bm.bmHeight = -bm.bmHeight;
647
648 Size.cx = abs(bm.bmWidth);
649 Size.cy = abs(bm.bmHeight);
650 res = IntCreateBitmap(Size,
651 bm.bmWidthBytes,
652 BitmapFormat(bm.bmBitsPixel * bm.bmPlanes, BI_RGB),
653 (bm.bmHeight < 0 ? BMF_TOPDOWN : 0) | BMF_NOZEROINIT,
654 NULL);
655
656 if(res)
657 {
658 PBYTE buf;
659
660 resBitmap = GDIOBJ_LockObj(res, GDI_OBJECT_TYPE_BITMAP);
661 if (resBitmap)
662 {
663 buf = ExAllocatePoolWithTag (PagedPool, bm.bmWidthBytes * abs(bm.bmHeight), TAG_BITMAP);
664 if (buf == NULL)
665 {
666 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
667 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
668 NtGdiDeleteObject(res);
669 return 0;
670 }
671 IntGetBitmapBits (Bitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
672 IntSetBitmapBits (resBitmap, bm.bmWidthBytes * abs(bm.bmHeight), buf);
673 ExFreePool (buf);
674 resBitmap->flFlags = Bitmap->flFlags;
675 GDIOBJ_UnlockObjByPtr((POBJ)resBitmap);
676 }
677 else
678 {
679 NtGdiDeleteObject(res);
680 res = NULL;
681 }
682 }
683
684 GDIOBJ_UnlockObjByPtr((POBJ)Bitmap);
685
686 return res;
687 }
688
689 INT STDCALL
690 BITMAP_GetObject(BITMAPOBJ * bmp, INT Count, LPVOID buffer)
691 {
692 if ((UINT)Count < sizeof(BITMAP)) return 0;
693
694 if(bmp->dib)
695 {
696 if((UINT)Count < sizeof(DIBSECTION))
697 {
698 Count = sizeof(BITMAP);
699 }
700 else
701 {
702 Count = sizeof(DIBSECTION);
703 }
704 if (buffer)
705 {
706 memcpy(buffer, bmp->dib, Count);
707 }
708 return Count;
709 }
710 else
711 {
712 Count = sizeof(BITMAP);
713 if (buffer)
714 {
715 BITMAP Bitmap;
716
717 Count = sizeof(BITMAP);
718 Bitmap.bmType = 0;
719 Bitmap.bmWidth = bmp->SurfObj.sizlBitmap.cx;
720 Bitmap.bmHeight = bmp->SurfObj.sizlBitmap.cy;
721 Bitmap.bmWidthBytes = abs(bmp->SurfObj.lDelta);
722 Bitmap.bmPlanes = 1;
723 Bitmap.bmBitsPixel = BitsPerFormat(bmp->SurfObj.iBitmapFormat);
724 //Bitmap.bmBits = bmp->SurfObj.pvBits;
725 Bitmap.bmBits = NULL; /* not set accoring wine test confirm in win2k */
726 memcpy(buffer, &Bitmap, Count);
727 }
728 return Count;
729 }
730 }
731 /* EOF */