2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
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.
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.
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.
26 #define IN_RECT(r,x,y) \
40 IN OPTIONAL LPBYTE pBits
)
46 /* NOTE: Windows also doesn't store nr. of planes separately! */
47 BitsPixel
= BITMAPOBJ_GetRealBitsPixel(BitsPixel
* Planes
);
49 /* Check parameters */
50 if (BitsPixel
== 0 || Width
<= 0 || Width
>= 0x8000000 || Height
== 0)
52 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n", Width
, Height
, BitsPixel
);
53 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
57 WidthBytes
= BITMAPOBJ_GetWidthBytes(Width
, BitsPixel
);
60 Size
.cy
= abs(Height
);
62 /* Make sure that cjBits will not overflow */
63 if ((ULONGLONG
)WidthBytes
* Size
.cy
>= 0x100000000ULL
)
65 DPRINT1("Width = %d, Height = %d BitsPixel = %d\n", Width
, Height
, BitsPixel
);
66 SetLastWin32Error(ERROR_INVALID_PARAMETER
);
70 /* Create the bitmap object. */
71 hBitmap
= IntCreateBitmap(Size
, WidthBytes
,
72 BitmapFormat(BitsPixel
, BI_RGB
),
73 (Height
< 0 ? BMF_TOPDOWN
: 0) |
74 (NULL
== pBits
? 0 : BMF_NOZEROINIT
), NULL
);
77 DPRINT("IntGdiCreateBitmap: returned 0\n");
81 PBITMAPOBJ bmp
= BITMAPOBJ_LockBitmap( hBitmap
);
84 NtGdiDeleteObject(hBitmap
);
88 bmp
->flFlags
= BITMAPOBJ_IS_APIBITMAP
;
89 bmp
->hDC
= NULL
; // Fixme
93 IntSetBitmapBits(bmp
, bmp
->SurfObj
.cjBits
, pBits
);
96 BITMAPOBJ_UnlockBitmap( bmp
);
98 DPRINT("IntGdiCreateBitmap : %dx%d, %d BPP colors, topdown %d, returning %08x\n",
99 Size
.cx
, Size
.cy
, BitsPixel
, (Height
< 0 ? 1 : 0), hBitmap
);
111 IN OPTIONAL LPBYTE pUnsafeBits
)
119 UINT cjBits
= BITMAPOBJ_GetWidthBytes(Width
, BitsPixel
) * abs(Height
);
120 ProbeForRead(pUnsafeBits
, cjBits
, 1);
123 hBitmap
= IntGdiCreateBitmap(Width
, Height
, Planes
, BitsPixel
, pUnsafeBits
);
136 BITMAP_Cleanup(PVOID ObjectBody
)
138 PBITMAPOBJ pBmp
= (PBITMAPOBJ
)ObjectBody
;
139 if (pBmp
->SurfObj
.pvBits
!= NULL
&&
140 (pBmp
->flFlags
& BITMAPOBJ_IS_APIBITMAP
))
142 if (pBmp
->dib
== NULL
)
144 ExFreePool(pBmp
->SurfObj
.pvBits
);
148 EngFreeUserMem(pBmp
->SurfObj
.pvBits
);
150 if (pBmp
->hDIBPalette
!= NULL
)
152 NtGdiDeleteObject(pBmp
->hDIBPalette
);
156 if (NULL
!= pBmp
->BitsLock
)
158 ExFreePoolWithTag(pBmp
->BitsLock
, TAG_BITMAPOBJ
);
159 pBmp
->BitsLock
= NULL
;
163 ExFreePoolWithTag(pBmp
->dib
, TAG_DIB
);
170 IntCreateCompatibleBitmap(
177 /* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
178 if (0 == Width
|| 0 == Height
)
180 Bmp
= NtGdiGetStockObject(DEFAULT_BITMAP
);
184 Bmp
= IntGdiCreateBitmap(abs(Width
), abs(Height
), 1, Dc
->w
.bitsPerPixel
, NULL
);
191 NtGdiCreateCompatibleBitmap(
201 DPRINT("NtGdiCreateCompatibleBitmap(%04x,%d,%d, bpp:%d) = \n", hDC
, Width
, Height
, Dc
->w
.bitsPerPixel
);
205 SetLastWin32Error(ERROR_INVALID_HANDLE
);
209 Bmp
= IntCreateCompatibleBitmap(Dc
, Width
, Height
);
211 DPRINT ("\t\t%04x\n", Bmp
);
217 NtGdiGetBitmapDimension(
227 bmp
= BITMAPOBJ_LockBitmap(hBitmap
);
230 SetLastWin32Error(ERROR_INVALID_HANDLE
);
236 ProbeForWrite(Dimension
, sizeof(SIZE
), 1);
237 *Dimension
= bmp
->dimension
;
245 BITMAPOBJ_UnlockBitmap(bmp
);
251 NtGdiGetPixel(HDC hDC
, INT XPos
, INT YPos
)
254 COLORREF Result
= (COLORREF
)CLR_INVALID
; // default to failure
255 BOOL bInRect
= FALSE
;
256 BITMAPOBJ
*BitmapObject
;
257 SURFOBJ
*SurfaceObject
;
262 dc
= DC_LockDc (hDC
);
266 SetLastWin32Error(ERROR_INVALID_HANDLE
);
269 if (dc
->DC_Type
== DC_TYPE_INFO
)
274 XPos
+= dc
->ptlDCOrig
.x
;
275 YPos
+= dc
->ptlDCOrig
.y
;
276 if ( IN_RECT(dc
->CombinedClip
->rclBounds
,XPos
,YPos
) )
279 BitmapObject
= BITMAPOBJ_LockBitmap(dc
->w
.hBitmap
);
280 SurfaceObject
= &BitmapObject
->SurfObj
;
283 Pal
= BitmapObject
->hDIBPalette
;
284 if (!Pal
) Pal
= pPrimarySurface
->DevInfo
.hpalDefault
;
286 /* FIXME: Verify if it shouldn't be PAL_BGR! */
287 XlateObj
= (XLATEOBJ
*)IntEngCreateXlate ( PAL_RGB
, 0, NULL
, Pal
);
290 // check if this DC has a DIB behind it...
291 if ( SurfaceObject
->pvScan0
) // STYPE_BITMAP == SurfaceObject->iType
293 ASSERT ( SurfaceObject
->lDelta
);
294 Result
= XLATEOBJ_iXlate(XlateObj
,
295 DibFunctionsForBitmapFormat
[SurfaceObject
->iBitmapFormat
].DIB_GetPixel ( SurfaceObject
, XPos
, YPos
) );
297 EngDeleteXlate(XlateObj
);
299 BITMAPOBJ_UnlockBitmap(BitmapObject
);
304 // if Result is still CLR_INVALID, then the "quick" method above didn't work
305 if ( bInRect
&& Result
== CLR_INVALID
)
307 // FIXME: create a 1x1 32BPP DIB, and blit to it
308 HDC hDCTmp
= NtGdiCreateCompatibleDC(hDC
);
311 static const BITMAPINFOHEADER bih
= { sizeof(BITMAPINFOHEADER
), 1, 1, 1, 32, BI_RGB
, 0, 0, 0, 0, 0 };
313 RtlMoveMemory ( &(bi
.bmiHeader
), &bih
, sizeof(bih
) );
314 hBmpTmp
= NtGdiCreateDIBitmapInternal(hDC
,
315 bi
.bmiHeader
.biWidth
,
316 bi
.bmiHeader
.biHeight
,
321 bi
.bmiHeader
.biBitCount
,
322 bi
.bmiHeader
.biSizeImage
,
326 //HBITMAP hBmpTmp = IntGdiCreateBitmap ( 1, 1, 1, 32, NULL);
329 HBITMAP hBmpOld
= (HBITMAP
)NtGdiSelectBitmap ( hDCTmp
, hBmpTmp
);
334 NtGdiBitBlt ( hDCTmp
, 0, 0, 1, 1, hDC
, XPos
, YPos
, SRCCOPY
, 0, 0 );
335 NtGdiSelectBitmap ( hDCTmp
, hBmpOld
);
337 // our bitmap is no longer selected, so we can access it's stuff...
338 bmpobj
= BITMAPOBJ_LockBitmap ( hBmpTmp
);
341 Result
= *(COLORREF
*)bmpobj
->SurfObj
.pvScan0
;
342 BITMAPOBJ_UnlockBitmap ( bmpobj
);
345 NtGdiDeleteObject ( hBmpTmp
);
347 NtGdiDeleteObjectApp ( hDCTmp
);
365 /* Don't copy more bytes than the buffer has */
366 Bytes
= min(Bytes
, bmp
->SurfObj
.cjBits
);
369 /* FIXME: Call DDI CopyBits here if available */
372 DPRINT("Calling device specific BitmapBits\n");
373 if(bmp
->DDBitmap
->funcs
->pBitmapBits
)
375 ret
= bmp
->DDBitmap
->funcs
->pBitmapBits(hbitmap
, bits
, count
, DDB_GET
);
379 ERR_(bitmap
)("BitmapBits == NULL??\n");
386 RtlCopyMemory(Bits
, bmp
->SurfObj
.pvBits
, Bytes
);
393 NtGdiGetBitmapBits(HBITMAP hBitmap
,
395 OUT OPTIONAL PBYTE pUnsafeBits
)
400 if (pUnsafeBits
!= NULL
&& Bytes
== 0)
405 bmp
= BITMAPOBJ_LockBitmap (hBitmap
);
408 SetLastWin32Error(ERROR_INVALID_HANDLE
);
412 /* If the bits vector is null, the function should return the read size */
413 if (pUnsafeBits
== NULL
)
415 ret
= bmp
->SurfObj
.cjBits
;
416 BITMAPOBJ_UnlockBitmap (bmp
);
420 /* Don't copy more bytes than the buffer has */
421 Bytes
= min(Bytes
, bmp
->SurfObj
.cjBits
);
425 ProbeForWrite(pUnsafeBits
, Bytes
, 1);
426 ret
= IntGetBitmapBits(bmp
, Bytes
, pUnsafeBits
);
434 BITMAPOBJ_UnlockBitmap (bmp
);
448 /* Don't copy more bytes than the buffer has */
449 Bytes
= min(Bytes
, bmp
->SurfObj
.cjBits
);
452 /* FIXME: call DDI specific function here if available */
455 DPRINT ("Calling device specific BitmapBits\n");
456 if (bmp
->DDBitmap
->funcs
->pBitmapBits
)
458 ret
= bmp
->DDBitmap
->funcs
->pBitmapBits(hBitmap
, (void *) Bits
, Bytes
, DDB_SET
);
462 DPRINT ("BitmapBits == NULL??\n");
469 RtlCopyMemory(bmp
->SurfObj
.pvBits
, Bits
, Bytes
);
481 IN PBYTE pUnsafeBits
)
486 if (pUnsafeBits
== NULL
|| Bytes
== 0)
491 bmp
= BITMAPOBJ_LockBitmap(hBitmap
);
494 SetLastWin32Error(ERROR_INVALID_HANDLE
);
500 ProbeForRead(pUnsafeBits
, Bytes
, 1);
501 ret
= IntSetBitmapBits(bmp
, Bytes
, pUnsafeBits
);
509 BITMAPOBJ_UnlockBitmap(bmp
);
515 NtGdiSetBitmapDimension(
527 bmp
= BITMAPOBJ_LockBitmap(hBitmap
);
530 SetLastWin32Error(ERROR_INVALID_HANDLE
);
538 ProbeForWrite(Size
, sizeof(SIZE
), 1);
539 *Size
= bmp
->dimension
;
548 /* The dimension is changed even if writing the old value failed */
549 bmp
->dimension
.cx
= Width
;
550 bmp
->dimension
.cy
= Height
;
552 BITMAPOBJ_UnlockBitmap (bmp
);
564 HBRUSH NewBrush
= NtGdiCreateSolidBrush(Color
, NULL
);
567 if (NewBrush
== NULL
)
569 OldBrush
= NtGdiSelectBrush(hDC
, NewBrush
);
570 if (OldBrush
== NULL
)
572 NtGdiDeleteObject(NewBrush
);
575 NtGdiPatBlt(hDC
, X
, Y
, 1, 1, PATCOPY
);
576 NtGdiSelectBrush(hDC
, OldBrush
);
577 NtGdiDeleteObject(NewBrush
);
588 DPRINT("0 NtGdiSetPixel X %ld Y %ld C %ld\n",X
,Y
,Color
);
590 if (GdiSetPixelV(hDC
,X
,Y
,Color
))
592 Color
= NtGdiGetPixel(hDC
,X
,Y
);
593 DPRINT("1 NtGdiSetPixel X %ld Y %ld C %ld\n",X
,Y
,Color
);
597 Color
= ((COLORREF
) CLR_INVALID
);
598 DPRINT("2 NtGdiSetPixel X %ld Y %ld C %ld\n",X
,Y
,Color
);
603 /* Internal Functions */
606 BITMAPOBJ_GetRealBitsPixel(UINT nBitsPixel
)
614 if (nBitsPixel
<= 16)
616 if (nBitsPixel
<= 24)
618 if (nBitsPixel
<= 32)
625 BITMAPOBJ_GetWidthBytes (INT bmWidth
, INT bpp
)
631 return 2 * ((bmWidth
+15) >> 4);
634 bmWidth
*= 3; /* fall through */
636 return bmWidth
+ (bmWidth
& 1);
646 return 2 * ((bmWidth
+3) >> 2);
655 return ((bmWidth
* bpp
+ 15) & ~15) >> 3;
659 BITMAPOBJ_CopyBitmap(HBITMAP hBitmap
)
663 BITMAPOBJ
*Bitmap
, *resBitmap
;
671 Bitmap
= GDIOBJ_LockObj(hBitmap
, GDI_OBJECT_TYPE_BITMAP
);
677 BITMAP_GetObject(Bitmap
, sizeof(BITMAP
), &bm
);
679 if (Bitmap
->SurfObj
.lDelta
>= 0)
680 bm
.bmHeight
= -bm
.bmHeight
;
682 Size
.cx
= abs(bm
.bmWidth
);
683 Size
.cy
= abs(bm
.bmHeight
);
684 res
= IntCreateBitmap(Size
,
686 BitmapFormat(bm
.bmBitsPixel
* bm
.bmPlanes
, BI_RGB
),
687 (bm
.bmHeight
< 0 ? BMF_TOPDOWN
: 0) | BMF_NOZEROINIT
,
694 resBitmap
= GDIOBJ_LockObj(res
, GDI_OBJECT_TYPE_BITMAP
);
697 buf
= ExAllocatePoolWithTag (PagedPool
, bm
.bmWidthBytes
* abs(bm
.bmHeight
), TAG_BITMAP
);
700 GDIOBJ_UnlockObjByPtr((POBJ
)resBitmap
);
701 GDIOBJ_UnlockObjByPtr((POBJ
)Bitmap
);
702 NtGdiDeleteObject(res
);
705 IntGetBitmapBits (Bitmap
, bm
.bmWidthBytes
* abs(bm
.bmHeight
), buf
);
706 IntSetBitmapBits (resBitmap
, bm
.bmWidthBytes
* abs(bm
.bmHeight
), buf
);
707 ExFreePoolWithTag (buf
,TAG_BITMAP
);
708 resBitmap
->flFlags
= Bitmap
->flFlags
;
709 GDIOBJ_UnlockObjByPtr((POBJ
)resBitmap
);
713 NtGdiDeleteObject(res
);
718 GDIOBJ_UnlockObjByPtr((POBJ
)Bitmap
);
724 BITMAP_GetObject(BITMAPOBJ
* bmp
, INT Count
, LPVOID buffer
)
726 if ((UINT
)Count
< sizeof(BITMAP
)) return 0;
730 if((UINT
)Count
< sizeof(DIBSECTION
))
732 Count
= sizeof(BITMAP
);
736 Count
= sizeof(DIBSECTION
);
740 memcpy(buffer
, bmp
->dib
, Count
);
746 Count
= sizeof(BITMAP
);
751 Count
= sizeof(BITMAP
);
753 Bitmap
.bmWidth
= bmp
->SurfObj
.sizlBitmap
.cx
;
754 Bitmap
.bmHeight
= bmp
->SurfObj
.sizlBitmap
.cy
;
755 Bitmap
.bmWidthBytes
= abs(bmp
->SurfObj
.lDelta
);
757 Bitmap
.bmBitsPixel
= BitsPerFormat(bmp
->SurfObj
.iBitmapFormat
);
758 Bitmap
.bmBits
= NULL
; /* not set according to wine test, confirmed in win2k */
759 memcpy(buffer
, &Bitmap
, Count
);
774 PBITMAPOBJ bmp
= BITMAPOBJ_LockBitmap( hsurf
);
778 BITMAPOBJ_UnlockBitmap( bmp
);