Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2871 lines
86 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-1999 Microsoft Corporation *
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#define EXTRAPIXEL 4
//
//The default band size is set to 4Mb
//
#define BAND_SIZE (4194304)
/******************************Public*Routine******************************\
* cjBitmapBitsSize - calculate the size of the bitmap bits for the
* given BITMAPINFO
*
* Arguments:
*
* pbmi - pointer to BITMAPINFO
*
* Return Value:
*
* size of bitmap bits in butes
*
* History:
*
* 11-Jul-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
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) ||
(pbmi->bmiHeader.biCompression == BI_CMYK))
{
return(CJSCAN(pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biPlanes,
pbmi->bmiHeader.biBitCount) *
ABS(pbmi->bmiHeader.biHeight));
}
else
{
return(pbmi->bmiHeader.biSizeImage);
}
}
//
// IS_BMI_RLE
//
// Checks if the header pointed to by pv is a BITMAPINFO for a RLE4 or RLE8.
// Evaluates to TRUE if RLE, FALSE otherwise.
//
#define IS_BMI_RLE(pv) \
((pv) && \
(((BITMAPINFO *)(pv))->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && \
((((BITMAPINFO *)(pv))->bmiHeader.biCompression == BI_RLE4) || \
(((BITMAPINFO *)(pv))->bmiHeader.biCompression == BI_RLE8) ))
//
// IS_BMI_JPEG
//
// Checks if the header pointed to by pv is a BITMAPINFO for a JPEG.
// Evaluates to TRUE if JPEG, FALSE otherwise.
//
#define IS_BMI_JPEG(pv) \
((pv) && \
(((BITMAPINFO *)(pv))->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && \
(((BITMAPINFO *)(pv))->bmiHeader.biCompression == BI_JPEG))
//
// IS_BMI_PNG
//
// Checks if the header pointed to by pv is a BITMAPINFO for a PNG.
// Evaluates to TRUE if PNG, FALSE otherwise.
//
#define IS_BMI_PNG(pv) \
((pv) && \
(((BITMAPINFO *)(pv))->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && \
(((BITMAPINFO *)(pv))->bmiHeader.biCompression == BI_PNG))
//
// IS_PASSTHROUGH_IMAGE
//
// Checks if the biCompression value is one of the passthrough formats that
// can be passed to devices (BI_JPEG or BI_PNG).
//
#define IS_PASSTHROUGH_IMAGE(biCompression) \
(((biCompression) == BI_JPEG) || ((biCompression) == BI_PNG))
//
// IS_BMI_PASSTHROUGH_IMAGE
//
// Checks if the header pointed to by pv is a BITMAPINFO for a JPEG or PNG.
// Evaluates to TRUE if JPEG or PNG, FALSE otherwise.
//
#define IS_BMI_PASSTHROUGH_IMAGE(pv) \
((pv) && \
(((BITMAPINFO *)(pv))->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER)) && \
IS_PASSTHROUGH_IMAGE(((BITMAPINFO *)(pv))->bmiHeader.biCompression))
/******************************Public*Routine******************************\
* cCalculateColorTableSize(
*
* Arguments:
*
*
*
* Return Value:
*
*
*
* History:
*
* 11-Jul-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL
cCalculateColorTableSize(
UINT uiBitCount,
UINT uiPalUsed,
UINT uiCompression,
UINT biSize,
ULONG *piUsage,
ULONG *pColors
)
{
BOOL bStatus = FALSE;
ULONG cColorsMax = 0;
if (uiCompression == BI_BITFIELDS)
{
//
// Handle 16 and 32 bit per pel bitmaps.
//
if (*piUsage == DIB_PAL_COLORS)
{
*piUsage = DIB_RGB_COLORS;
}
switch (uiBitCount)
{
case 16:
case 32:
break;
default:
WARNING("ConvertInfo failed for BI_BITFIELDS\n");
return(FALSE);
}
if (biSize <= sizeof(BITMAPINFOHEADER))
{
uiPalUsed = cColorsMax = 3;
}
else
{
//
// masks are part of BITMAPV4 and greater
//
uiPalUsed = cColorsMax = 0;
}
}
else if (uiCompression == BI_RGB)
{
switch (uiBitCount)
{
case 1:
cColorsMax = 2;
break;
case 4:
cColorsMax = 16;
break;
case 8:
cColorsMax = 256;
break;
default:
if (*piUsage == DIB_PAL_COLORS)
{
*piUsage = 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(FALSE);
}
}
}
else if (uiCompression == BI_CMYK)
{
if (*piUsage == DIB_PAL_COLORS)
{
*piUsage = DIB_RGB_COLORS;
}
switch (uiBitCount)
{
case 1:
cColorsMax = 2;
break;
case 4:
cColorsMax = 16;
break;
case 8:
cColorsMax = 256;
break;
case 32:
cColorsMax = 0;
break;
default:
WARNING("convertinfo failed invalid bitcount in bmi BI_CMYK\n");
return(FALSE);
}
}
else if ((uiCompression == BI_RLE4) || (uiCompression == BI_CMYKRLE4))
{
if (uiBitCount != 4)
{
// WARNING("cCalculateColroTableSize invalid bitcount BI_RLE4\n");
return(FALSE);
}
cColorsMax = 16;
}
else if ((uiCompression == BI_RLE8) || (uiCompression == BI_CMYKRLE8))
{
if (uiBitCount != 8)
{
// WARNING("cjBitmapSize invalid bitcount BI_RLE8\n");
return(FALSE);
}
cColorsMax = 256;
}
else if ((uiCompression == BI_JPEG) || (uiCompression == BI_PNG))
{
cColorsMax = 0;
}
else
{
WARNING("convertinfo failed invalid Compression in header\n");
return(FALSE);
}
if (uiPalUsed != 0)
{
if (uiPalUsed <= cColorsMax)
{
cColorsMax = uiPalUsed;
}
}
*pColors = cColorsMax;
return(TRUE);
}
/**********************************************************************\
* 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
*
* Arguments:
*
* pbmi - original bitmapinfo
* iUsage - iUsage from API
* *count - return size
* bCopyInfoHeader - force copy if input is BITMAPINFOHEADER
* and bPackedDIB is NOT set
* bPackedDIB - BITMAPINFO has bitmap data that must be
* copied also
*
* Return Value:
*
* Converted PBITMAPINFO if successful, otherwise NULL
*
* 10-1-95 -by- Lingyun Wang [lingyunw]
\**********************************************************************/
LPBITMAPINFO
pbmiConvertInfo(
CONST BITMAPINFO *pbmi,
ULONG iUsage,
ULONG *count,
BOOL bPackedDIB
)
{
LPBITMAPINFO pbmiNew;
ULONG cjRGB;
ULONG cColors;
UINT uiBitCount;
UINT uiPalUsed;
UINT uiCompression;
BOOL bCoreHeader = FALSE;
ULONG ulSize;
ULONG cjBits = 0;
PVOID pjBits, pjBitsNew;
BOOL bStatus;
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)) &&
(ulSize <= ( 2 * sizeof(BITMAPV5HEADER))))
{
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
//
bStatus = cCalculateColorTableSize(
uiBitCount,
uiPalUsed,
uiCompression,
ulSize,
&iUsage,
&cColors
);
if (!bStatus)
{
return(NULL);
}
if (iUsage == DIB_PAL_COLORS)
{
cjRGB = sizeof(USHORT);
}
else if (iUsage == DIB_PAL_INDICES)
{
cjRGB = 0;
}
if (bPackedDIB)
{
cjBits = cjBitmapBitsSize(pbmi);
}
//
// if passed COREHEADER then convert to BITMAPINFOHEADER
//
if (bCoreHeader)
{
RGBTRIPLE *pTri;
RGBQUAD *pQuad;
//
// allocate new header to hold the info
//
ulSize = sizeof(BITMAPINFOHEADER);
pbmiNew = (PBITMAPINFO)LOCALALLOC(ulSize +
cjRGB * cColors+cjBits);
if (pbmiNew == NULL)
return (0);
//
// copy COREHEADER info over
//
CopyCoreToInfoHeader(&pbmiNew->bmiHeader, (BITMAPCOREHEADER *)pbmi);
//
// 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);
}
}
else
{
pbmiNew = (LPBITMAPINFO)pbmi;
}
*count = ((ulSize + (cjRGB * cColors) + cjBits) + 3) & ~3;
return((LPBITMAPINFO) pbmiNew);
}
/******************************Public*Routine******************************\
* cjBitmapScanSize
*
* Arguments:
*
* pbmi
* nScans
*
* Return Value:
*
* Image size based on number of scans
*
* History:
*
* 11-Jul-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
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) ||
(pbmi->bmiHeader.biCompression == BI_CMYK))
{
return(CJSCAN(pbmi->bmiHeader.biWidth,pbmi->bmiHeader.biPlanes,
pbmi->bmiHeader.biBitCount) * nScans);
}
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;
// ICM related variables
PCACHED_COLORSPACE pBitmapColorSpace = NULL;
PCACHED_COLORTRANSFORM pCXform = NULL;
HANDLE hcmTempXform = NULL;
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);
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 (that's because we always guarantee display and printer
// drivers that bitmaps are dword aligned):
//
cScansCopied = 1;
if ((ULONG_PTR)pBits & (sizeof(DWORD) - 1))
{
pulBits = LOCALALLOC(cjBits);
if (pulBits)
{
//
// We used to simply access violate here if we had been given
// a corrupt DIB bitmap. This was bad because WinLogon is
// responsible for showing the original background bitmap, and
// if that bitmap is corrupt, and we access violate, we'll
// cause the system to blue-screen:
//
try
{
RtlCopyMemory(pulBits,pBits,cjBits);
pBits = pulBits;
}
except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("SetDIBitsToDevice: Corrupt bitmap\n");
cScansCopied = 0;
}
}
}
if (cScansCopied)
{
PDC_ATTR pdcattr;
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (pdcattr)
{
//
// ICM translation of BITMAP bits or color table
//
// At this moment, ensured that pBits and pbmiNew is not NULL.
// (see above parameter validate check and NULL check !)
//
if (
IS_ICM_INSIDEDC(pdcattr->lIcmMode) &&
(iUsage != DIB_PAL_COLORS) &&
!IS_BMI_PASSTHROUGH_IMAGE(pbmiNew))
{
LPBITMAPINFO pbmiIcm = NULL;
PVOID pvBitsIcm = NULL;
ULONG cjHeaderNew = 0;
BOOL bIcmStatus;
VOID *pBitsBand = (VOID *)pBits;
ULONG CurrentBandSize;
ULONG SizeOfOneScanline;
ULONG nBands;
ULONG nScansInBand;
ULONG nScansInCurrentBand;
ULONG nScansInRemainderBand;
ULONG CumulativeScans=0;
ULONG i;
LONG PositiveBandDelta=0;
LONG NegativeBandDelta=0;
LONG TotalBandDelta=0;
LONG IcmSizeOfOneScanline;
INT iRet;
LONG HeaderHeightHack;
SizeOfOneScanline = cjBitmapScanSize(pbmi, 1);
//
//pbmiNew must be initialized before getting to this point.
//
ASSERTGDI(pbmiNew!=NULL, "SetDIBitsToDevice cannot proceed with pbmiNew==NULL\n");
nScansInBand = BAND_SIZE/SizeOfOneScanline;
//
// Set the number of bands provided there are enough scanlines
// and the hdc is a printer dc.
//
// Else set the nubmer of bands to 1 and the scanlines in the
// remainder band to all of them, so the entire bitmap is printed
// in one band (All the code below reduces to doing a single piece)
//
// If the bitmap is RLE compressed, we set it up to do one band
// only. When this is the case, Start and NegativeBandDelta will be
// computed as 0 and the SizeOfOneScanline parameter will be
// multiplied away to zero.
//
if ((nScansInBand>0)&&
(GetDeviceCaps(hdc, TECHNOLOGY)==DT_RASPRINTER)&&
(!IS_BMI_RLE(pbmiNew)))
{
//
// Compressed images cannot be converted in this way.
// This should never be hit and is included as a guard against
// someone inventing a new compression mode and not updating
// this conditional.
//
ASSERTGDI(SizeOfOneScanline*nNumScans==cjBits, "SetDIBitsToDevice, cannot band compressed image");
nBands = (nNumScans)/nScansInBand;
nScansInRemainderBand = nNumScans % nScansInBand;
}
else
{
nBands = 0;
nScansInRemainderBand = (nNumScans);
}
if (nScansInRemainderBand>0)
{
nBands++;
nScansInCurrentBand = nScansInRemainderBand;
}
else
{
nScansInCurrentBand = nScansInBand;
}
cScansCopied = 0;
HeaderHeightHack = pbmiNew->bmiHeader.biHeight;
for (i=0; i<nBands; i++)
{
CurrentBandSize = nScansInCurrentBand*SizeOfOneScanline;
IcmSizeOfOneScanline = SizeOfOneScanline;
//
// The Delta refers to the number of extra scanlines to pass
// to the internal blting routines in order to avoid halftone
// seams.
//
// PositiveBandDelta is the number of scanlines to
// add on to the end of the band. (relative to the start in
// memory)
//
// NegativeBandDelta is the number of scanlines to
// subtract from the begining of the band (ie move the start
// pointer back this many scanlines).
//
// Total BandDelta is simply the total number of extra scans
// added for this band (both at the start and end).
//
PositiveBandDelta = MIN(EXTRAPIXEL, CumulativeScans);
NegativeBandDelta = MIN(EXTRAPIXEL, nNumScans-(CumulativeScans+nScansInCurrentBand));
TotalBandDelta = NegativeBandDelta+PositiveBandDelta;
if (nBands!=1)
{
SaveDC(hdc);
//
// Intersect the clip rectangles.
// This clip rectangle is designed to restrict the output to
// just the displayed portion of the band.
// We may pass more scanlines on the top and bottom of the band
// to get halftoning to merge seamlessly.
//
iRet = IntersectClipRect(
hdc,
xDest,
nNumScans - (nStartScan+CumulativeScans+nScansInCurrentBand),
xDest+nWidth,
nNumScans - (nStartScan+CumulativeScans));
if (iRet==ERROR)
{
WARNING("SetDIBitsToDevice: error intersecting clip rect\n");
RestoreDC(hdc, -1);
goto Exit;
}
//
// Empty clip rectangle
// If the clip regions don't intersect, we can quit without
// doing anything.
//
if (iRet==NULLREGION)
{
RestoreDC(hdc, -1);
//
// Nothing to do - fall through and do
// initialization for next iteration.
//
goto Continue_With_Init;
}
}
if (HeaderHeightHack >= 0)
{
//
//Bottom Up
//
pBitsBand = (char *)pBits + (CumulativeScans-PositiveBandDelta)*SizeOfOneScanline;
}
else
{
//
//TopDown
//
pBitsBand = (char *)pBits + (nNumScans-nScansInCurrentBand-CumulativeScans-NegativeBandDelta)*SizeOfOneScanline;
}
cjHeaderNew=0;
pbmiIcm=NULL;
pvBitsIcm = NULL;
//
// Call ICM with an oversized band for later halftoning by
// NtGdiSetDIBitsInternal
//
bIcmStatus = IcmTranslateDIB(
hdc,
pdcattr,
CurrentBandSize+TotalBandDelta*SizeOfOneScanline,
(PVOID)pBitsBand,
&pvBitsIcm,
pbmiNew,
&pbmiIcm,
&cjHeaderNew,
nScansInCurrentBand+TotalBandDelta,
iUsage,
ICM_FORWARD,
&pBitmapColorSpace,
&pCXform);
if (bIcmStatus)
{
if (pvBitsIcm == NULL)
{
pvBitsIcm = pBitsBand;
}
if (pbmiIcm == NULL)
{
pbmiIcm = pbmiNew;
cjHeaderNew = cjHeader;
}
else
{
CurrentBandSize = cjBitmapScanSize(pbmiIcm, nScansInCurrentBand);
IcmSizeOfOneScanline = cjBitmapScanSize(pbmiIcm, 1);
if (!cjHeaderNew)
{
cjHeaderNew = cjHeader;
}
}
if (pCXform)
{
hcmTempXform = pCXform->ColorTransform;
}
}
else
{
pvBitsIcm = pBitsBand;
pbmiIcm = pbmiNew;
cjHeaderNew = cjHeader;
}
cScansCopied += NtGdiSetDIBitsToDeviceInternal(
hdc,
xDest,
yDest,
nWidth,
nHeight,
xSrc,
ySrc,
nStartScan+CumulativeScans-PositiveBandDelta,
nScansInCurrentBand+TotalBandDelta,
(LPBYTE)pvBitsIcm,
pbmiIcm,
iUsage,
(UINT)CurrentBandSize+TotalBandDelta*IcmSizeOfOneScanline,
(UINT)cjHeaderNew,
TRUE,
hcmTempXform);
cScansCopied -= TotalBandDelta;
if (pBitmapColorSpace)
{
if (pCXform)
{
IcmDeleteColorTransform(pCXform,FALSE);
}
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
}
if ((pvBitsIcm!=NULL)&&(pvBitsIcm!=pBitsBand))
{
LOCALFREE(pvBitsIcm);
pvBitsIcm = NULL;
}
if ((pbmiIcm!=NULL)&&(pbmiIcm!=pbmiNew))
{
LOCALFREE(pbmiIcm);
pbmiIcm = NULL;
}
hcmTempXform = NULL;
Continue_With_Init:
CumulativeScans += nScansInCurrentBand;
nScansInCurrentBand = nScansInBand;
if (nBands != 1)
{
RestoreDC(hdc, -1);
}
}
//
// We do our own NtGdiSetDIBitsToDeviceInternal
// So we need to fall through to cleanup at this point.
//
goto Exit;
}
}
//
// Do the non-ICM version of the SetDIB
//
cScansCopied = NtGdiSetDIBitsToDeviceInternal(
hdc,
xDest,
yDest,
nWidth,
nHeight,
xSrc,
ySrc,
nStartScan,
nNumScans,
(LPBYTE)pBits,
pbmiNew,
iUsage,
(UINT)cjBits,
(UINT)cjHeader,
TRUE,
hcmTempXform);
}
Exit:
if (pulBits)
{
//
// Free temporary buffer, this would be the buffer which allocated
// to align, Or to do ICM.
//
LOCALFREE (pulBits);
}
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 = 0;
PDC_ATTR pdcattr;
FIXUP_HANDLE(hdc);
FIXUP_HANDLE(hbm);
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (pdcattr)
{
BOOL bNeedICM = TRUE;
cjBits = cjBitmapScanSize(pbmi,nNumScans);
//
// If pbmi is a input buffer specifying image format
// (i.e., pBits != NULL), then fail for passthrough
// images (BI_JPEG and BI_PNG)
//
if (pBits && IS_BMI_PASSTHROUGH_IMAGE(pbmi))
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return 0;
}
if (pbmi->bmiHeader.biBitCount == 0)
{
//
// no color table required.
//
bNeedICM = FALSE;
}
//
// if the pBits are not dword aligned, we need to allocate
// a buffer and copy them
//
if ((ULONG_PTR)pBits & (sizeof(DWORD) - 1))
{
pulBits = LOCALALLOC(cjBits);
if (pulBits == NULL)
return(0);
}
iRet = NtGdiGetDIBitsInternal(
hdc,
hbm,
nStartScan,
nNumScans,
(LPVOID)pulBits,
pbmi,
iUsage,
cjBits,
0);
//
// translate DIB if needed
//
if (bNeedICM &&
(IS_ICM_HOST(pdcattr->lIcmMode)) && (iUsage != DIB_PAL_COLORS))
{
//
// UNDER_CONSTRUCTION: Failed on GetDIBits() from CMYK surface.
//
if (IS_CMYK_COLOR(pdcattr->lIcmMode))
{
WARNING("GetDIBits(): was called on CMYK bitmap\n");
iRet = 0;
}
else
{
//
// Do backward transform.
//
if (!IcmTranslateDIB(hdc,
pdcattr,
cjBits,
pulBits,
NULL, // Indicates overwrite original...
pbmi,
NULL, // Indicates overwrite original...
NULL,
nNumScans,
iUsage,
ICM_BACKWARD,
NULL,NULL))
{
//
// ICM translation failed.
//
iRet = 0;
}
}
}
if (pulBits != pBits)
{
if (iRet)
{
RtlCopyMemory(pBits,pulBits,cjBits);
}
LOCALFREE(pulBits);
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
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;
PDC_ATTR pdcattr;
// ICM related variables.
PCACHED_COLORSPACE pBitmapColorSpace = NULL;
PCACHED_COLORTRANSFORM pCXform = NULL;
HANDLE hcmTempXform = NULL;
FIXUP_HANDLEZ(hdc);
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
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);
}
}
}
else
{
pjBits = NULL;
}
}
// CreateDIBitmap cannot handle passthrough image (BI_JPEG or BI_PNG)
// init data
if (IS_BMI_PASSTHROUGH_IMAGE(pbmiNew))
{
hRet = 0;
}
// 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)
{
BOOL bStatus = TRUE;
// if the pJBits are not dword aligned we need to allocate a buffer and copy them
if ((ULONG_PTR)pjBits & (sizeof(DWORD) - 1))
{
pulBits = LOCALALLOC(cjBits);
if (pulBits)
{
RtlCopyMemory(pulBits,pjBits,cjBits);
pjBits = pulBits;
}
}
// ICM conversion
//
// Convert bitmap data only when ...
//
// - HDC is not NULL.
// - ICM is enanled.
// - ICM is not lazy mode.
// - Initialize data is not Palette Index.
// - Initialize data is provided.
if (pdcattr &&
IS_ICM_INSIDEDC(pdcattr->lIcmMode) &&
(IS_ICM_LAZY_CORRECTION(pdcattr->lIcmMode) == FALSE) &&
(iUsage != DIB_PAL_COLORS) &&
pjBits && pbmiNew)
{
PVOID pvBitsIcm = NULL;
PBITMAPINFO pbmiIcm = NULL;
ULONG cjBMINew = 0;
BOOL bIcmStatus;
bIcmStatus = IcmTranslateDIB(hdc,
pdcattr,
cjBits,
(PVOID)pjBits,
&pvBitsIcm,
pbmiNew,
&pbmiIcm,
&cjBMINew,
(DWORD)-1,
iUsage,
ICM_FORWARD,
&pBitmapColorSpace,
&pCXform);
//
// IcmTranslateDIB will create a duplicate dib
// pointed to by pulBits if needed.
//
if (bIcmStatus)
{
if (pvBitsIcm != NULL)
{
ICMMSG(("CreateDIBitmap(): Temp bits are allocated\n"));
if (pulBits)
{
LOCALFREE(pulBits);
}
pjBits = (PVOID)pulBits = pvBitsIcm;
}
if (pbmiIcm != NULL)
{
ICMMSG(("CreateDIBitmap(): Temp bmi are allocated\n"));
if (pbmiNew && (pbmiNew != pbmi))
{
LOCALFREE(pbmiNew);
}
pbmiNew = pbmiIcm;
//
// Calculate bitmap bits size based on BITMAPINFO and nNumScans
//
cjBits = cjBitmapBitsSize(pbmiNew);
//
// Update sizeof bitmap info (including color table)
//
if (cjBMINew)
{
cjBMI = cjBMINew;
}
}
//
// Get color transform handle need to pass kernel
//
if (pCXform)
{
hcmTempXform = pCXform->ColorTransform;
}
}
}
if (bStatus)
{
hRet = NtGdiCreateDIBitmapInternal(hdc,
cx,
cy,
flInit,
(LPBYTE) pjBits,
(LPBITMAPINFO) pbmiNew,
iUsage,
cjBMI,
cjBits,
0,
hcmTempXform);
#if TRACE_SURFACE_ALLOCS
{
PULONGLONG pUserAlloc;
PSHARED_GET_VALIDATE(pUserAlloc, hRet, SURF_TYPE);
if (pUserAlloc != NULL)
{
RtlWalkFrameChain((PVOID *)&pUserAlloc[1], (ULONG)*pUserAlloc, 0);
}
}
#endif
}
if (pBitmapColorSpace)
{
if (pCXform)
{
IcmDeleteColorTransform(pCXform,FALSE);
}
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
}
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);
}
// if passthrough image (BI_JPEG or BI_JPEG), fail
if (IS_BMI_PASSTHROUGH_IMAGE(pInitInfo))
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
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 = ((LPBITMAPCOREHEADER)pInitInfo)->bcWidth;
cHeight = ((LPBITMAPCOREHEADER)pInitInfo)->bcHeight;
}
else
{
cWidth = pInitInfo->bmiHeader.biWidth;
cHeight = ABS(pInitInfo->bmiHeader.biHeight);
}
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 = 0;
BITMAPINFO * pbmiNew = NULL;
PDC_ATTR pdcattr;
BOOL bStatus = TRUE;
// ICM related variables.
PCACHED_COLORSPACE pBitmapColorSpace = NULL;
PCACHED_COLORTRANSFORM pCXform = NULL;
HANDLE hcmTempXform = 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)
{
//
// speeds up cases when partial sources bits are sent
//
int iStart = 0;
int iEnd = 0;
int cScans = 0;
if (pbmi && (pbmi->bmiHeader.biWidth == nSrcWidth) && (pbmi->bmiHeader.biHeight > nSrcHeight) &&
(pbmi->bmiHeader.biHeight > 0) &&
!(IS_BMI_RLE(pbmi) || IS_BMI_PASSTHROUGH_IMAGE(pbmi)))
{
iStart = ((ySrc - EXTRAPIXEL) > 0) ? (ySrc - EXTRAPIXEL) : 0;
iEnd = ((ySrc+nSrcHeight + EXTRAPIXEL) > pbmi->bmiHeader.biHeight)?
pbmi->bmiHeader.biHeight : (ySrc+nSrcHeight + EXTRAPIXEL);
cScans = iEnd - iStart;
}
if (!MF_AnyDIBits(hdc,
xDest,
yDest,
nDestWidth,
nDestHeight,
xSrc,
ySrc,
nSrcWidth,
nSrcHeight,
iStart,
cScans,
(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);
}
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_PTR)pj & (sizeof(DWORD) - 1))
{
pulBits = LOCALALLOC(cjBits);
if (pulBits)
{
RtlCopyMemory(pulBits,pj,cjBits);
pj = pulBits;
}
}
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (pdcattr)
{
// icm tranlation
//
// Convert bitmap data only when ...
//
// - ICM is enabled.
// - Bitmap is not Palette Index.
// - Bitmap header & data is provided.
// - Bitmap is not passthrough image (BI_JPEG or BI_PNG).
if (IS_ICM_INSIDEDC(pdcattr->lIcmMode) &&
(iUsage != DIB_PAL_COLORS) &&
pbmiNew && pj &&
!IS_BMI_PASSTHROUGH_IMAGE(pbmiNew))
{
LPBITMAPINFO pbmiIcm = NULL;
LPBITMAPINFO pbmiSave = NULL;
PVOID pvBitsIcm = NULL;
ULONG cjHeaderNew = 0;
ULONG cjBitsIcm;
BOOL bIcmStatus;
VOID *pBitsBand = (VOID *)pj;
LONG CurrentBandSize;
LONG SizeOfOneScanline;
LONG IcmSizeOfOneScanline;
LONG nBands;
LONG nScansInBand;
LONG nScansInCurrentBand;
LONG nScansInRemainderBand;
LONG CumulativeScans=0;
LONG i;
LONG PositiveBandDelta=0;
LONG NegativeBandDelta=0;
LONG TotalBandDelta=0;
HRGN hrgnBandClip = NULL;
RECT rectCurrentClip;
LONG HeaderHeightHack;
INT cScanCount=0;
float lMulDivStoreY1;
float lMulDivStoreY2;
SizeOfOneScanline = cjBitmapScanSize(pbmiNew, 1);
//
//pbmiNew must be initialized before getting to this point.
//
ASSERTGDI(pbmiNew!=NULL, "StretchDIBits cannot proceed with pbmiNew==NULL\n");
nScansInBand = BAND_SIZE/SizeOfOneScanline;
//
// Set the number of bands provided there are enough scanlines
// and the hdc is a printer dc.
//
// Else set the nubmer of bands to 1 and the scanlines in the
// remainder band to all of them, so the entire bitmap is printed
// in one band (All the code below reduces to doing a single piece)
//
// If the bitmap is RLE compressed, we set it up to do one band
// only. When this is the case, Start and NegativeBandDelta will be
// computed as 0 and the SizeOfOneScanline parameter will be
// multiplied away to zero.
//
if ((nScansInBand>0)&&
(GetDeviceCaps(hdc, TECHNOLOGY)==DT_RASPRINTER)&&
(!IS_BMI_RLE(pbmiNew)))
{
//
// Compressed images cannot be converted in this way.
// This should never be hit and is included as a guard against
// someone inventing a new compression mode and not updating
// this conditional.
//
//This assert needs a rethink - cjBits refers to the whole image
//which could be larger than the nSrcHeight portion.
//ASSERTGDI(SizeOfOneScanline*nSrcHeight==cjBits, "StretchDIBits, cannot band compressed image");
nBands = (nSrcHeight)/nScansInBand;
nScansInRemainderBand = nSrcHeight % nScansInBand;
}
else
{
nBands = 0;
nScansInRemainderBand = (nSrcHeight);
}
if (nScansInRemainderBand>0)
{
nBands++;
nScansInCurrentBand = nScansInRemainderBand;
}
else
{
nScansInCurrentBand = nScansInBand;
}
if (nBands != 1)
{
//
// We're going to have to modify the bmi for this image to
// coerce NtGdiStretchDIBitsInternal to do the banding.
// There is a codepath that gets to this point with pbmiNew
// set to pbmi (pointer copy) rather than local allocated space.
// if the memory passed in the pointer to pbmi is read only,
// we won't be able to hack the header, so we make a local copy
// for banding.
//
pbmiSave = pbmiNew; //store the old value
pbmiNew = (LPBITMAPINFO)LOCALALLOC(cjHeader);
if (pbmiNew)
{
RtlCopyMemory((LPBYTE)pbmiNew,
(LPBYTE)pbmiSave,
cjHeader);
HeaderHeightHack = pbmiNew->bmiHeader.biHeight;
}
else
{
//
// we need to bail out here. Goto the cleanup code.
//
WARNING("StretchDIBits: couldn't allocate memory for temporary BITMAPINFO\n");
pbmiNew = pbmiSave;
iRet = 0;
goto Exit;
}
}
for (i=0; i<nBands; i++)
{
//
// Initialize band specific size counters.
//
CurrentBandSize = nScansInCurrentBand*SizeOfOneScanline;
IcmSizeOfOneScanline = SizeOfOneScanline;
cjBitsIcm = cjBits;
//
// The Delta refers to the number of extra scanlines to pass
// to the internal blting routines in order to avoid halftone
// seams.
//
// PositiveBandDelta is usually the number of scanlines to
// add on to the end of the band. (relative to the start in
// memory)
//
// NegativeBandDelta is usually the number of scanlines to
// subtract from the begining of the band (ie move the start
// pointer back this many scanlines).
//
// Total BandDelta is simply the total number of extra scans
// added for this band (both at the start and end).
//
// We reverse the sense of positive and negative when rendering
// bottom up DIBs
//
NegativeBandDelta = MIN(EXTRAPIXEL, CumulativeScans);
PositiveBandDelta = MIN(EXTRAPIXEL, MAX(0, nSrcHeight-(CumulativeScans+nScansInCurrentBand)));
TotalBandDelta = NegativeBandDelta+PositiveBandDelta;
if (nBands != 1)
{
//
// We're going to be doing fancy banding stuff with the clip
// region so we'll want to restore it after the band is done.
//
SaveDC(hdc);
//
// Intersect the clip rectangles.
// This clip rectangle is designed to restrict the output to
// just the displayed portion of the band.
// We may pass more scanlines on the top and bottom of the band
// to get halftoning to merge seamlessly.
//
lMulDivStoreY1 = (float)nDestHeight*CumulativeScans;
lMulDivStoreY2 = (float)nDestHeight*(CumulativeScans+nScansInCurrentBand);
iRet = IntersectClipRect(
hdc,
xDest,
yDest+(LONG)(lMulDivStoreY1/nSrcHeight+0.5),
xDest+nDestWidth,
yDest+(LONG)(lMulDivStoreY2/nSrcHeight+0.5));
if (iRet==ERROR)
{
WARNING("StretchDIBits: error intersecting clip rect\n");
RestoreDC(hdc, -1);
goto Exit;
}
//
// Empty clip rectangle
// If the clip regions don't intersect, we can quit without
// doing anything.
//
if (iRet==NULLREGION)
{
RestoreDC(hdc, -1);
//
// Nothing to do - fall through and do
// initialization for next iteration.
//
goto Continue_With_Init;
}
//
// Hack the BITMAPINFO header so that NtGdiStretchDIBitsInternal
// works correctly. Note that hacking it before the ICM call will
// carry through to the NtGdiStretchDIBitsInteral call.
//
// This code also updates the pointer to the bits, in a manner
// appropriate to the topdown/bottomup nature of the DIB.
//
if (HeaderHeightHack >= 0)
{
//
//Bottom Up
//
pBitsBand = (char *)pj + (ySrc+nSrcHeight-nScansInCurrentBand-CumulativeScans-PositiveBandDelta)*SizeOfOneScanline;
pbmiNew->bmiHeader.biHeight = nScansInCurrentBand+TotalBandDelta;
}
else
{
//
//Top Down
//
pBitsBand = (char *)pj + (ySrc+CumulativeScans-NegativeBandDelta)*SizeOfOneScanline;
pbmiNew->bmiHeader.biHeight = -(nScansInCurrentBand+TotalBandDelta);
}
}
else
{
pBitsBand = (char *)pj;
}
//
// Initialize per band ICM variables
//
cjHeaderNew=0;
pbmiIcm = NULL;
pvBitsIcm = NULL;
//
// Call ICM with an oversized band for later halftoning by
// NtGdiStretchDIBitsInternal
//
bIcmStatus = IcmTranslateDIB(
hdc,
pdcattr,
(nBands==1)?cjBits:(CurrentBandSize+TotalBandDelta*SizeOfOneScanline),
(PVOID)pBitsBand,
&pvBitsIcm,
pbmiNew,
&pbmiIcm,
&cjHeaderNew,
(nBands==1)?((DWORD)-1):(nScansInCurrentBand+TotalBandDelta),
iUsage,
ICM_FORWARD,
&pBitmapColorSpace,
&pCXform);
if (bIcmStatus)
{
if (pvBitsIcm == NULL)
{
pvBitsIcm = pBitsBand;
}
if (pbmiIcm == NULL)
{
pbmiIcm = pbmiNew;
cjHeaderNew = cjHeader;
}
else
{
//
// new bits and header means a possibly different size bitmap
// and different size scanline.
//
// if nBands==1 then nScansInCurrentBand==nNumScans and
// TotalBandDelta==0
//
// Also note that nNumScans is the number of scans rendered,
// not the number of scans in the bitmap or converted in
// IcmTranslateDIB for nBands==1 case
//
if(nBands == 1) {
cjBitsIcm = cjBitmapBitsSize(pbmiIcm);
}
CurrentBandSize = cjBitmapScanSize(pbmiIcm, nScansInCurrentBand);
IcmSizeOfOneScanline = cjBitmapScanSize(pbmiIcm, 1);
if (!cjHeaderNew)
{
cjHeaderNew = cjHeader;
}
}
if (pCXform)
{
hcmTempXform = pCXform->ColorTransform;
}
}
else
{
pvBitsIcm = pBitsBand;
pbmiIcm = pbmiNew;
cjHeaderNew = cjHeader;
}
lMulDivStoreY1 = (float)nDestHeight*(CumulativeScans-NegativeBandDelta);
lMulDivStoreY2 = (float)nDestHeight*(nScansInCurrentBand+TotalBandDelta);
iRet = NtGdiStretchDIBitsInternal(
hdc,
xDest,
yDest+(LONG)(lMulDivStoreY1/nSrcHeight+0.5),
nDestWidth,
(LONG)(lMulDivStoreY2/nSrcHeight+0.5),
xSrc,
(nBands==1)?ySrc:0,
nSrcWidth,
nScansInCurrentBand+TotalBandDelta,
(LPBYTE) pvBitsIcm,
(LPBITMAPINFO) pbmiIcm,
iUsage,
lRop,
(UINT)cjHeaderNew,
(nBands==1)?cjBitsIcm:(UINT)CurrentBandSize+TotalBandDelta*IcmSizeOfOneScanline,
hcmTempXform);
if (nBands != 1)
{
//
// Unhack the header
//
pbmiNew->bmiHeader.biHeight = HeaderHeightHack;
}
if (iRet==GDI_ERROR)
{
WARNING("StretchDIBits: NtGdiStretchDIBitsInternal returned GDI_ERROR\n");
if (nBands!=1)
{
RestoreDC(hdc, -1);
}
goto Exit; //Some GDI error and we need to quit.
}
cScanCount+=iRet-TotalBandDelta;
//
//Throw away temp storage
//
if (pBitmapColorSpace)
{
if (pCXform)
{
IcmDeleteColorTransform(pCXform,FALSE);
pCXform = NULL;
}
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
pBitmapColorSpace = NULL;
}
if ((pvBitsIcm!=NULL)&&(pvBitsIcm!=pBitsBand))
{
LOCALFREE(pvBitsIcm);
pvBitsIcm = NULL;
}
if ((pbmiIcm!=NULL)&&(pbmiIcm!=pbmiNew))
{
LOCALFREE(pbmiIcm);
pbmiIcm = NULL;
}
hcmTempXform = NULL;
Continue_With_Init:
//
//Initialize variables for next loop.
//
CumulativeScans += nScansInCurrentBand;
nScansInCurrentBand = nScansInBand;
if (nBands != 1)
{
RestoreDC(hdc, -1);
}
}
if (nBands != 1)
{
ASSERTGDI(pbmiSave!=NULL, "StretchDIBits: pbmiSave==NULL\n");
ASSERTGDI(pbmiNew!=NULL, "StretchDIBits: pbmiNew==NULL\n");
LOCALFREE(pbmiNew);
pbmiNew = pbmiSave;
//
// pbmiNew will be cleaned up in the
// regular cleanup code below.
//
}
//
// We do our own NtGdiSetDIBitsToDeviceInternal
// So we need to fall through to cleanup at this point.
//
iRet=cScanCount;
goto Exit;
}
}
if (bStatus)
{
iRet = NtGdiStretchDIBitsInternal(hdc,
xDest,
yDest,
nDestWidth,
nDestHeight,
xSrc,
ySrc,
nSrcWidth,
nSrcHeight,
(LPBYTE) pj,
(LPBITMAPINFO) pbmiNew,
iUsage,
lRop,
cjHeader,
cjBits,
hcmTempXform);
}
Exit:
if (pulBits)
{
LOCALFREE(pulBits);
}
if (pbmiNew && (pbmiNew != pbmi))
{
LOCALFREE(pbmiNew);
}
return (iRet);
}
/******************************Public*Routine******************************\
*
* History:
* 27-Oct-2000 -by- Pravin Santiago [pravins]
* Wrote it.
\**************************************************************************/
HBITMAP SetBitmapAttributes(HBITMAP hbm, DWORD dwFlags)
{
FIXUP_HANDLE(hbm);
if ((dwFlags & ~SBA_STOCK) != 0)
return (HBITMAP)0;
return (HBITMAP)NtGdiSetBitmapAttributes(hbm,dwFlags);
}
/******************************Public*Routine******************************\
*
* History:
* 27-Oct-2000 -by- Pravin Santiago [pravins]
* Wrote it.
\**************************************************************************/
HBITMAP ClearBitmapAttributes(HBITMAP hbm, DWORD dwFlags)
{
FIXUP_HANDLE(hbm);
if ((dwFlags & ~SBA_STOCK) != 0)
return (HBITMAP)0;
return (HBITMAP)NtGdiClearBitmapAttributes(hbm,dwFlags);
}
/******************************Public*Routine******************************\
*
* History:
* 27-Oct-2000 -by- Pravin Santiago [pravins]
* Wrote it.
\**************************************************************************/
DWORD GetBitmapAttributes(HBITMAP hbm)
{
DWORD dwRet = 0;
FIXUP_HANDLE(hbm);
if (IS_STOCKOBJ(hbm))
dwRet |= SBA_STOCK;
return dwRet;
}
/******************************Public*Routine******************************\
*
* History:
* 27-Oct-2000 -by- Pravin Santiago [pravins]
* Wrote it.
\**************************************************************************/
HBRUSH SetBrushAttributes(HBRUSH hbr, DWORD dwFlags)
{
FIXUP_HANDLE(hbr);
if ((dwFlags & ~SBA_STOCK) != 0)
return (HBRUSH)0;
return (HBRUSH)NtGdiSetBrushAttributes(hbr,dwFlags);
}
/******************************Public*Routine******************************\
*
* History:
* 27-Oct-2000 -by- Pravin Santiago [pravins]
* Wrote it.
\**************************************************************************/
HBRUSH ClearBrushAttributes(HBRUSH hbr, DWORD dwFlags)
{
FIXUP_HANDLE(hbr);
if ((dwFlags & ~SBA_STOCK) != 0)
return (HBRUSH)0;
return (HBRUSH)NtGdiClearBrushAttributes(hbr,dwFlags);
}
/******************************Public*Routine******************************\
*
* History:
* 27-Oct-2000 -by- Pravin Santiago [pravins]
* Wrote it.
\**************************************************************************/
DWORD GetBrushAttributes(HBRUSH hbr)
{
DWORD dwRet = 0;
FIXUP_HANDLE(hbr);
if (IS_STOCKOBJ(hbr))
dwRet |= SBA_STOCK;
return dwRet;
}
/******************************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);
#if TRACE_SURFACE_ALLOCS
{
PULONG pUserAlloc;
PSHARED_GET_VALIDATE(pUserAlloc, hbm, SURF_TYPE);
if (pUserAlloc != NULL)
{
pUserAlloc[1] = RtlWalkFrameChain((PVOID *)&pUserAlloc[2], pUserAlloc[0], 0);
}
}
#endif
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 TRACE_SURFACE_ALLOCS
{
PULONG pUserAlloc;
PSHARED_GET_VALIDATE(pUserAlloc, hbm, SURF_TYPE);
if (pUserAlloc != NULL)
{
pUserAlloc[1] = RtlWalkFrameChain((PVOID *)&pUserAlloc[2], pUserAlloc[0], 0);
}
}
#endif
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);
//
// Does not support passthrough image (BI_JPEG or BI_PNG).
// Return NULL for error.
//
if (IS_BMI_PASSTHROUGH_IMAGE(pbmiNew))
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return hbm;
}
//
// 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) )
{
PCACHED_COLORSPACE pBitmapColorSpace = NULL;
BOOL bCreatedColorSpace = FALSE;
LOGCOLORSPACEW LogColorSpace;
PROFILE ColorProfile;
DWORD dwFlags = 0;
//
// Check they has thier own color space or not.
//
if (pbmiNew && IcmGetBitmapColorSpace(pbmiNew,&LogColorSpace,&ColorProfile,&dwFlags))
{
//
// Find ColorSpace from cache.
//
pBitmapColorSpace = IcmGetColorSpaceByColorSpace(
(HGDIOBJ)hdc,
&LogColorSpace,
&ColorProfile,
dwFlags);
if (pBitmapColorSpace == NULL)
{
//
// If we can not find the color space for this DIBSection from existing color space.
// create new one for this, but we mark it as DIBSECTION_COLORSPACE, then associated
// to this hdc (later hbm), so that we can make sure this color space get deleted
// when hbm is deleted.
//
dwFlags |= DIBSECTION_COLORSPACE;
//
// Mark we will create new colorspace for this bitmap.
//
bCreatedColorSpace = TRUE;
//
// Create new cache.
//
pBitmapColorSpace = IcmCreateColorSpaceByColorSpace(
(HGDIOBJ)hdc,
&LogColorSpace,
&ColorProfile,
dwFlags);
}
}
hbm = NtGdiCreateDIBSection(
hdc,
hSectionApp,
dwOffset,
(LPBITMAPINFO) pbmiNew,
iUsage,
cjHdr,
0,
(ULONG_PTR)pBitmapColorSpace,
(PVOID *)&pjBits);
if ((hbm == NULL) || (pjBits == NULL))
{
hbm = 0;
pjBits = NULL;
if (pBitmapColorSpace)
{
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
}
}
else
{
#if TRACE_SURFACE_ALLOCS
PULONG pUserAlloc;
PSHARED_GET_VALIDATE(pUserAlloc, hbm, SURF_TYPE);
if (pUserAlloc != NULL)
{
pUserAlloc[1] = RtlWalkFrameChain((PVOID *)&pUserAlloc[2], pUserAlloc[0], 0);
}
#endif
if (pBitmapColorSpace && bCreatedColorSpace)
{
//
// if we created new color space for this bitmap,
// set owner of this colorspace to the created bitmap.
//
pBitmapColorSpace->hObj = hbm;
}
}
}
//
// Assign the appropriate value to the caller's pointer
//
if (ppvBits != NULL)
{
*ppvBits = pjBits;
}
if (pbmiNew && (pbmiNew != pbmi))
{
LOCALFREE(pbmiNew);
}
return(hbm);
}