reactos/win32ss/gdi/gdi32/objects/bitmap.c
Hermès Bélusca-Maïto e4c4894564
[GDI32] CreateDIBSection: Remove erroneous assignation (#5502)
bmBits is only used and assigned on output. It points (holds the address)
to the array of DIB bit values. The "Bits" parameter is however a pointer
to a variable that will receive the address of that array.
So it makes no sense to initially assign bmBits to the value of the Bits
parameter...
2023-08-06 17:35:23 +02:00

1208 lines
31 KiB
C

#include <precomp.h>
#include <pseh/pseh2.h>
#define NDEBUG
#include <debug.h>
/* Copied from win32ss/gdi/eng/surface.c */
ULONG
FASTCALL
BitmapFormat(ULONG cBits, ULONG iCompression)
{
switch (iCompression)
{
case BI_RGB:
/* Fall through */
case BI_BITFIELDS:
if (cBits <= 1) return BMF_1BPP;
if (cBits <= 4) return BMF_4BPP;
if (cBits <= 8) return BMF_8BPP;
if (cBits <= 16) return BMF_16BPP;
if (cBits <= 24) return BMF_24BPP;
if (cBits <= 32) return BMF_32BPP;
return 0;
case BI_RLE4:
return BMF_4RLE;
case BI_RLE8:
return BMF_8RLE;
default:
return 0;
}
}
/* Copied from win32ss/gdi/eng/surface.c */
UCHAR
gajBitsPerFormat[11] =
{
0, /* 0: unused */
1, /* 1: BMF_1BPP */
4, /* 2: BMF_4BPP */
8, /* 3: BMF_8BPP */
16, /* 4: BMF_16BPP */
24, /* 5: BMF_24BPP */
32, /* 6: BMF_32BPP */
4, /* 7: BMF_4RLE */
8, /* 8: BMF_8RLE */
0, /* 9: BMF_JPEG */
0, /* 10: BMF_PNG */
};
// From Yuan, ScanLineSize = (Width * bitcount + 31)/32
#define WIDTH_BYTES_ALIGN32(cx, bpp) ((((cx) * (bpp) + 31) & ~31) >> 3)
/*
* DIB_BitmapInfoSize
*
* Return the size of the bitmap info structure including color table.
* 11/16/1999 (RJJ) lifted from wine
*/
INT
FASTCALL DIB_BitmapInfoSize(
const BITMAPINFO * info,
WORD coloruse,
BOOL max)
{
unsigned int colors, size, masks = 0;
if (info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
const BITMAPCOREHEADER *core = (const BITMAPCOREHEADER *) info;
size = sizeof(BITMAPCOREHEADER);
if (core->bcBitCount <= 8)
{
colors = 1 << core->bcBitCount;
if (coloruse == DIB_RGB_COLORS)
size += colors * sizeof(RGBTRIPLE);
else
size += colors * sizeof(WORD);
}
return size;
}
else /* assume BITMAPINFOHEADER */
{
colors = max ? (1 << info->bmiHeader.biBitCount) : info->bmiHeader.biClrUsed;
if (colors > 256)
colors = 256;
if (!colors && (info->bmiHeader.biBitCount <= 8))
colors = 1 << info->bmiHeader.biBitCount;
if (info->bmiHeader.biCompression == BI_BITFIELDS)
masks = 3;
size = max(info->bmiHeader.biSize, sizeof(BITMAPINFOHEADER) + masks * sizeof(DWORD));
return size + colors * ((coloruse == DIB_RGB_COLORS) ? sizeof(RGBQUAD) : sizeof(WORD));
}
}
/*
* Return the full scan size for a bitmap.
*
* Based on Wine, Utils.c and Windows Graphics Prog pg 595, SDK amvideo.h.
*/
UINT
FASTCALL
DIB_BitmapMaxBitsSize(
PBITMAPINFO Info,
UINT ScanLines)
{
UINT Ret;
if (!Info)
return 0;
if (Info->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
PBITMAPCOREHEADER Core = (PBITMAPCOREHEADER) Info;
Ret = WIDTH_BYTES_ALIGN32(Core->bcWidth * Core->bcPlanes,
Core->bcBitCount) * ScanLines;
}
else /* assume BITMAPINFOHEADER */
{
if ((Info->bmiHeader.biCompression == BI_RGB) || (Info->bmiHeader.biCompression == BI_BITFIELDS))
{
Ret = WIDTH_BYTES_ALIGN32(
Info->bmiHeader.biWidth * Info->bmiHeader.biPlanes,
Info->bmiHeader.biBitCount) * ScanLines;
}
else
{
Ret = Info->bmiHeader.biSizeImage;
}
}
return Ret;
}
/*
* DIB_GetBitmapInfo is complete copy of wine cvs 2/9-2006
* from file dib.c from gdi32.dll or orginal version
* did not calc the info right for some headers.
*/
INT
WINAPI
DIB_GetBitmapInfo(
const BITMAPINFOHEADER *header,
PLONG width,
PLONG height,
PWORD planes,
PWORD bpp,
PLONG compr,
PLONG size)
{
if (header->biSize == sizeof(BITMAPCOREHEADER))
{
BITMAPCOREHEADER *core = (BITMAPCOREHEADER *) header;
*width = core->bcWidth;
*height = core->bcHeight;
*planes = core->bcPlanes;
*bpp = core->bcBitCount;
*compr = 0;
*size = 0;
return 0;
}
if (header->biSize == sizeof(BITMAPINFOHEADER))
{
*width = header->biWidth;
*height = header->biHeight;
*planes = header->biPlanes;
*bpp = header->biBitCount;
*compr = header->biCompression;
*size = header->biSizeImage;
return 1;
}
if (header->biSize == sizeof(BITMAPV4HEADER))
{
BITMAPV4HEADER *v4hdr = (BITMAPV4HEADER *) header;
*width = v4hdr->bV4Width;
*height = v4hdr->bV4Height;
*planes = v4hdr->bV4Planes;
*bpp = v4hdr->bV4BitCount;
*compr = v4hdr->bV4V4Compression;
*size = v4hdr->bV4SizeImage;
return 4;
}
if (header->biSize == sizeof(BITMAPV5HEADER))
{
BITMAPV5HEADER *v5hdr = (BITMAPV5HEADER *) header;
*width = v5hdr->bV5Width;
*height = v5hdr->bV5Height;
*planes = v5hdr->bV5Planes;
*bpp = v5hdr->bV5BitCount;
*compr = v5hdr->bV5Compression;
*size = v5hdr->bV5SizeImage;
return 5;
}
DPRINT("(%lu): wrong size for header\n", header->biSize);
return -1;
}
/*
* @implemented
*/
int
WINAPI
GdiGetBitmapBitsSize(
BITMAPINFO *lpbmi)
{
UINT Ret;
if (!lpbmi)
return 0;
if (lpbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
PBITMAPCOREHEADER Core = (PBITMAPCOREHEADER) lpbmi;
Ret =
WIDTH_BYTES_ALIGN32(Core->bcWidth * Core->bcPlanes,
Core->bcBitCount) * Core->bcHeight;
}
else /* assume BITMAPINFOHEADER */
{
if (!(lpbmi->bmiHeader.biCompression) || (lpbmi->bmiHeader.biCompression == BI_BITFIELDS))
{
Ret = WIDTH_BYTES_ALIGN32(
lpbmi->bmiHeader.biWidth * lpbmi->bmiHeader.biPlanes,
lpbmi->bmiHeader.biBitCount) * abs(lpbmi->bmiHeader.biHeight);
}
else
{
Ret = lpbmi->bmiHeader.biSizeImage;
}
}
return Ret;
}
/*
* @implemented
*/
HBITMAP
WINAPI
CreateDIBSection(
HDC hDC,
CONST BITMAPINFO *BitmapInfo,
UINT Usage,
VOID **Bits,
HANDLE hSection,
DWORD dwOffset)
{
PBITMAPINFO pConvertedInfo;
UINT ConvertedInfoSize;
HBITMAP hBitmap = NULL;
PVOID bmBits = NULL;
pConvertedInfo = ConvertBitmapInfo(BitmapInfo,
Usage,
&ConvertedInfoSize,
FALSE);
if (pConvertedInfo)
{
// Verify header due to converted may == info.
if (pConvertedInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
{
if (pConvertedInfo->bmiHeader.biCompression == BI_JPEG ||
pConvertedInfo->bmiHeader.biCompression == BI_PNG)
{
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}
}
hBitmap = NtGdiCreateDIBSection(hDC,
hSection,
dwOffset,
pConvertedInfo,
Usage,
ConvertedInfoSize,
0, // fl
0, // dwColorSpace
&bmBits);
if (!hBitmap)
bmBits = NULL;
if (BitmapInfo != pConvertedInfo)
RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo);
}
if (Bits)
*Bits = bmBits;
return hBitmap;
}
/*
* @implemented
*/
HBITMAP
WINAPI
CreateBitmap(
INT Width,
INT Height,
UINT Planes,
UINT BitsPixel,
CONST VOID* pUnsafeBits)
{
if (Width && Height)
{
return NtGdiCreateBitmap(Width, Height, Planes, BitsPixel, (LPBYTE) pUnsafeBits);
}
else
{
/* Return 1x1 bitmap */
return GetStockObject(DEFAULT_BITMAP);
}
}
/*
* @implemented
*/
HBITMAP
WINAPI
CreateBitmapIndirect(
const BITMAP *pbm)
{
HBITMAP bitmap = NULL;
/* Note windows xp/2003 does not check if pbm is NULL or not */
if ((pbm->bmWidthBytes != 0) && (!(pbm->bmWidthBytes & 1)))
{
bitmap = CreateBitmap(pbm->bmWidth, pbm->bmHeight, pbm->bmPlanes, pbm->bmBitsPixel,
pbm->bmBits);
}
else
{
SetLastError(ERROR_INVALID_PARAMETER);
}
return bitmap;
}
HBITMAP
WINAPI
CreateDiscardableBitmap(
HDC hDC,
INT Width,
INT Height)
{
return CreateCompatibleBitmap(hDC, Width, Height);
}
HBITMAP
WINAPI
CreateCompatibleBitmap(
HDC hDC,
INT Width,
INT Height)
{
PDC_ATTR pDc_Attr;
if (!GdiGetHandleUserData(hDC, GDI_OBJECT_TYPE_DC, (PVOID) & pDc_Attr))
return NULL;
if (!Width || !Height)
return GetStockObject(DEFAULT_BITMAP);
if (!(pDc_Attr->ulDirty_ & DC_DIBSECTION))
{
return NtGdiCreateCompatibleBitmap(hDC, Width, Height);
}
else
{
HBITMAP hBmp = NULL;
struct
{
BITMAP bitmap;
BITMAPINFOHEADER bmih;
RGBQUAD rgbquad[256];
} buffer;
DIBSECTION* pDIBs = (DIBSECTION*) &buffer;
BITMAPINFO* pbmi = (BITMAPINFO*) &buffer.bmih;
hBmp = NtGdiGetDCObject(hDC, GDI_OBJECT_TYPE_BITMAP);
if (GetObjectA(hBmp, sizeof(DIBSECTION), pDIBs) != sizeof(DIBSECTION))
return NULL;
if (pDIBs->dsBm.bmBitsPixel <= 8)
GetDIBColorTable(hDC, 0, 256, buffer.rgbquad);
pDIBs->dsBmih.biWidth = Width;
pDIBs->dsBmih.biHeight = Height;
return CreateDIBSection(hDC, pbmi, DIB_RGB_COLORS, NULL, NULL, 0);
}
return NULL;
}
INT
WINAPI
GetDIBits(
HDC hDC,
HBITMAP hbmp,
UINT uStartScan,
UINT cScanLines,
LPVOID lpvBits,
LPBITMAPINFO lpbmi,
UINT uUsage)
{
UINT cjBmpScanSize;
UINT cjInfoSize;
if (!hDC || !GdiValidateHandle((HGDIOBJ) hDC) || !lpbmi)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
cjBmpScanSize = DIB_BitmapMaxBitsSize(lpbmi, cScanLines);
/* Caller must provide maximum size possible */
cjInfoSize = DIB_BitmapInfoSize(lpbmi, uUsage, TRUE);
if (lpvBits)
{
if (lpbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
{
if (lpbmi->bmiHeader.biCompression == BI_JPEG
|| lpbmi->bmiHeader.biCompression == BI_PNG)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
}
}
return NtGdiGetDIBitsInternal(hDC, hbmp, uStartScan, cScanLines, lpvBits, lpbmi, uUsage,
cjBmpScanSize, cjInfoSize);
}
/*
* @implemented
*/
HBITMAP
WINAPI
CreateDIBitmap(
HDC hDC,
const BITMAPINFOHEADER *Header,
DWORD Init,
LPCVOID Bits,
const BITMAPINFO *Data,
UINT ColorUse)
{
LONG Width, Height, Compression, DibSize;
WORD Planes, BitsPerPixel;
// PDC_ATTR pDc_Attr;
UINT cjBmpScanSize = 0;
HBITMAP hBitmap = NULL;
PBITMAPINFO pbmiConverted;
UINT cjInfoSize;
/* Convert the BITMAPINFO if it is a COREINFO */
pbmiConverted = ConvertBitmapInfo(Data, ColorUse, &cjInfoSize, FALSE);
/* Check for CBM_CREATDIB */
if (Init & CBM_CREATDIB)
{
if (cjInfoSize == 0)
{
goto Exit;
}
else if (Init & CBM_INIT)
{
if (Bits == NULL)
{
goto Exit;
}
}
else
{
Bits = NULL;
}
/* CBM_CREATDIB needs Data. */
if (pbmiConverted == NULL)
{
DPRINT1("CBM_CREATDIB needs a BITMAPINFO!\n");
goto Exit;
}
/* It only works with PAL or RGB */
if (ColorUse > DIB_PAL_COLORS)
{
DPRINT1("Invalid ColorUse: %lu\n", ColorUse);
GdiSetLastError(ERROR_INVALID_PARAMETER);
goto Exit;
}
/* Use the header from the data */
Header = &Data->bmiHeader;
}
else
{
if (Init & CBM_INIT)
{
if (Bits != NULL)
{
if (cjInfoSize == 0)
{
goto Exit;
}
}
else
{
Init &= ~CBM_INIT;
}
}
}
/* Header is required */
if (!Header)
{
DPRINT1("Header is NULL\n");
GdiSetLastError(ERROR_INVALID_PARAMETER);
goto Exit;
}
/* Get the bitmap format and dimensions */
if (DIB_GetBitmapInfo(Header, &Width, &Height, &Planes, &BitsPerPixel, &Compression, &DibSize) == -1)
{
DPRINT1("DIB_GetBitmapInfo failed!\n");
GdiSetLastError(ERROR_INVALID_PARAMETER);
goto Exit;
}
/* Check if the Compr is incompatible */
if ((Compression == BI_JPEG) || (Compression == BI_PNG))
{
DPRINT1("Invalid compression: %lu!\n", Compression);
goto Exit;
}
/* Only DIB_RGB_COLORS (0), DIB_PAL_COLORS (1) and 2 are valid. */
if (ColorUse > DIB_PAL_COLORS + 1)
{
DPRINT1("Invalid compression: %lu!\n", Compression);
GdiSetLastError(ERROR_INVALID_PARAMETER);
goto Exit;
}
/* If some Bits are given, only DIB_PAL_COLORS and DIB_RGB_COLORS are valid */
if (Bits && (ColorUse > DIB_PAL_COLORS))
{
DPRINT1("Invalid ColorUse: %lu\n", ColorUse);
GdiSetLastError(ERROR_INVALID_PARAMETER);
goto Exit;
}
/* Negative width is not allowed */
if (Width < 0)
{
DPRINT1("Negative width: %li\n", Width);
goto Exit;
}
/* Top-down DIBs have a negative height. */
Height = abs(Height);
// For Icm support.
// GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID)&pDc_Attr))
cjBmpScanSize = GdiGetBitmapBitsSize(pbmiConverted);
DPRINT("pBMI %p, Size bpp %u, dibsize %d, Conv %u, BSS %u\n",
Data, BitsPerPixel, DibSize, cjInfoSize, cjBmpScanSize);
if (!Width || !Height)
{
hBitmap = GetStockObject(DEFAULT_BITMAP);
}
else
{
hBitmap = NtGdiCreateDIBitmapInternal(hDC,
Width,
Height,
Init,
(LPBYTE)Bits,
(LPBITMAPINFO)pbmiConverted,
ColorUse,
cjInfoSize,
cjBmpScanSize,
0, 0);
}
Exit:
/* Cleanup converted BITMAPINFO */
if ((pbmiConverted != NULL) && (pbmiConverted != Data))
{
RtlFreeHeap(RtlGetProcessHeap(), 0, pbmiConverted);
}
return hBitmap;
}
/*
* @implemented
*/
INT
WINAPI
SetDIBits(
HDC hDC,
HBITMAP hBitmap,
UINT uStartScan,
UINT cScanLines,
CONST VOID *lpvBits,
CONST BITMAPINFO *lpbmi,
UINT fuColorUse)
{
HDC hDCc, SavehDC, nhDC;
DWORD dwWidth, dwHeight;
HGDIOBJ hOldBitmap;
HPALETTE hPal = NULL;
INT LinesCopied = 0;
BOOL newDC = FALSE;
if (fuColorUse != DIB_RGB_COLORS && fuColorUse != DIB_PAL_COLORS)
return 0;
if (!lpvBits || (GDI_HANDLE_GET_TYPE(hBitmap) != GDI_OBJECT_TYPE_BITMAP))
return 0;
if (lpbmi->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER))
{
if (lpbmi->bmiHeader.biCompression == BI_JPEG
|| lpbmi->bmiHeader.biCompression == BI_PNG)
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
}
if (lpbmi->bmiHeader.biCompression == BI_BITFIELDS)
{
DWORD *masks = (DWORD *)lpbmi->bmiColors;
if (!masks[0] || !masks[1] || !masks[2])
{
SetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
}
hDCc = NtGdiGetDCforBitmap(hBitmap); // hDC can be NULL, so, get it from the bitmap.
SavehDC = hDCc;
if (!hDCc) // No DC associated with bitmap, Clone or Create one.
{
nhDC = CreateCompatibleDC(hDC);
if (!nhDC)
return 0;
newDC = TRUE;
SavehDC = nhDC;
}
else if (!SaveDC(hDCc))
return 0;
hOldBitmap = SelectObject(SavehDC, hBitmap);
if (hOldBitmap)
{
if (hDC)
hPal = SelectPalette(SavehDC, (HPALETTE) GetCurrentObject(hDC, OBJ_PAL), FALSE);
if (lpbmi->bmiHeader.biSize < sizeof(BITMAPINFOHEADER))
{
PBITMAPCOREINFO pbci = (PBITMAPCOREINFO) lpbmi;
dwWidth = pbci->bmciHeader.bcWidth;
dwHeight = pbci->bmciHeader.bcHeight;
}
else
{
dwWidth = lpbmi->bmiHeader.biWidth;
dwHeight = abs(lpbmi->bmiHeader.biHeight);
}
LinesCopied = SetDIBitsToDevice(SavehDC, 0, 0, dwWidth, dwHeight, 0, 0, uStartScan,
cScanLines, (void *) lpvBits, (LPBITMAPINFO) lpbmi, fuColorUse);
if (hDC)
SelectPalette(SavehDC, hPal, FALSE);
SelectObject(SavehDC, hOldBitmap);
}
if (newDC)
DeleteDC(SavehDC);
else
RestoreDC(SavehDC, -1);
return LinesCopied;
}
/*
* @implemented
*
*/
INT
WINAPI
SetDIBitsToDevice(
HDC hdc,
int XDest,
int YDest,
DWORD Width,
DWORD Height,
int XSrc,
int YSrc,
UINT StartScan,
UINT ScanLines,
CONST VOID *Bits,
CONST BITMAPINFO *lpbmi,
UINT ColorUse)
{
PDC_ATTR pDc_Attr;
PBITMAPINFO pConvertedInfo;
UINT ConvertedInfoSize;
INT LinesCopied = 0;
UINT cjBmpScanSize = 0;
BOOL Hit = FALSE;
PVOID pvSafeBits = (PVOID) Bits;
UINT bmiHeight;
BOOL top_down;
INT src_y = 0;
ULONG iFormat, cBitsPixel, cjBits, cjWidth;
#define MaxScanLines 1000
#define MaxHeight 2000
#define MaxSourceHeight 2000
#define IS_ALIGNED(Pointer, Alignment) \
(((ULONG_PTR)(void *)(Pointer)) % (Alignment) == 0)
if (!ScanLines || !lpbmi || !Bits)
return 0;
DPRINT("ScanLines %d Height %d Width %d biHeight %d biWidth %d\n"
" lpbmi '%p' ColorUse '%d' SizeImage '%d' StartScan %d\n"
" biCompression '%d' biBitCount '%d'\n",
ScanLines, Height, Width, lpbmi->bmiHeader.biHeight,
lpbmi->bmiHeader.biWidth, lpbmi, ColorUse,
lpbmi->bmiHeader.biSizeImage, StartScan,
lpbmi->bmiHeader.biCompression, lpbmi->bmiHeader.biBitCount);
if (lpbmi->bmiHeader.biWidth < 0)
return 0;
if (ColorUse && ColorUse != DIB_PAL_COLORS && ColorUse != DIB_PAL_COLORS + 1)
return 0;
pConvertedInfo = ConvertBitmapInfo(lpbmi, ColorUse, &ConvertedInfoSize, FALSE);
if (!pConvertedInfo)
return 0;
if (ScanLines > MaxScanLines)
{
LinesCopied = 0;
goto Exit;
}
bmiHeight = abs(pConvertedInfo->bmiHeader.biHeight);
top_down = (pConvertedInfo->bmiHeader.biHeight < 0);
if ((StartScan > bmiHeight) && (ScanLines > bmiHeight))
{
DPRINT("Returning ScanLines of '%d'\n", ScanLines);
LinesCopied = ScanLines;
goto Exit;
}
if (pConvertedInfo->bmiHeader.biHeight == 0)
{
LinesCopied = 0;
goto Exit;
}
if (!IS_ALIGNED(Bits, 2) && (ScanLines > Height))
{
LinesCopied = 0;
goto Exit;
}
/* Below code modeled after Wine's nulldrv_SetDIBitsToDevice */
if (StartScan <= YSrc + bmiHeight)
{
if ((pConvertedInfo->bmiHeader.biCompression == BI_RLE8) ||
(pConvertedInfo->bmiHeader.biCompression == BI_RLE4))
{
StartScan = 0;
ScanLines = bmiHeight;
}
else
{
if (StartScan >= bmiHeight)
{
LinesCopied = 0;
goto Exit;
}
if (!top_down && ScanLines > bmiHeight - StartScan)
{
ScanLines = bmiHeight - StartScan;
}
src_y = StartScan + ScanLines - (YSrc + Height);
if (!top_down)
{
/* get rid of unnecessary lines */
if ((src_y < 0 || src_y >= (INT)ScanLines) &&
pConvertedInfo->bmiHeader.biCompression != BI_BITFIELDS)
{
LinesCopied = ScanLines;
goto Exit;
}
if (YDest >= 0)
{
LinesCopied = ScanLines + StartScan;
ScanLines -= src_y;
}
else
{
LinesCopied = ScanLines - src_y;
}
}
else if (src_y < 0 || src_y >= (INT)ScanLines)
{
if (lpbmi->bmiHeader.biHeight < 0 &&
StartScan > MaxScanLines)
{
ScanLines = lpbmi->bmiHeader.biHeight - StartScan;
}
DPRINT("Returning ScanLines of '%d'\n", ScanLines);
LinesCopied = ScanLines;
goto Exit;
}
else
{
LinesCopied = ScanLines;
}
}
}
HANDLE_METADC(INT,
SetDIBitsToDevice,
0,
hdc,
XDest,
YDest,
Width,
Height,
XSrc,
YSrc,
StartScan,
ScanLines,
Bits,
lpbmi,
ColorUse);
// Handle the "Special Case"!
{
PLDC pldc;
ULONG hType = GDI_HANDLE_GET_TYPE(hdc);
if (hType != GDILoObjType_LO_DC_TYPE && hType != GDILoObjType_LO_METADC16_TYPE)
{
pldc = GdiGetLDC(hdc);
if (pldc)
{
if (pldc->Flags & LDC_STARTPAGE) StartPage(hdc);
if (pldc->Flags & LDC_SAPCALLBACK) GdiSAPCallback(pldc);
if (pldc->Flags & LDC_KILL_DOCUMENT)
{
LinesCopied = 0;
goto Exit;
}
}
else
{
SetLastError(ERROR_INVALID_HANDLE);
LinesCopied = 0;
goto Exit;
}
}
}
if ((pConvertedInfo->bmiHeader.biCompression == BI_RLE8) ||
(pConvertedInfo->bmiHeader.biCompression == BI_RLE4))
{
/* For compressed data, we must set the whole thing */
StartScan = 0;
ScanLines = pConvertedInfo->bmiHeader.biHeight;
}
cjBmpScanSize = DIB_BitmapMaxBitsSize((LPBITMAPINFO) lpbmi, ScanLines);
pvSafeBits = RtlAllocateHeap(GetProcessHeap(), 0, cjBmpScanSize);
if (pvSafeBits)
{
_SEH2_TRY
{
RtlCopyMemory(pvSafeBits, Bits, cjBmpScanSize);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Hit = TRUE;
}
_SEH2_END;
if (Hit)
{
// We don't die, we continue on with a allocated safe pointer to kernel
// space.....
if (!IS_ALIGNED(Bits, 2)) // If both Read Exception and mis-aligned
{
LinesCopied = 0;
goto Exit;
}
DPRINT1("SetDIBitsToDevice fail to read BitMapInfo: %p or Bits: %p & Size: %u\n",
pConvertedInfo, Bits, cjBmpScanSize);
}
DPRINT("SetDIBitsToDevice Allocate Bits %u!!!\n", cjBmpScanSize);
}
if (!GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID) & pDc_Attr))
{
DPRINT1("SetDIBitsToDevice called on invalid DC %p (not owned?)\n", hdc);
SetLastError(ERROR_INVALID_PARAMETER);
LinesCopied = 0;
goto Exit;
}
/* Calculation of ScanLines for NtGdiSetDIBitsToDeviceInternal */
if (YDest >= 0)
{
ScanLines = min(abs(Height), ScanLines);
if (YSrc > 0)
ScanLines += YSrc;
}
else
{
ScanLines = min(ScanLines,
abs(pConvertedInfo->bmiHeader.biHeight) - StartScan);
}
if (YDest >= 0 && YSrc > 0 && bmiHeight <= MaxHeight)
{
ScanLines += YSrc;
}
/* Find Format from lpbmi which is now pConvertedInfo */
iFormat = BitmapFormat(pConvertedInfo->bmiHeader.biBitCount,
pConvertedInfo->bmiHeader.biCompression);
/* Get bits per pixel from the format */
cBitsPixel = gajBitsPerFormat[iFormat];
cjWidth = WIDTH_BYTES_ALIGN32(pConvertedInfo->bmiHeader.biWidth, cBitsPixel);
/* Calculate the correct bitmap size in bytes */
if (!NT_SUCCESS(RtlULongMult(cjWidth, max(ScanLines, LinesCopied), &cjBits)))
{
DPRINT1("Overflow calculating size: cjWidth %lu, ScanLines %lu\n",
cjWidth, max(ScanLines, LinesCopied));
goto Exit;
}
/* Make sure the buffer is large enough */
if (pConvertedInfo->bmiHeader.biSizeImage < cjBits)
{
DPRINT("Buffer is too small, required: %lu, got %lu\n",
cjBits, pConvertedInfo->bmiHeader.biSizeImage);
if (pConvertedInfo->bmiHeader.biCompression == BI_RGB)
{
pConvertedInfo->bmiHeader.biSizeImage = cjBits;
}
}
/*
if ( !pDc_Attr || // DC is Public
ColorUse == DIB_PAL_COLORS ||
((pConvertedInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
(pConvertedInfo->bmiHeader.biCompression == BI_JPEG ||
pConvertedInfo->bmiHeader.biCompression == BI_PNG )) )*/
{
LinesCopied = NtGdiSetDIBitsToDeviceInternal(hdc, XDest, YDest,
Width, Height, XSrc, YSrc,
StartScan, ScanLines, (LPBYTE) pvSafeBits,
(LPBITMAPINFO) pConvertedInfo, ColorUse,
cjBmpScanSize, ConvertedInfoSize,
TRUE,
NULL);
}
if (bmiHeight > MaxScanLines)
{
LinesCopied = ScanLines;
}
if (YDest < 0)
{
if (top_down)
LinesCopied = ScanLines;
else
LinesCopied = ScanLines - src_y;
}
if (pConvertedInfo->bmiHeader.biCompression == BI_RLE8 ||
pConvertedInfo->bmiHeader.biCompression == BI_RLE4)
{
LinesCopied = bmiHeight;
}
if (pConvertedInfo->bmiHeader.biHeight < 0)
{
if (pConvertedInfo->bmiHeader.biHeight < -MaxSourceHeight ||
(YDest >= 0 && src_y < -ScanLines))
{
LinesCopied = ScanLines + src_y;
}
else
{
LinesCopied = ScanLines;
}
}
Exit:
if (Bits != pvSafeBits)
RtlFreeHeap(RtlGetProcessHeap(), 0, pvSafeBits);
if (lpbmi != pConvertedInfo)
RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo);
return LinesCopied;
}
/*
* @unimplemented
*/
int
WINAPI
StretchDIBits(
HDC hdc,
int XDest,
int YDest,
int nDestWidth,
int nDestHeight,
int XSrc,
int YSrc,
int nSrcWidth,
int nSrcHeight,
CONST VOID *lpBits,
CONST BITMAPINFO *lpBitsInfo,
UINT iUsage,
DWORD dwRop)
{
PDC_ATTR pDc_Attr;
PBITMAPINFO pConvertedInfo = NULL;
UINT ConvertedInfoSize = 0;
INT LinesCopied = 0;
UINT cjBmpScanSize = 0;
PVOID pvSafeBits = NULL;
BOOL Hit = FALSE;
DPRINT("StretchDIBits %p : %p : %u\n", lpBits, lpBitsInfo, iUsage);
HANDLE_METADC( int,
StretchDIBits,
0,
hdc,
XDest,
YDest,
nDestWidth,
nDestHeight,
XSrc,
YSrc,
nSrcWidth,
nSrcHeight,
lpBits,
lpBitsInfo,
iUsage,
dwRop );
if ( GdiConvertAndCheckDC(hdc) == NULL ) return 0;
pConvertedInfo = ConvertBitmapInfo(lpBitsInfo, iUsage, &ConvertedInfoSize, FALSE);
if (!pConvertedInfo)
{
return 0;
}
cjBmpScanSize = GdiGetBitmapBitsSize((BITMAPINFO *) pConvertedInfo);
if (lpBits)
{
pvSafeBits = RtlAllocateHeap(GetProcessHeap(), 0, cjBmpScanSize);
if (pvSafeBits)
{
_SEH2_TRY
{
RtlCopyMemory(pvSafeBits, lpBits, cjBmpScanSize);
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Hit = TRUE;
}
_SEH2_END
if (Hit)
{
// We don't die, we continue on with a allocated safe pointer to kernel
// space.....
DPRINT1("StretchDIBits fail to read BitMapInfo: %p or Bits: %p & Size: %u\n",
pConvertedInfo, lpBits, cjBmpScanSize);
}
DPRINT("StretchDIBits Allocate Bits %u!!!\n", cjBmpScanSize);
}
}
if (!GdiGetHandleUserData(hdc, GDI_OBJECT_TYPE_DC, (PVOID) & pDc_Attr))
{
DPRINT1("StretchDIBits called on invalid DC %p (not owned?)\n", hdc);
SetLastError(ERROR_INVALID_PARAMETER);
LinesCopied = 0;
goto Exit;
}
/*
if ( !pDc_Attr ||
iUsage == DIB_PAL_COLORS ||
((pConvertedInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) &&
(pConvertedInfo->bmiHeader.biCompression == BI_JPEG ||
pConvertedInfo->bmiHeader.biCompression == BI_PNG )) )*/
{
LinesCopied = NtGdiStretchDIBitsInternal( hdc,
XDest,
YDest,
nDestWidth,
nDestHeight,
XSrc,
YSrc,
nSrcWidth,
nSrcHeight,
pvSafeBits,
pConvertedInfo,
(DWORD) iUsage,
dwRop,
ConvertedInfoSize,
cjBmpScanSize,
NULL );
}
Exit:
if (pvSafeBits)
RtlFreeHeap(RtlGetProcessHeap(), 0, pvSafeBits);
if (lpBitsInfo != pConvertedInfo)
RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo);
return LinesCopied;
}
/*
* @implemented
*/
DWORD
WINAPI
GetBitmapAttributes(HBITMAP hbm)
{
if ( GDI_HANDLE_IS_STOCKOBJ(hbm) )
{
return SC_BB_STOCKOBJ;
}
return 0;
}
/*
* @implemented
*/
HBITMAP
WINAPI
SetBitmapAttributes(HBITMAP hbm, DWORD dwFlags)
{
if ( dwFlags & ~SC_BB_STOCKOBJ )
{
return NULL;
}
return NtGdiSetBitmapAttributes( hbm, dwFlags );
}
/*
* @implemented
*/
HBITMAP
WINAPI
ClearBitmapAttributes(HBITMAP hbm, DWORD dwFlags)
{
if ( dwFlags & ~SC_BB_STOCKOBJ )
{
return NULL;
}
return NtGdiClearBitmapAttributes( hbm, dwFlags );;
}