Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1381 lines
36 KiB

/******************************Module*Header*******************************\
* Module Name: bitmap.c *
* *
* Client side stubs that move bitmaps over the C/S interface. *
* *
* Created: 14-May-1991 11:04:49 *
* Author: Eric Kutter [erick] *
* *
* Copyright (c) 1991 Microsoft Corporation *
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
ULONG cjBitmapBitsSize(CONST BITMAPINFO *pbmi)
{
// Check for PM-style DIB
if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
LPBITMAPCOREINFO pbmci;
pbmci = (LPBITMAPCOREINFO)pbmi;
return(CJSCAN(pbmci->bmciHeader.bcWidth,pbmci->bmciHeader.bcPlanes,
pbmci->bmciHeader.bcBitCount) *
pbmci->bmciHeader.bcHeight);
}
// not a core header
if ((pbmi->bmiHeader.biCompression == BI_RGB) ||
(pbmi->bmiHeader.biCompression == BI_BITFIELDS))
{
return(CJSCAN(pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biPlanes,
pbmi->bmiHeader.biBitCount) *
ABS(pbmi->bmiHeader.biHeight));
}
else
{
return(pbmi->bmiHeader.biSizeImage);
}
}
/**********************************************************************\
* pbmiConvertInfo
*
* Does two things:
*
* 1. takes BITMAPINFO, Converts BITMAPCOREHEADER
* into BITMAPINFOHEADER and copies the the color table
*
* 2. also return the size of the size of INFO struct if bPackedDIB is FALSE
* otherwise pass back the size of INFO plus cjBits
*
* 10-1-95 -by- Lingyun Wang [lingyunw]
\**********************************************************************/
LPBITMAPINFO pbmiConvertInfo(CONST BITMAPINFO *pbmi, ULONG iUsage, ULONG *count, BOOL bPackedDIB)
{
LPBITMAPINFO pbmiNew;
ULONG cjRGB;
ULONG cColorsMax;
ULONG cColors;
UINT uiBitCount;
UINT uiPalUsed;
UINT uiCompression;
BOOL bCoreHeader = FALSE;
ULONG ulSize;
ULONG cjBits = 0;
PVOID pjBits, pjBitsNew;
if (pbmi == (LPBITMAPINFO) NULL)
{
return(0);
}
//
// Checking for different bitmap headers
//
ulSize = pbmi->bmiHeader.biSize;
if (ulSize == sizeof(BITMAPCOREHEADER))
{
cjRGB = sizeof(RGBQUAD);
uiBitCount = ((LPBITMAPCOREINFO)pbmi)->bmciHeader.bcBitCount;
uiPalUsed = 0;
uiCompression = (UINT) BI_RGB;
bCoreHeader = TRUE;
}
else if (ulSize >= sizeof(BITMAPINFOHEADER))
{
cjRGB = sizeof(RGBQUAD);
uiBitCount = pbmi->bmiHeader.biBitCount;
uiPalUsed = pbmi->bmiHeader.biClrUsed;
uiCompression = (UINT) pbmi->bmiHeader.biCompression;
}
else
{
WARNING("ConvertInfo failed - invalid header size\n");
return(0);
}
//
// figure out the size of the color table
//
if (uiCompression == BI_BITFIELDS)
{
// Handle 16 and 32 bit per pel bitmaps.
if (iUsage == DIB_PAL_COLORS)
{
iUsage = DIB_RGB_COLORS;
}
switch (uiBitCount)
{
case 16:
case 32:
break;
default:
WARNING("ConvertInfo failed for BI_BITFIELDS\n");
return(0);
}
uiPalUsed = cColorsMax = 3;
}
else if (uiCompression == BI_RGB)
{
switch (uiBitCount)
{
case 1:
cColorsMax = 2;
break;
case 4:
cColorsMax = 16;
break;
case 8:
cColorsMax = 256;
break;
default:
if (iUsage == DIB_PAL_COLORS)
{
iUsage = DIB_RGB_COLORS;
}
cColorsMax = 0;
switch (uiBitCount)
{
case 16:
case 24:
case 32:
break;
default:
WARNING("convertinfo failed invalid bitcount in bmi BI_RGB\n");
return(0);
}
}
}
else if (uiCompression == BI_RLE4)
{
if (uiBitCount != 4)
{
// WARNING("cjBitmapSize invalid bitcount BI_RLE4\n");
return(0);
}
cColorsMax = 16;
}
else if (uiCompression == BI_RLE8)
{
if (uiBitCount != 8)
{
// WARNING("cjBitmapSize invalid bitcount BI_RLE8\n");
return(0);
}
cColorsMax = 256;
}
else
{
WARNING("convertinfo failed invalid Compression in header\n");
return(0);
}
if (uiPalUsed != 0)
{
if (uiPalUsed <= cColorsMax)
cColors = uiPalUsed;
else
cColors = cColorsMax;
}
else
cColors = cColorsMax;
if (iUsage == DIB_PAL_COLORS)
cjRGB = sizeof(USHORT);
else if (iUsage == DIB_PAL_INDICES)
cjRGB = 0;
if (bPackedDIB)
cjBits = cjBitmapBitsSize(pbmi);
//
// if passed non COREHEADER, donot need to convert
//
if (!bCoreHeader)
{
pbmiNew = (LPBITMAPINFO)pbmi;
}
else
{
RGBTRIPLE *pTri;
RGBQUAD *pQuad;
//
// allocate new header to hold the info
//
ulSize = sizeof(BITMAPINFOHEADER);
pbmiNew = (PBITMAPINFO)LocalAlloc(LMEM_FIXED,ulSize +
cjRGB * cColors+cjBits);
if (pbmiNew == NULL)
return (0);
pbmiNew->bmiHeader.biSize = ulSize;
//
// copy COREHEADER info over
//
pbmiNew->bmiHeader.biWidth = ((BITMAPCOREHEADER *)pbmi)->bcWidth;
pbmiNew->bmiHeader.biHeight = ((BITMAPCOREHEADER *)pbmi)->bcHeight;
pbmiNew->bmiHeader.biPlanes = ((BITMAPCOREHEADER *)pbmi)->bcPlanes;
pbmiNew->bmiHeader.biBitCount = ((BITMAPCOREHEADER *)pbmi)->bcBitCount;
pbmiNew->bmiHeader.biCompression = 0;
pbmiNew->bmiHeader.biSizeImage = 0;
pbmiNew->bmiHeader.biXPelsPerMeter = 0;
pbmiNew->bmiHeader.biYPelsPerMeter = 0;
pbmiNew->bmiHeader.biClrUsed = 0;
pbmiNew->bmiHeader.biClrImportant = 0;
//
// copy the color table
//
pTri = (RGBTRIPLE *)((LPBYTE)pbmi + sizeof(BITMAPCOREHEADER));
pQuad = (RGBQUAD *)((LPBYTE)pbmiNew + sizeof(BITMAPINFOHEADER));
//
// copy RGBTRIPLE to RGBQUAD
//
if (iUsage != DIB_PAL_COLORS)
{
INT cj = cColors;
while (cj--)
{
pQuad->rgbRed = pTri->rgbtRed;
pQuad->rgbGreen = pTri->rgbtGreen;
pQuad->rgbBlue = pTri->rgbtBlue;
pQuad->rgbReserved = 0;
pQuad++;
pTri++;
}
if (bPackedDIB)
pjBits = (LPBYTE)pbmi + sizeof(BITMAPCOREHEADER) + cColors*sizeof(RGBTRIPLE);
}
else
// DIB_PAL_COLORS
{
RtlCopyMemory((LPBYTE)pQuad,(LPBYTE)pTri,cColors * cjRGB);
if (bPackedDIB)
pjBits = (LPBYTE)pbmi + sizeof(BITMAPCOREHEADER) + cColors * cjRGB;
}
//
// copy the packed bits
//
if (bPackedDIB)
{
pjBitsNew = (LPBYTE)pbmiNew + ulSize + cColors*cjRGB;
RtlCopyMemory((LPBYTE)pjBitsNew,
(LPBYTE)pjBits,
cjBits);
}
}
*count = ((ulSize + (cjRGB * cColors) + cjBits) + 3) & ~3;
return((LPBITMAPINFO) pbmiNew);
}
ULONG cjBitmapScanSize(
CONST BITMAPINFO *pbmi,
int nScans
)
{
// Check for PM-style DIB
if (pbmi->bmiHeader.biSize == sizeof(BITMAPCOREHEADER))
{
LPBITMAPCOREINFO pbmci;
pbmci = (LPBITMAPCOREINFO)pbmi;
return(CJSCAN(pbmci->bmciHeader.bcWidth,pbmci->bmciHeader.bcPlanes,
pbmci->bmciHeader.bcBitCount) * nScans);
}
// not a core header
if ((pbmi->bmiHeader.biCompression == BI_RGB) ||
(pbmi->bmiHeader.biCompression == BI_BITFIELDS))
{
return(CJSCAN(pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biPlanes,
pbmi->bmiHeader.biBitCount) * nScans);
}
//
// rle: use image size, nScans is not used
//
//else if (nScans >= pbmi->bmiHeader.biHeight)
//{
else
{
return(pbmi->bmiHeader.biSizeImage);
}
}
/******************************Public*Routine******************************\
* CopyCoreToInfoHeader
*
\**************************************************************************/
VOID CopyCoreToInfoHeader(LPBITMAPINFOHEADER pbmih, LPBITMAPCOREHEADER pbmch)
{
pbmih->biSize = sizeof(BITMAPINFOHEADER);
pbmih->biWidth = pbmch->bcWidth;
pbmih->biHeight = pbmch->bcHeight;
pbmih->biPlanes = pbmch->bcPlanes;
pbmih->biBitCount = pbmch->bcBitCount;
pbmih->biCompression = BI_RGB;
pbmih->biSizeImage = 0;
pbmih->biXPelsPerMeter = 0;
pbmih->biYPelsPerMeter = 0;
pbmih->biClrUsed = 0;
pbmih->biClrImportant = 0;
}
/******************************Public*Routine******************************\
* DWORD SetDIBitsToDevice *
* *
* Can reduce it to 1 scan at a time. If compressed mode, this could *
* gete very difficult. There must be enough space for the header and *
* color table. This will be needed for every batch. *
* *
* BITMAPINFO *
* BITMAPINFOHEADER *
* RGBQUAD[cEntries] | RGBTRIPLE[cEntries] *
* *
* *
* 1. compute header size (including color table) *
* 2. compute size of required bits *
* 3. compute total size (header + bits + args) *
* 4. if (memory window is large enough for header + at least 1 scan *
* *
* History: *
* Tue 29-Oct-1991 -by- Patrick Haluptzok [patrickh] *
* Add shared memory action for large RLE's. *
* *
* Tue 19-Oct-1991 -by- Patrick Haluptzok [patrickh] *
* Add support for RLE's *
* *
* Thu 20-Jun-1991 01:41:45 -by- Charles Whitmer [chuckwh] *
* Added handle translation and metafiling. *
* *
* 14-May-1991 -by- Eric Kutter [erick] *
* Wrote it. *
\**************************************************************************/
int SetDIBitsToDevice(
HDC hdc,
int xDest,
int yDest,
DWORD nWidth,
DWORD nHeight,
int xSrc,
int ySrc,
UINT nStartScan,
UINT nNumScans,
CONST VOID * pBits,
CONST BITMAPINFO *pbmi,
UINT iUsage) // DIB_PAL_COLORS || DIB_RGB_COLORS
{
LONG cScansCopied = 0; // total # of scans copied
LONG ySrcMax; // maximum ySrc possible
// hold info about the header
UINT uiWidth;
UINT uiHeight;
PULONG pulBits = NULL;
INT cjHeader = 0;
LPBITMAPINFO pbmiNew = NULL;
ULONG cjBits;
FIXUP_HANDLE(hdc);
// Let's validate the parameters so we don't gp-fault ourselves and
// to save checks later on.
if ((nNumScans == 0) ||
(pbmi == (LPBITMAPINFO) NULL) ||
(pBits == (LPVOID) NULL) ||
((iUsage != DIB_RGB_COLORS) &&
(iUsage != DIB_PAL_COLORS) &&
(iUsage != DIB_PAL_INDICES)))
{
WARNING("You failed a param validation in SetDIBitsToDevice\n");
return(0);
}
pbmiNew = pbmiConvertInfo(pbmi, iUsage, &cjHeader, FALSE);
if (pbmiNew == NULL)
return (0);
uiWidth = (UINT) pbmiNew->bmiHeader.biWidth;
uiHeight = (UINT) pbmiNew->bmiHeader.biHeight;
// Compute the minimum nNumScans to send across csr interface.
// It will also prevent faults as a result of overreading the source.
ySrcMax = max(ySrc, ySrc + (int) nHeight);
if (ySrcMax <= 0)
return(0);
ySrcMax = min(ySrcMax, (int) uiHeight);
nNumScans = min(nNumScans, (UINT) ySrcMax - nStartScan);
// NEWFRAME support for backward compatibility.
// Ship the transform to the server side if needed.
if (IS_ALTDC_TYPE(hdc))
{
PLDC pldc;
if (IS_METADC16_TYPE(hdc))
{
cScansCopied = MF_AnyDIBits(
hdc,
xDest,yDest,0,0,
xSrc,ySrc,(int) nWidth,(int) nHeight,
nStartScan,nNumScans,
pBits,pbmi,
iUsage,
SRCCOPY,
META_SETDIBTODEV
);
goto Exit;
}
DC_PLDC(hdc,pldc,0);
if (pldc->iType == LO_METADC)
{
if (!MF_AnyDIBits(
hdc,
xDest,yDest,0,0,
xSrc,ySrc,(int) nWidth,(int) nHeight,
nStartScan,nNumScans,
pBits,pbmi,
iUsage,
SRCCOPY,
EMR_SETDIBITSTODEVICE
))
{
cScansCopied = 0;
goto Exit;
}
}
if (pldc->fl & LDC_CALL_STARTPAGE)
StartPage(hdc);
if (pldc->fl & LDC_SAP_CALLBACK)
vSAPCallback(pldc);
//BUGBUG - for printing, we may want to band like in the old days
// so we can call vSAPCallback every few bands.
if (pldc->fl & LDC_DOC_CANCELLED)
{
cScansCopied = 0;
goto Exit;
}
}
// reset user's poll count so it counts this as output
// put it right next to BEGINMSG so that NtCurrentTeb() is optimized
RESETUSERPOLLCOUNT();
//
// Calculate bitmap bits size based on BITMAPINFO and nNumScans
//
cjBits = cjBitmapScanSize(pbmi,nNumScans);
// if the pBits are not dword aligned we need to allocate a buffer and copy them
if ((ULONG)pBits & (sizeof(DWORD) - 1))
{
pulBits = LocalAlloc(LMEM_FIXED,cjBits);
if (pulBits)
{
RtlCopyMemory(pulBits,pBits,cjBits);
pBits = pulBits;
}
}
cScansCopied = NtGdiSetDIBitsToDeviceInternal(
hdc,
xDest,
yDest,
nWidth,
nHeight,
xSrc,
ySrc,
nStartScan,
nNumScans,
(LPBYTE)pBits,
pbmiNew,
iUsage,
(UINT)cjBits,
(UINT)cjHeader,
TRUE);
if (pulBits)
LocalFree(pulBits);
Exit:
if (pbmiNew && (pbmiNew != pbmi))
{
LocalFree (pbmiNew);
}
return (cScansCopied);
}
/******************************Public*Routine******************************\
* DWORD GetDIBits
*
* Can reduce it to 1 scan at a time. There must be enough space
* for the header and color table. This will be needed for every chunk
*
* History:
* Wed 04-Dec-1991 -by- Patrick Haluptzok [patrickh]
* bug fix, only check for valid DC if DIB_PAL_COLORS.
*
* Fri 22-Nov-1991 -by- Patrick Haluptzok [patrickh]
* bug fix, copy the header into memory window for NULL bits.
*
* Tue 20-Aug-1991 -by- Patrick Haluptzok [patrickh]
* bug fix, make iStart and cNum be in valid range.
*
* Thu 20-Jun-1991 01:44:41 -by- Charles Whitmer [chuckwh]
* Added handle translation.
*
* 14-May-1991 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
int GetDIBits(
HDC hdc,
HBITMAP hbm,
UINT nStartScan,
UINT nNumScans,
LPVOID pBits,
LPBITMAPINFO pbmi,
UINT iUsage) // DIB_PAL_COLORS || DIB_RGB_COLORS
{
PULONG pulBits = pBits;
ULONG cjBits;
int iRet;
FIXUP_HANDLE(hdc);
FIXUP_HANDLE(hbm);
cjBits = cjBitmapScanSize(pbmi,nNumScans);
// if the pBits are not dword aligned we need to allocate a buffer and copy them
if ((ULONG)pBits & (sizeof(DWORD) - 1))
{
pulBits = LocalAlloc(LMEM_FIXED,cjBits);
if (pulBits == NULL)
return(0);
}
iRet = NtGdiGetDIBitsInternal(
hdc,
hbm,
nStartScan,
nNumScans,
(LPVOID)pulBits,
pbmi,
iUsage,
cjBits,
0);
if (pulBits != pBits)
{
RtlCopyMemory(pBits,pulBits,cjBits);
LocalFree(pulBits);
}
return(iRet);
}
/******************************Public*Routine******************************\
* CreateDIBitmap
*
* History:
* Mon 25-Jan-1993 -by- Patrick Haluptzok [patrickh]
* Add CBM_CREATEDIB support.
*
* Thu 20-Jun-1991 02:14:59 -by- Charles Whitmer [chuckwh]
* Added local handle support.
*
* 23-May-1991 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
HBITMAP CreateDIBitmap(
HDC hdc,
CONST BITMAPINFOHEADER *pbmih,
DWORD flInit,
CONST VOID *pjBits,
CONST BITMAPINFO *pbmi,
UINT iUsage)
{
LONG cjBMI = 0;
LONG cjBits = 0;
INT cx = 0;
INT cy = 0;
PULONG pulBits = NULL;
HBITMAP hRet = (HBITMAP)-1;
LPBITMAPINFO pbmiNew = NULL;
FIXUP_HANDLEZ(hdc);
if (iUsage & DIB_LOCALFLAGS)
{
hRet = 0;
}
else
{
//
// covert pbmi
//
pbmiNew = pbmiConvertInfo(pbmi,iUsage,&cjBMI,FALSE);
if (flInit & CBM_CREATEDIB)
{
// With CBM_CREATEDIB we ignore pbmih
pbmih = (LPBITMAPINFOHEADER) pbmi;
if (cjBMI == 0)
{
hRet = 0;
}
else if (flInit & CBM_INIT)
{
if (pjBits == NULL)
{
// doesn't make sence if they asked to initialize it but
// didn't pass the bits.
hRet = 0;
}
else
{
cjBits = cjBitmapBitsSize(pbmiNew);
}
}
else
{
pjBits = NULL;
}
}
else
{
// compute the size of the optional init bits and BITMAPINFO
if (flInit & CBM_INIT)
{
if (pjBits == NULL)
{
// doesn't make sence if they asked to initialize it but
// didn't pass the bits.
flInit &= ~CBM_INIT;
}
else
{
if (cjBMI == 0)
{
hRet = 0;
}
else
{
// compute the size of the bits
cjBits = cjBitmapBitsSize(pbmiNew);
}
}
}
}
// if they passed us a zero height or zero width
// bitmap then return a pointer to the stock bitmap
if (pbmih)
{
if (pbmih->biSize >= sizeof(BITMAPINFOHEADER))
{
cx = pbmih->biWidth;
cy = pbmih->biHeight;
}
else
{
cx = ((LPBITMAPCOREHEADER) pbmih)->bcWidth;
cy = ((LPBITMAPCOREHEADER) pbmih)->bcHeight;
}
if ((cx == 0) || (cy == 0))
{
hRet = GetStockObject(PRIV_STOCK_BITMAP);
}
}
// if hRet is still -1, then all is OK and we need to try to the bitmap
if (hRet == (HBITMAP)-1)
{
// if the pJBits are not dword aligned we need to allocate a buffer and copy them
if ((ULONG)pjBits & (sizeof(DWORD) - 1))
{
pulBits = LocalAlloc(LMEM_FIXED,cjBits);
if (pulBits)
{
RtlCopyMemory(pulBits,pjBits,cjBits);
pjBits = pulBits;
}
}
hRet = NtGdiCreateDIBitmapInternal(hdc,
cx,
cy,
flInit,
(LPBYTE) pjBits,
(LPBITMAPINFO) pbmiNew,
iUsage,
cjBMI,
cjBits,
0);
if (pulBits)
LocalFree(pulBits);
}
if (pbmiNew && (pbmiNew != pbmi))
LocalFree(pbmiNew);
}
return(hRet);
}
/******************************Public*Routine******************************\
* Set/GetBitmapBits *
* *
* History: *
* 05-Jun-1991 -by- Eric Kutter [erick] *
* Wrote it. *
\**************************************************************************/
LONG WINAPI SetBitmapBits(
HBITMAP hbm,
DWORD c,
CONST VOID *pv)
{
LONG lRet;
FIXUP_HANDLE(hbm);
lRet = (LONG)NtGdiSetBitmapBits(hbm,c,(PBYTE)pv);
return(lRet);
}
LONG WINAPI GetBitmapBits(
HBITMAP hbm,
LONG c,
LPVOID pv)
{
LONG lRet;
FIXUP_HANDLE(hbm);
lRet = (LONG)NtGdiGetBitmapBits(hbm,c,(PBYTE)pv);
return(lRet);
}
/******************************Public*Routine******************************\
* GdiGetPaletteFromDC
*
* Returns the palette for the DC, 0 for error.
*
* History:
* 04-Oct-1991 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
HANDLE GdiGetPaletteFromDC(HDC h)
{
return((HANDLE)GetDCObject(h,LO_PALETTE_TYPE));
}
/******************************Public*Routine******************************\
* GdiGetDCforBitmap
*
* Returns the DC a bitmap is selected into, 0 if none or if error occurs.
*
* History:
* 22-Sep-1991 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
HDC GdiGetDCforBitmap(HBITMAP hbm)
{
FIXUP_HANDLE(hbm);
return (NtGdiGetDCforBitmap(hbm));
}
/******************************Public*Routine******************************\
* SetDIBits
*
* API to initialize bitmap with DIB
*
* History:
* Sun 22-Sep-1991 -by- Patrick Haluptzok [patrickh]
* Make it work even if it is selected into a DC, Win3.0 compatibility.
*
* 06-Jun-1991 -by- Patrick Haluptzok patrickh
* Wrote it.
\**************************************************************************/
int WINAPI SetDIBits(
HDC hdc,
HBITMAP hbm,
UINT iStartScans,
UINT cNumScans,
CONST VOID *pInitBits,
CONST BITMAPINFO *pInitInfo,
UINT iUsage)
{
HDC hdcTemp;
HBITMAP hbmTemp;
int iReturn = 0;
BOOL bMakeDC = FALSE;
HPALETTE hpalTemp;
DWORD cWidth;
DWORD cHeight;
FIXUP_HANDLE(hdc);
FIXUP_HANDLE(hbm);
// if no bits or hbm is not a bitmap, fail
if ((pInitBits == (PVOID) NULL) ||
(GRE_TYPE(hbm) != SURF_TYPE))
{
return(0);
}
// First we need a DC to select this bitmap into. If he is already in a
// DC we just use that DC temporarily to blt to (we still have to select
// it in and out because someone might do a SaveDC and select another
// bitmap in). If he hasn't been stuck in a DC anywhere we just create
// one temporarily.
hdcTemp = GdiGetDCforBitmap(hbm);
if (hdcTemp == (HDC) 0)
{
hdcTemp = CreateCompatibleDC(hdc);
bMakeDC = TRUE;
if (hdcTemp == (HDC) NULL)
{
WARNING("SetDIBits failed CreateCompatibleDC, is hdc valid?\n");
return(0);
}
}
else
{
if (SaveDC(hdcTemp) == 0)
return(0);
}
hbmTemp = SelectObject(hdcTemp, hbm);
if (hbmTemp == (HBITMAP) 0)
{
//WARNING("ERROR SetDIBits failed to Select, is bitmap valid?\n");
goto Error_SetDIBits;
}
if (hdc != (HDC) 0)
{
hpalTemp = SelectPalette(hdcTemp, GdiGetPaletteFromDC(hdc), 0);
}
if (pInitInfo->bmiHeader.biSize == sizeof(BITMAPINFOHEADER))
{
cWidth = pInitInfo->bmiHeader.biWidth;
cHeight = ABS(pInitInfo->bmiHeader.biHeight);
}
else
{
cWidth = ((LPBITMAPCOREHEADER)pInitInfo)->bcWidth;
cHeight = ((LPBITMAPCOREHEADER)pInitInfo)->bcHeight;
}
iReturn = SetDIBitsToDevice(hdcTemp,
0,
0,
cWidth,
cHeight,
0, 0,
iStartScans,
cNumScans,
(VOID *) pInitBits,
pInitInfo,
iUsage);
if (hdc != (HDC) 0)
{
SelectPalette(hdcTemp, hpalTemp, 0);
}
SelectObject(hdcTemp, hbmTemp);
Error_SetDIBits:
if (bMakeDC)
{
DeleteDC(hdcTemp);
}
else
{
RestoreDC(hdcTemp, -1);
}
return(iReturn);
}
/******************************Public*Routine******************************\
* StretchDIBits()
*
*
* Effects:
*
* Warnings:
*
* History:
* 22-Jul-1991 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
int WINAPI StretchDIBits(
HDC hdc,
int xDest,
int yDest,
int nDestWidth,
int nDestHeight,
int xSrc,
int ySrc,
int nSrcWidth,
int nSrcHeight,
CONST VOID *pj,
CONST BITMAPINFO *pbmi,
UINT iUsage,
DWORD lRop)
{
LONG cPoints = 0;
LONG cjHeader;
LONG cjBits;
ULONG ulResult = 0;
PULONG pulBits = NULL;
int iRet;
BITMAPINFO * pbmiNew = NULL;
FIXUP_HANDLE(hdc);
// NEWFRAME support for backward compatibility.
// Ship the transform to the server side if needed.
if (IS_ALTDC_TYPE(hdc))
{
PLDC pldc;
if (IS_METADC16_TYPE(hdc))
{
return(MF_AnyDIBits(
hdc,
xDest,
yDest,
nDestWidth,
nDestHeight,
xSrc,
ySrc,
nSrcWidth,
nSrcHeight,
0,
0,
(BYTE *) pj,
pbmi,
iUsage,
lRop,
META_STRETCHDIB
));
}
DC_PLDC(hdc,pldc,ulResult);
if (pldc->iType == LO_METADC)
{
if (!MF_AnyDIBits(hdc,
xDest,
yDest,
nDestWidth,
nDestHeight,
xSrc,
ySrc,
nSrcWidth,
nSrcHeight,
0,
0,
(BYTE *) pj,
pbmi,
iUsage,
lRop,
EMR_STRETCHDIBITS
))
{
return(0);
}
}
if (pldc->fl & LDC_SAP_CALLBACK)
vSAPCallback(pldc);
if (pldc->fl & LDC_DOC_CANCELLED)
return(0);
if (pldc->fl & LDC_CALL_STARTPAGE)
StartPage(hdc);
}
// compute the size
if (pbmi != NULL)
{
pbmiNew = pbmiConvertInfo (pbmi, iUsage, &cjHeader,FALSE);
if (pbmiNew == NULL)
return (0);
cjBits = cjBitmapBitsSize(pbmiNew);
}
else
{
cjHeader = 0;
cjBits = 0;
}
// reset user's poll count so it counts this as output
// put it right next to BEGINMSG so that NtCurrentTeb() is optimized
RESETUSERPOLLCOUNT();
// if the pj are not dword aligned we need to allocate a buffer and copy them
if ((ULONG)pj & (sizeof(DWORD) - 1))
{
pulBits = LocalAlloc(LMEM_FIXED,cjBits);
if (pulBits)
{
RtlCopyMemory(pulBits,pj,cjBits);
pj = pulBits;
}
}
iRet = NtGdiStretchDIBitsInternal(
hdc,
xDest,
yDest,
nDestWidth,
nDestHeight,
xSrc,
ySrc,
nSrcWidth,
nSrcHeight,
(LPBYTE) pj,
(LPBITMAPINFO) pbmiNew,
iUsage,
lRop,
cjHeader,
cjBits);
if (pulBits)
LocalFree(pulBits);
if (pbmiNew && (pbmiNew != pbmi))
LocalFree(pbmiNew);
return(iRet);
}
/******************************Public*Routine******************************\
*
* History:
* 28-May-1991 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
HBITMAP CreateBitmap(
int nWidth,
int nHeight,
UINT nPlanes,
UINT nBitCount,
CONST VOID *lpBits)
{
LONG cj;
HBITMAP hbm = (HBITMAP)0;
INT ii;
// check if it is an empty bitmap
if ((nWidth == 0) || (nHeight == 0))
{
return(GetStockObject(PRIV_STOCK_BITMAP));
}
// Pass call to the server
if (lpBits == (VOID *) NULL)
cj = 0;
else
{
cj = (((nWidth*nPlanes*nBitCount + 15) >> 4) << 1) * nHeight;
if (cj < 0)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return((HBITMAP)0);
}
}
hbm = NtGdiCreateBitmap(nWidth,
nHeight,
nPlanes,
nBitCount,
(LPBYTE) lpBits);
return(hbm);
}
/******************************Public*Routine******************************\
* HBITMAP CreateBitmapIndirect(CONST BITMAP * pbm)
*
* NOTE: if the bmWidthBytes is larger than it needs to be, GetBitmapBits
* will return different info than the set.
*
* History:
* Tue 18-Jan-1994 -by- Bodin Dresevic [BodinD]
* update: added bmWidthBytes support
* 28-May-1991 -by- Eric Kutter [erick]
* Wrote it.
\**************************************************************************/
HBITMAP CreateBitmapIndirect(CONST BITMAP * pbm)
{
HBITMAP hbm = (HBITMAP)0;
LPBYTE lpBits = (LPBYTE)NULL; // important to zero init
BOOL bAlloc = FALSE; // indicates that tmp bitmap was allocated
// compute minimal word aligned scan width in bytes given the number of
// pixels in x. The width refers to one plane only. Our multi - planar
// support is broken anyway. I believe that we should take an early
// exit if bmPlanes != 1. [bodind].
LONG cjWidthWordAligned = ((pbm->bmWidth * pbm->bmBitsPixel + 15) >> 4) << 1;
// Win 31 requires at least WORD alinged scans, have to reject inconsistent
// input, this is what win31 does
if
(
(pbm->bmWidthBytes & 1) ||
(pbm->bmWidthBytes == 0) ||
(pbm->bmWidthBytes < cjWidthWordAligned)
)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return (HBITMAP)0;
}
// take an early exit if this is not the case we know how to handle:
if (pbm->bmPlanes != 1)
{
WARNING("gdi32: can not handle bmPlanes != 1\n");
GdiSetLastError(ERROR_INVALID_PARAMETER);
return (HBITMAP)0;
}
// if bmBits is nonzero and bmWidthBytes is bigger than the minimal required
// word aligned width we will first convert the bitmap to one that
// has the rows that are minimally word aligned:
if (pbm->bmBits)
{
if (pbm->bmWidthBytes > cjWidthWordAligned)
{
PBYTE pjSrc, pjDst, pjDstEnd;
ULONGLONG lrg;
lrg = UInt32x32To64(
(ULONG)cjWidthWordAligned,
(ULONG)pbm->bmHeight
);
if (lrg > ULONG_MAX ||
!(lpBits = (LPBYTE)LOCALALLOC((size_t) lrg)))
{
// the result does not fit in 32 bits, alloc memory will fail
// this is too big to digest
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return (HBITMAP)0;
}
// flag that we have allocated memory so that we can free it later
bAlloc = TRUE;
// convert bitmap to minimally word aligned format
pjSrc = (LPBYTE)pbm->bmBits;
pjDst = lpBits;
pjDstEnd = lpBits + (size_t) lrg;
while (pjDst < pjDstEnd)
{
RtlCopyMemory(pjDst,pjSrc, cjWidthWordAligned);
pjDst += cjWidthWordAligned, pjSrc += pbm->bmWidthBytes;
}
}
else
{
// bits already in minimally aligned format, do nothing
ASSERTGDI(
pbm->bmWidthBytes == cjWidthWordAligned,
"pbm->bmWidthBytes != cjWidthWordAligned\n"
);
lpBits = (LPBYTE)pbm->bmBits;
}
}
hbm = CreateBitmap(
pbm->bmWidth,
pbm->bmHeight,
(UINT) pbm->bmPlanes,
(UINT) pbm->bmBitsPixel,
lpBits);
if (bAlloc)
LOCALFREE(lpBits);
return(hbm);
}
/******************************Public*Routine******************************\
* CreateDIBSection
*
* Allocate a file mapping object for a DIB. Return the pointer to it
* and the handle of the bitmap.
*
* History:
*
* 25-Aug-1993 -by- Wendy Wu [wendywu]
* Wrote it.
\**************************************************************************/
HBITMAP
WINAPI
CreateDIBSection(
HDC hdc,
CONST BITMAPINFO *pbmi,
UINT iUsage,
VOID **ppvBits,
HANDLE hSectionApp,
DWORD dwOffset)
{
HBITMAP hbm = NULL;
PVOID pjBits = NULL;
BITMAPINFO * pbmiNew = NULL;
INT cjHdr;
FIXUP_HANDLE(hdc);
pbmiNew = pbmiConvertInfo(pbmi, iUsage, &cjHdr, FALSE);
//
// dwOffset has to be a multiple of 4 (sizeof(DWORD))
// if there is a section. If the section is NULL we do
// not care
//
if ( (hSectionApp == NULL) ||
((dwOffset & 3) == 0) )
{
hbm = NtGdiCreateDIBSection(
hdc,
hSectionApp,
dwOffset,
(LPBITMAPINFO) pbmiNew,
iUsage,
cjHdr,
0,
(PVOID *)&pjBits);
if ((hbm == NULL) || (pjBits == NULL))
{
hbm = 0;
pjBits = NULL;
}
}
//
// Assign the appropriate value to the caller's pointer
//
if (ppvBits != NULL)
{
*ppvBits = pjBits;
}
if (pbmiNew && (pbmiNew != pbmi))
LocalFree(pbmiNew);
return(hbm);
}