mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 18:15:11 +00:00
090ccb3d8e
Also fix an old copy-pasta.
888 lines
23 KiB
C
888 lines
23 KiB
C
/*
|
|
* 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)
|
|
{
|
|
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 != DCTYPE_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);
|
|
if (Bmp == NULL)
|
|
{
|
|
DPRINT1("Failed to allocate a bitmap!\n");
|
|
return 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:
|
|
psurfBmp->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;
|
|
}
|
|
|
|
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;
|
|
|
|
/* 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 */
|