reactos/win32ss/gdi/ntgdi/bitmaps.c

884 lines
23 KiB
C
Raw Normal View History

/*
* COPYRIGHT: GNU GPL, See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Bitmap functions
* FILE: win32ss/gdi/ntgdi/bitmaps.c
* PROGRAMERS: Timo Kreuzer <timo.kreuzer@reactos.org>
* Katayama Hirofumi MZ <katayama.hirofumi.mz@gmail.com>
*/
#include <win32k.h>
#define NDEBUG
#include <debug.h>
BOOL
NTAPI
GreSetBitmapOwner(
_In_ HBITMAP hbmp,
_In_ ULONG ulOwner)
{
/* Check if we have the correct object type */
if (GDI_HANDLE_GET_TYPE(hbmp) != GDILoObjType_LO_BITMAP_TYPE)
{
DPRINT1("Incorrect type for hbmp: %p\n", hbmp);
return FALSE;
}
/// FIXME: this is a hack and doesn't handle a race condition properly.
/// It needs to be done in GDIOBJ_vSetObjectOwner atomically.
/* Check if we set public or none */
if ((ulOwner == GDI_OBJ_HMGR_PUBLIC) ||
(ulOwner == GDI_OBJ_HMGR_NONE))
{
/* Only allow this for owned objects */
if (GreGetObjectOwner(hbmp) != GDI_OBJ_HMGR_POWNED)
{
DPRINT1("Cannot change owner for non-powned hbmp\n");
return FALSE;
}
}
return GreSetObjectOwner(hbmp, ulOwner);
}
LONG
NTAPI
UnsafeSetBitmapBits(
_Inout_ PSURFACE psurf,
_In_ ULONG cjBits,
_In_ const VOID *pvBits)
{
PUCHAR pjDst;
const UCHAR *pjSrc;
LONG lDeltaDst, lDeltaSrc, lDeltaDstAbs;
ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel;
NT_ASSERT(psurf->flags & API_BITMAP);
NT_ASSERT(psurf->SurfObj.iBitmapFormat <= BMF_32BPP);
nWidth = psurf->SurfObj.sizlBitmap.cx;
nHeight = psurf->SurfObj.sizlBitmap.cy;
cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
pjDst = psurf->SurfObj.pvScan0;
pjSrc = pvBits;
lDeltaDst = psurf->SurfObj.lDelta;
lDeltaDstAbs = labs(lDeltaDst);
lDeltaSrc = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
NT_ASSERT(lDeltaSrc <= lDeltaDstAbs);
cbDst = lDeltaDstAbs * nHeight;
cbSrc = lDeltaSrc * nHeight;
cjBits = min(cjBits, cbSrc);
iSrc = iDst = 0;
for (Y = 0; Y < nHeight; Y++)
{
if (iSrc + lDeltaSrc > cjBits || iDst + lDeltaDstAbs > cbDst)
{
LONG lDelta = min(cjBits - iSrc, cbDst - iDst);
NT_ASSERT(lDelta >= 0);
RtlCopyMemory(pjDst, pjSrc, lDelta);
iSrc += lDelta;
break;
}
/* Copy one line */
RtlCopyMemory(pjDst, pjSrc, lDeltaSrc);
pjSrc += lDeltaSrc;
pjDst += lDeltaDst;
iSrc += lDeltaSrc;
iDst += lDeltaDstAbs;
}
return iSrc;
}
HBITMAP
NTAPI
GreCreateBitmapEx(
_In_ ULONG nWidth,
_In_ ULONG nHeight,
_In_ ULONG cjWidthBytes,
_In_ ULONG iFormat,
_In_ USHORT fjBitmap,
_In_ ULONG cjSizeImage,
_In_opt_ PVOID pvBits,
_In_ FLONG flags)
{
PSURFACE psurf;
HBITMAP hbmp;
PVOID pvCompressedBits = NULL;
/* Verify format */
if (iFormat < BMF_1BPP || iFormat > BMF_PNG) return NULL;
/* The infamous RLE hack */
if ((iFormat == BMF_4RLE) || (iFormat == BMF_8RLE))
{
pvCompressedBits = pvBits;
pvBits = NULL;
iFormat = (iFormat == BMF_4RLE) ? BMF_4BPP : BMF_8BPP;
}
/* Allocate a surface */
psurf = SURFACE_AllocSurface(STYPE_BITMAP,
nWidth,
nHeight,
iFormat,
fjBitmap,
cjWidthBytes,
pvCompressedBits ? 0 : cjSizeImage,
pvBits);
if (!psurf)
{
DPRINT1("SURFACE_AllocSurface failed.\n");
return NULL;
}
/* The infamous RLE hack */
if (pvCompressedBits)
{
SIZEL sizl;
LONG lDelta;
sizl.cx = nWidth;
sizl.cy = nHeight;
lDelta = WIDTH_BYTES_ALIGN32(nWidth, gajBitsPerFormat[iFormat]);
pvBits = psurf->SurfObj.pvBits;
DecompressBitmap(sizl, pvCompressedBits, pvBits, lDelta, iFormat, cjSizeImage);
}
/* Get the handle for the bitmap */
hbmp = (HBITMAP)psurf->SurfObj.hsurf;
/* Mark as API bitmap */
psurf->flags |= (flags | API_BITMAP);
/* Unlock the surface and return */
SURFACE_UnlockSurface(psurf);
return hbmp;
}
/* Creates a DDB surface,
* as in CreateCompatibleBitmap or CreateBitmap.
* Note that each scanline must be 32bit aligned!
*/
HBITMAP
NTAPI
GreCreateBitmap(
_In_ ULONG nWidth,
_In_ ULONG nHeight,
_In_ ULONG cPlanes,
_In_ ULONG cBitsPixel,
_In_opt_ PVOID pvBits)
{
/* Call the extended function */
return GreCreateBitmapEx(nWidth,
nHeight,
0, /* Auto width */
BitmapFormat(cBitsPixel * cPlanes, BI_RGB),
0, /* No bitmap flags */
0, /* Auto size */
pvBits,
DDB_SURFACE /* DDB */);
}
HBITMAP
APIENTRY
NtGdiCreateBitmap(
IN INT nWidth,
IN INT nHeight,
IN UINT cPlanes,
IN UINT cBitsPixel,
IN OPTIONAL LPBYTE pUnsafeBits)
{
HBITMAP hbmp;
ULONG cRealBpp, cjWidthBytes, iFormat;
ULONGLONG cjSize;
PSURFACE psurf;
/* Calculate bitmap format and real bits per pixel. */
iFormat = BitmapFormat(cBitsPixel * cPlanes, BI_RGB);
cRealBpp = gajBitsPerFormat[iFormat];
/* Calculate width and image size in bytes */
cjWidthBytes = WIDTH_BYTES_ALIGN16(nWidth, cRealBpp);
cjSize = (ULONGLONG)cjWidthBytes * nHeight;
/* Check parameters (possible overflow of cjSize!) */
if ((iFormat == 0) || (nWidth <= 0) || (nWidth >= 0x8000000) || (nHeight <= 0) ||
(cBitsPixel > 32) || (cPlanes > 32) || (cjSize >= 0x100000000ULL))
{
DPRINT1("Invalid bitmap format! Width=%d, Height=%d, Bpp=%u, Planes=%u\n",
nWidth, nHeight, cBitsPixel, cPlanes);
EngSetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
/* Allocate the surface (but don't set the bits) */
psurf = SURFACE_AllocSurface(STYPE_BITMAP,
nWidth,
nHeight,
iFormat,
0,
0,
0,
NULL);
if (!psurf)
{
DPRINT1("SURFACE_AllocSurface failed.\n");
return NULL;
}
/* Mark as API and DDB bitmap */
psurf->flags |= (API_BITMAP | DDB_SURFACE);
/* Check if we have bits to set */
if (pUnsafeBits)
{
/* Protect with SEH and copy the bits */
_SEH2_TRY
{
ProbeForRead(pUnsafeBits, (SIZE_T)cjSize, 1);
UnsafeSetBitmapBits(psurf, cjSize, pUnsafeBits);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
[WIN32K] Rewrite of the GDI handle manager - The old handle manager used a completely retarded spinlock in combination with KeDelayExecutionThread() for both exclusive and shared locks. This is probably the most uneffective algorithm possible. It was also duplicating code everywhere and it was a overall mess It is now replaced with a lock-free reference counter for shared locks and a pushlock for exclusive locks. -> Better performance and scalability. - Allocate user mode object attributes from the new gdi pool. This way, we don't need any caching, since the pool serves as a cache. Its also much faster and uses much less memory. - Allow object allocations of different size, instead of fixed size from a table. This way a single allocation can take care of actual needs. - Allow allcoating objects without a handle and insert them into the handle table later - Properly synchronize the process GDIHandleCount. Now gdiview and taskmanager show the correct number of gdi handles. - Implement a new event tracking system, that is capable of tracking all reverences and locks of objects and pool allocations to help track possible leaks - Make sure that all objects of a process are deleted in cleanup - Make sure all usermode memory allocations are freed, when cleaning up the process pool. - Make sure that each object type is using the correct type of lock (either shared or exclusive, not a mixture) - Fix some object / reference leaks - Lots of inferface improvements - Use global variables for certain things instead of members in the mapped gdi handle table - Make IntSysCreateRectpRgn create a region without a handle - Fix detection od source and mask use in GreStretchBltMask - Use GDIOBJ_bLockMultipleObjects in NtGdiCombineRegion to avoid possible deadlocks - Fix NtGdiAbortPath to reset DCPATH_ACTIVE flag in the dc and only bail out on error, instead of always - Replace DC_AllocateDcAttr and DC_AllocDcAttr with DC_bAllocDcAttr using the new user mode pool - Remove DCU_SyncDcAttrtoUser and DCU_SynchDcAttrtoUser. Those functions were unused and didn't do anything useful anyway, - Replace IntGdiSetDCOwnerEx and DC_SetOwnership with GreSetDCOwner, remove unused NoSetBrush parameter - Replace GDIOBJ_bValidateHandle and IsObjectDead with GreIsHandleValid - Chage GDIOBJ_bLockMultipleObjects: pass object type, return a BOOL, whether all objects could be locked, cleanup on failure svn path=/trunk/; revision=51470
2011-04-28 08:26:46 +00:00
GDIOBJ_vDeleteObject(&psurf->BaseObject);
_SEH2_YIELD(return NULL;)
}
_SEH2_END
}
else
{
/* Zero the bits */
RtlZeroMemory(psurf->SurfObj.pvBits, psurf->SurfObj.cjBits);
}
/* Get the handle for the bitmap */
hbmp = (HBITMAP)psurf->SurfObj.hsurf;
/* Unlock the surface */
SURFACE_UnlockSurface(psurf);
return hbmp;
}
HBITMAP FASTCALL
IntCreateCompatibleBitmap(
PDC Dc,
INT Width,
INT Height,
UINT Planes,
UINT Bpp)
{
HBITMAP Bmp = NULL;
PPALETTE ppal;
/* MS doc says if width or height is 0, return 1-by-1 pixel, monochrome bitmap */
if (0 == Width || 0 == Height)
{
return NtGdiGetStockObject(DEFAULT_BITMAP);
}
if (Dc->dctype != DC_TYPE_MEMORY)
{
PSURFACE psurf;
Bmp = GreCreateBitmap(abs(Width),
abs(Height),
Planes ? Planes : 1,
Bpp ? Bpp : Dc->ppdev->gdiinfo.cBitsPixel,
NULL);
if (Bmp == NULL)
{
DPRINT1("Failed to allocate a bitmap!\n");
return NULL;
}
psurf = SURFACE_ShareLockSurface(Bmp);
ASSERT(psurf);
/* Dereference old palette and set new palette */
ppal = PALETTE_ShareLockPalette(Dc->ppdev->devinfo.hpalDefault);
ASSERT(ppal);
SURFACE_vSetPalette(psurf, ppal);
PALETTE_ShareUnlockPalette(ppal);
/* Set flags */
psurf->flags = API_BITMAP;
psurf->hdc = NULL; // FIXME:
psurf->SurfObj.hdev = (HDEV)Dc->ppdev;
SURFACE_ShareUnlockSurface(psurf);
}
else
{
DIBSECTION dibs;
INT Count;
PSURFACE psurf = Dc->dclevel.pSurface;
if(!psurf) psurf = psurfDefaultBitmap;
Count = BITMAP_GetObject(psurf, sizeof(dibs), &dibs);
if (Count == sizeof(BITMAP))
{
PSURFACE psurfBmp;
Bmp = GreCreateBitmap(abs(Width),
abs(Height),
Planes ? Planes : 1,
Bpp ? Bpp : dibs.dsBm.bmBitsPixel,
NULL);
psurfBmp = SURFACE_ShareLockSurface(Bmp);
ASSERT(psurfBmp);
/* Dereference old palette and set new palette */
SURFACE_vSetPalette(psurfBmp, psurf->ppal);
/* Set flags */
psurfBmp->flags = API_BITMAP;
psurfBmp->hdc = NULL; // FIXME:
psurf->SurfObj.hdev = (HDEV)Dc->ppdev;
SURFACE_ShareUnlockSurface(psurfBmp);
}
else if (Count == sizeof(DIBSECTION))
{
/* A DIB section is selected in the DC */
BYTE buf[sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)] = {0};
PVOID Bits;
BITMAPINFO* bi = (BITMAPINFO*)buf;
bi->bmiHeader.biSize = sizeof(bi->bmiHeader);
bi->bmiHeader.biWidth = Width;
bi->bmiHeader.biHeight = Height;
bi->bmiHeader.biPlanes = Planes ? Planes : dibs.dsBmih.biPlanes;
bi->bmiHeader.biBitCount = Bpp ? Bpp : dibs.dsBmih.biBitCount;
bi->bmiHeader.biCompression = dibs.dsBmih.biCompression;
bi->bmiHeader.biSizeImage = 0;
bi->bmiHeader.biXPelsPerMeter = dibs.dsBmih.biXPelsPerMeter;
bi->bmiHeader.biYPelsPerMeter = dibs.dsBmih.biYPelsPerMeter;
bi->bmiHeader.biClrUsed = dibs.dsBmih.biClrUsed;
bi->bmiHeader.biClrImportant = dibs.dsBmih.biClrImportant;
if (bi->bmiHeader.biCompression == BI_BITFIELDS)
{
/* Copy the color masks */
RtlCopyMemory(bi->bmiColors, dibs.dsBitfields, 3*sizeof(RGBQUAD));
}
else if (bi->bmiHeader.biBitCount <= 8)
{
/* Copy the color table */
UINT Index;
PPALETTE PalGDI;
if (!psurf->ppal)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
[WIN32K] Rewrite of the GDI handle manager - The old handle manager used a completely retarded spinlock in combination with KeDelayExecutionThread() for both exclusive and shared locks. This is probably the most uneffective algorithm possible. It was also duplicating code everywhere and it was a overall mess It is now replaced with a lock-free reference counter for shared locks and a pushlock for exclusive locks. -> Better performance and scalability. - Allocate user mode object attributes from the new gdi pool. This way, we don't need any caching, since the pool serves as a cache. Its also much faster and uses much less memory. - Allow object allocations of different size, instead of fixed size from a table. This way a single allocation can take care of actual needs. - Allow allcoating objects without a handle and insert them into the handle table later - Properly synchronize the process GDIHandleCount. Now gdiview and taskmanager show the correct number of gdi handles. - Implement a new event tracking system, that is capable of tracking all reverences and locks of objects and pool allocations to help track possible leaks - Make sure that all objects of a process are deleted in cleanup - Make sure all usermode memory allocations are freed, when cleaning up the process pool. - Make sure that each object type is using the correct type of lock (either shared or exclusive, not a mixture) - Fix some object / reference leaks - Lots of inferface improvements - Use global variables for certain things instead of members in the mapped gdi handle table - Make IntSysCreateRectpRgn create a region without a handle - Fix detection od source and mask use in GreStretchBltMask - Use GDIOBJ_bLockMultipleObjects in NtGdiCombineRegion to avoid possible deadlocks - Fix NtGdiAbortPath to reset DCPATH_ACTIVE flag in the dc and only bail out on error, instead of always - Replace DC_AllocateDcAttr and DC_AllocDcAttr with DC_bAllocDcAttr using the new user mode pool - Remove DCU_SyncDcAttrtoUser and DCU_SynchDcAttrtoUser. Those functions were unused and didn't do anything useful anyway, - Replace IntGdiSetDCOwnerEx and DC_SetOwnership with GreSetDCOwner, remove unused NoSetBrush parameter - Replace GDIOBJ_bValidateHandle and IsObjectDead with GreIsHandleValid - Chage GDIOBJ_bLockMultipleObjects: pass object type, return a BOOL, whether all objects could be locked, cleanup on failure svn path=/trunk/; revision=51470
2011-04-28 08:26:46 +00:00
PalGDI = psurf->ppal;
for (Index = 0;
Index < 256 && Index < PalGDI->NumColors;
Index++)
{
bi->bmiColors[Index].rgbRed = PalGDI->IndexedColors[Index].peRed;
bi->bmiColors[Index].rgbGreen = PalGDI->IndexedColors[Index].peGreen;
bi->bmiColors[Index].rgbBlue = PalGDI->IndexedColors[Index].peBlue;
bi->bmiColors[Index].rgbReserved = 0;
}
}
Bmp = DIB_CreateDIBSection(Dc,
bi,
DIB_RGB_COLORS,
&Bits,
NULL,
0,
0);
return Bmp;
}
}
return Bmp;
}
HBITMAP APIENTRY
NtGdiCreateCompatibleBitmap(
HDC hDC,
INT Width,
INT Height)
{
HBITMAP Bmp;
PDC Dc;
/* Check parameters */
if ((Width <= 0) || (Height <= 0) || ((Width * Height) > 0x3FFFFFFF))
{
EngSetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
if (!hDC)
return GreCreateBitmap(Width, Height, 1, 1, 0);
Dc = DC_LockDc(hDC);
DPRINT("NtGdiCreateCompatibleBitmap(%p,%d,%d, bpp:%u) = \n",
hDC, Width, Height, Dc->ppdev->gdiinfo.cBitsPixel);
if (NULL == Dc)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return NULL;
}
Bmp = IntCreateCompatibleBitmap(Dc, Width, Height, 0, 0);
DC_UnlockDc(Dc);
return Bmp;
}
BOOL
NTAPI
GreGetBitmapDimension(
_In_ HBITMAP hBitmap,
_Out_ LPSIZE psizDim)
{
PSURFACE psurfBmp;
if (hBitmap == NULL)
return FALSE;
/* Lock the bitmap */
psurfBmp = SURFACE_ShareLockSurface(hBitmap);
if (psurfBmp == NULL)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
*psizDim = psurfBmp->sizlDim;
/* Unlock the bitmap */
SURFACE_ShareUnlockSurface(psurfBmp);
return TRUE;
}
BOOL
APIENTRY
NtGdiGetBitmapDimension(
HBITMAP hBitmap,
LPSIZE psizDim)
{
SIZE dim;
if (!GreGetBitmapDimension(hBitmap, &dim))
return FALSE;
/* Use SEH to copy the data to the caller */
_SEH2_TRY
{
ProbeForWrite(psizDim, sizeof(*psizDim), 1);
*psizDim = dim;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return FALSE);
}
_SEH2_END
return TRUE;
}
LONG
FASTCALL
UnsafeGetBitmapBits(
PSURFACE psurf,
DWORD Bytes,
OUT PBYTE pvBits)
{
PUCHAR pjDst, pjSrc;
LONG lDeltaDst, lDeltaSrc, lDeltaSrcAbs;
ULONG Y, iSrc, iDst, cbSrc, cbDst, nWidth, nHeight, cBitsPixel;
nWidth = psurf->SurfObj.sizlBitmap.cx;
nHeight = psurf->SurfObj.sizlBitmap.cy;
cBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
/* Get pointers */
pjSrc = psurf->SurfObj.pvScan0;
pjDst = pvBits;
lDeltaSrc = psurf->SurfObj.lDelta;
lDeltaSrcAbs = labs(lDeltaSrc);
lDeltaDst = WIDTH_BYTES_ALIGN16(nWidth, cBitsPixel);
NT_ASSERT(lDeltaSrcAbs >= lDeltaDst);
cbSrc = nHeight * lDeltaSrcAbs;
cbDst = nHeight * lDeltaDst;
Bytes = min(Bytes, cbDst);
iSrc = iDst = 0;
for (Y = 0; Y < nHeight; Y++)
{
if (iSrc + lDeltaSrcAbs > cbSrc || iDst + lDeltaDst > Bytes)
{
LONG lDelta = min(cbSrc - iSrc, Bytes - iDst);
NT_ASSERT(lDelta >= 0);
RtlCopyMemory(pjDst, pjSrc, lDelta);
iDst += lDelta;
break;
}
/* Copy one line */
RtlCopyMemory(pjDst, pjSrc, lDeltaDst);
pjSrc += lDeltaSrc;
pjDst += lDeltaDst;
iSrc += lDeltaSrcAbs;
iDst += lDeltaDst;
}
return iDst;
}
LONG
APIENTRY
NtGdiGetBitmapBits(
HBITMAP hBitmap,
ULONG cjBuffer,
OUT OPTIONAL PBYTE pUnsafeBits)
{
PSURFACE psurf;
ULONG cjSize;
LONG ret;
/* Check parameters */
if (pUnsafeBits != NULL && cjBuffer == 0)
{
return 0;
}
/* Lock the bitmap */
psurf = SURFACE_ShareLockSurface(hBitmap);
if (!psurf)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
/* Calculate the size of the bitmap in bytes */
cjSize = WIDTH_BYTES_ALIGN16(psurf->SurfObj.sizlBitmap.cx,
BitsPerFormat(psurf->SurfObj.iBitmapFormat)) *
psurf->SurfObj.sizlBitmap.cy;
XLATEOBJ rewrite. The new XLATEOBJ is not allocated from paged pool anymore, but instead allocated on the stack and Initialized. Only when we habe more than a color table with more than 6 entries, we need to allocate an additional buffer. The new interface: EXLATEOBJ_vInitialize is the main init function. It takes a source and destination palette and back and fore colors for monochome surfaces. EXLATEOBJ_vInitXlateFromDCs takes the source and dest DC and is for color translation between 2 surfaces represented by 2 DCs. EXLATEOBJ_vInitBrushXlate initializes an XLATEOBJ for a pattern brush. Finally EXLATEOBJ_vCleanup needs to be called when the XLATEOBJ is not needed anymore. Implement individual iXlate functions for certain cases and store a function pointer in the EXLATEOBJ structure for quick access. Change the usage of the PALETTE.Mode member to be a flag instead of an enum, add usage of PAL_MONOCHOME, PAL_RGB16_555 and PAL_RGB16_565. Add gpalMono, which *should* be used as palette for 1bpp DDBs. Currently there's a hack in the XLATEOBJ init code, to hack around the fact that this is missing. Fix the Hatch brush patterns, as they were inverted. Implement PALETTE_ulGetNearestBitFieldsIndex and PALETTE_ulGetNearestIndex. Get rid of the XLATEOBJ for the mouse pointer instead realize the pointer before usage. Get rid of logicalToSystem PALETTE member. NtGdiGetDIBitsInternal: Don't create a DIBBrush from the BITMAPINFO, when pvBits is NULL, as the function might be uninitualized. This fixes a crash of gdi_regtest. The whole function is quite ugly and needs to be rewritten (like probably the rest of the DIB code). This fixes the problem of artifacts in the selected desktop icons and some color problems. svn path=/trunk/; revision=42391
2009-08-04 20:37:10 +00:00
/* If the bits vector is null, the function should return the read size */
if (pUnsafeBits == NULL)
{
SURFACE_ShareUnlockSurface(psurf);
return cjSize;
}
/* Don't copy more bytes than the buffer has */
cjBuffer = min(cjBuffer, cjSize);
// FIXME: Use MmSecureVirtualMemory
_SEH2_TRY
{
ProbeForWrite(pUnsafeBits, cjBuffer, 1);
ret = UnsafeGetBitmapBits(psurf, cjBuffer, pUnsafeBits);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ret = 0;
}
_SEH2_END
SURFACE_ShareUnlockSurface(psurf);
return ret;
}
LONG APIENTRY
NtGdiSetBitmapBits(
HBITMAP hBitmap,
DWORD Bytes,
IN PBYTE pUnsafeBits)
{
LONG ret;
PSURFACE psurf;
if (pUnsafeBits == NULL || Bytes == 0)
{
return 0;
}
if (GDI_HANDLE_IS_STOCKOBJ(hBitmap))
{
return 0;
}
psurf = SURFACE_ShareLockSurface(hBitmap);
if (psurf == NULL)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
if (((psurf->flags & API_BITMAP) == 0) ||
(psurf->SurfObj.iBitmapFormat > BMF_32BPP))
{
DPRINT1("Invalid bitmap: iBitmapFormat = %lu, flags = 0x%lx\n",
psurf->SurfObj.iBitmapFormat,
psurf->flags);
EngSetLastError(ERROR_INVALID_HANDLE);
SURFACE_ShareUnlockSurface(psurf);
return 0;
}
_SEH2_TRY
{
/* NOTE: Win2k3 doesn't check WORD alignment here. */
ProbeForWrite(pUnsafeBits, Bytes, 1);
ret = UnsafeSetBitmapBits(psurf, Bytes, pUnsafeBits);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
ret = 0;
}
_SEH2_END
SURFACE_ShareUnlockSurface(psurf);
return ret;
}
BOOL APIENTRY
NtGdiSetBitmapDimension(
HBITMAP hBitmap,
INT Width,
INT Height,
LPSIZE Size)
{
PSURFACE psurf;
BOOL Ret = TRUE;
if (hBitmap == NULL)
return FALSE;
psurf = SURFACE_ShareLockSurface(hBitmap);
if (psurf == NULL)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
if (Size)
{
_SEH2_TRY
{
ProbeForWrite(Size, sizeof(SIZE), 1);
*Size = psurf->sizlDim;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Ret = FALSE;
}
_SEH2_END
}
/* The dimension is changed even if writing the old value failed */
psurf->sizlDim.cx = Width;
psurf->sizlDim.cy = Height;
SURFACE_ShareUnlockSurface(psurf);
return Ret;
}
/* Internal Functions */
HBITMAP
FASTCALL
BITMAP_CopyBitmap(HBITMAP hBitmap)
{
HBITMAP hbmNew;
SURFACE *psurfSrc, *psurfNew;
/* Fail, if no source bitmap is given */
if (hBitmap == NULL) return 0;
/* Lock the source bitmap */
psurfSrc = SURFACE_ShareLockSurface(hBitmap);
if (psurfSrc == NULL)
{
return 0;
}
/* Allocate a new bitmap with the same dimensions as the source bmp */
hbmNew = GreCreateBitmapEx(psurfSrc->SurfObj.sizlBitmap.cx,
psurfSrc->SurfObj.sizlBitmap.cy,
abs(psurfSrc->SurfObj.lDelta),
psurfSrc->SurfObj.iBitmapFormat,
psurfSrc->SurfObj.fjBitmap & BMF_TOPDOWN,
psurfSrc->SurfObj.cjBits,
NULL,
psurfSrc->flags);
if (hbmNew)
{
/* Lock the new bitmap */
psurfNew = SURFACE_ShareLockSurface(hbmNew);
if (psurfNew)
{
/* Copy the bitmap bits to the new bitmap buffer */
RtlCopyMemory(psurfNew->SurfObj.pvBits,
psurfSrc->SurfObj.pvBits,
psurfNew->SurfObj.cjBits);
/* Reference the palette of the source bitmap and use it */
SURFACE_vSetPalette(psurfNew, psurfSrc->ppal);
/* Unlock the new surface */
SURFACE_ShareUnlockSurface(psurfNew);
}
else
{
/* Failed to lock the bitmap, shouldn't happen */
GreDeleteObject(hbmNew);
hbmNew = NULL;
}
}
/* Unlock the source bitmap and return the handle of the new bitmap */
SURFACE_ShareUnlockSurface(psurfSrc);
return hbmNew;
}
INT APIENTRY
BITMAP_GetObject(SURFACE *psurf, INT Count, LPVOID buffer)
{
PBITMAP pBitmap;
if (!buffer) return sizeof(BITMAP);
if ((UINT)Count < sizeof(BITMAP)) return 0;
/* Always fill a basic BITMAP structure */
pBitmap = buffer;
pBitmap->bmType = 0;
pBitmap->bmWidth = psurf->SurfObj.sizlBitmap.cx;
pBitmap->bmHeight = psurf->SurfObj.sizlBitmap.cy;
pBitmap->bmPlanes = 1;
pBitmap->bmBitsPixel = BitsPerFormat(psurf->SurfObj.iBitmapFormat);
pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN16(pBitmap->bmWidth, pBitmap->bmBitsPixel);
/* Check for DIB section */
if (psurf->hSecure)
{
/* Set bmBits in this case */
pBitmap->bmBits = psurf->SurfObj.pvBits;
/* DIBs data are 32 bits aligned */
pBitmap->bmWidthBytes = WIDTH_BYTES_ALIGN32(pBitmap->bmWidth, pBitmap->bmBitsPixel);
if (Count >= sizeof(DIBSECTION))
{
/* Fill rest of DIBSECTION */
PDIBSECTION pds = buffer;
pds->dsBmih.biSize = sizeof(BITMAPINFOHEADER);
pds->dsBmih.biWidth = pds->dsBm.bmWidth;
pds->dsBmih.biHeight = pds->dsBm.bmHeight;
pds->dsBmih.biPlanes = pds->dsBm.bmPlanes;
pds->dsBmih.biBitCount = pds->dsBm.bmBitsPixel;
switch (psurf->SurfObj.iBitmapFormat)
{
case BMF_1BPP:
case BMF_4BPP:
case BMF_8BPP:
pds->dsBmih.biCompression = BI_RGB;
break;
case BMF_16BPP:
if (psurf->ppal->flFlags & PAL_RGB16_555)
pds->dsBmih.biCompression = BI_RGB;
else
pds->dsBmih.biCompression = BI_BITFIELDS;
break;
case BMF_24BPP:
case BMF_32BPP:
/* 24/32bpp BI_RGB is actually BGR format */
if (psurf->ppal->flFlags & PAL_BGR)
pds->dsBmih.biCompression = BI_RGB;
else
pds->dsBmih.biCompression = BI_BITFIELDS;
break;
case BMF_4RLE:
pds->dsBmih.biCompression = BI_RLE4;
break;
case BMF_8RLE:
pds->dsBmih.biCompression = BI_RLE8;
break;
case BMF_JPEG:
pds->dsBmih.biCompression = BI_JPEG;
break;
case BMF_PNG:
pds->dsBmih.biCompression = BI_PNG;
break;
default:
ASSERT(FALSE); /* This shouldn't happen */
}
pds->dsBmih.biSizeImage = psurf->SurfObj.cjBits;
pds->dsBmih.biXPelsPerMeter = 0;
pds->dsBmih.biYPelsPerMeter = 0;
pds->dsBmih.biClrUsed = psurf->ppal->NumColors;
pds->dsBmih.biClrImportant = psurf->biClrImportant;
pds->dsBitfields[0] = psurf->ppal->RedMask;
pds->dsBitfields[1] = psurf->ppal->GreenMask;
pds->dsBitfields[2] = psurf->ppal->BlueMask;
pds->dshSection = psurf->hDIBSection;
pds->dsOffset = psurf->dwOffset;
return sizeof(DIBSECTION);
}
}
else
{
/* Not set according to wine test, confirmed in win2k */
pBitmap->bmBits = NULL;
}
return sizeof(BITMAP);
}
/*
* @implemented
*/
HDC
APIENTRY
NtGdiGetDCforBitmap(
IN HBITMAP hsurf)
{
HDC hdc = NULL;
PSURFACE psurf = SURFACE_ShareLockSurface(hsurf);
if (psurf)
{
hdc = psurf->hdc;
SURFACE_ShareUnlockSurface(psurf);
}
return hdc;
}
/* EOF */