mirror of
https://github.com/reactos/reactos.git
synced 2025-01-03 21:09:19 +00:00
fc16259faf
Sync/Port: Metafile code from wine. Patches by Jacek Caban, Daniel Lehman, Zhiyi Zhang. Gabriel Ivancescu, Michael Stefaniuc, Francois Gouget, Nikolay Sivov Dmitry Timoshkov, Andrew EiKum, Piotr Caban and Alexandre Julliard. This commit is dedicated to George Bisoc!
947 lines
23 KiB
C
947 lines
23 KiB
C
#include <precomp.h>
|
|
|
|
#include <pseh/pseh2.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
bmBits = Bits;
|
|
hBitmap = NtGdiCreateDIBSection(hDC, hSection, dwOffset, pConvertedInfo, Usage,
|
|
ConvertedInfoSize, 0, // fl
|
|
0, // dwColorSpace
|
|
&bmBits);
|
|
|
|
if (BitmapInfo != pConvertedInfo)
|
|
RtlFreeHeap(RtlGetProcessHeap(), 0, pConvertedInfo);
|
|
|
|
if (!hBitmap)
|
|
{
|
|
bmBits = NULL;
|
|
}
|
|
}
|
|
|
|
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 (!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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
|
|
if (!ScanLines || !lpbmi || !Bits)
|
|
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;
|
|
|
|
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.....
|
|
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))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
/*
|
|
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);
|
|
}
|
|
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))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return 0;
|
|
}
|
|
/*
|
|
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 );
|
|
}
|
|
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 );;
|
|
}
|
|
|
|
|