5046 lines
175 KiB
C++
5046 lines
175 KiB
C++
/******************************Module*Header*******************************\
|
||
* Module Name: dibapi.cxx
|
||
*
|
||
* This contains all the functions relating to DIBs
|
||
*
|
||
* Created: 12-Mar-1991 13:53:29
|
||
* Author: Patrick Haluptzok patrickh
|
||
*
|
||
* Copyright (c) 1990-1999 Microsoft Corporation
|
||
\**************************************************************************/
|
||
|
||
#include "precomp.hxx"
|
||
|
||
BOOL bIdenticalFormat (XEPALOBJ, INT);
|
||
|
||
//
|
||
// This is to convert BMF constants into max # of palette entries
|
||
//
|
||
|
||
ULONG gacPalEntries[7] =
|
||
{
|
||
0,
|
||
2,
|
||
16,
|
||
256,
|
||
0,
|
||
0,
|
||
0
|
||
};
|
||
|
||
extern PAL_ULONG aPalVGA[16];
|
||
|
||
//
|
||
// 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))
|
||
|
||
//
|
||
// IS_CMYK_BITMAP
|
||
//
|
||
// Checks if the bitmap uses CMYK color data either in color table or bitmap
|
||
// itself.
|
||
//
|
||
|
||
#define IS_CMYK_BITMAP(biCompression) \
|
||
(((biCompression) == BI_CMYK) || \
|
||
((biCompression) == BI_CMYKRLE4) || \
|
||
((biCompression) == BI_CMYKRLE8))
|
||
|
||
/******************************Public*Routine******************************\
|
||
* vCopyCoreToInfoHeader
|
||
*
|
||
* Copy a BITMAPCOREINFOHEADER to BITMAPINFOHEADER
|
||
*
|
||
* 06-Mar-1995 -by- Lingyun Wang [lingyunw]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
VOID vCopyCoreToInfoHeader(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******************************\
|
||
* vCopyCoreToInfoColorTable
|
||
*
|
||
* Copy a RGBTRIPLE color table to a RGBQUAD color table
|
||
*
|
||
* 06-Mar-1995 -by- Lingyun Wang [lingyunw]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
VOID vCopyCoreToInfoColorTable(RGBQUAD *pQuad, RGBTRIPLE *pTri, INT cEntries, INT iUsage)
|
||
{
|
||
INT cj;
|
||
|
||
cj = cEntries;
|
||
|
||
if (iUsage != DIB_PAL_COLORS)
|
||
{
|
||
while (cj--)
|
||
{
|
||
pQuad->rgbRed = pTri->rgbtRed;
|
||
pQuad->rgbGreen = pTri->rgbtGreen;
|
||
pQuad->rgbBlue = pTri->rgbtBlue;
|
||
pQuad->rgbReserved = 0;
|
||
|
||
pQuad++;
|
||
pTri++;
|
||
}
|
||
}
|
||
else
|
||
// DIB_PAL_COLORS
|
||
{
|
||
RtlCopyMemory((LPBYTE)pQuad,(LPBYTE)pTri,cEntries * sizeof(USHORT));
|
||
}
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreCreateDIBitmapComp
|
||
*
|
||
* Only called by CreateDIBitmap from client - when CREATEDIB is not set
|
||
*
|
||
* History:
|
||
*
|
||
* 03-Mar-1995 -by- Lingyun Wang [lingyunw]
|
||
* Changed from GreCreateDIBitmapInternal.
|
||
\**************************************************************************/
|
||
|
||
HBITMAP
|
||
APIENTRY
|
||
GreCreateDIBitmapComp(
|
||
HDC hdc,
|
||
INT cx,
|
||
INT cy,
|
||
DWORD fInit,
|
||
LPBYTE pInitBits,
|
||
LPBITMAPINFO pInitInfo,
|
||
DWORD iUsage,
|
||
UINT cjMaxInitInfo,
|
||
UINT cjMaxBits,
|
||
FLONG fl,
|
||
HANDLE hcmXform)
|
||
{
|
||
DEVBITMAPINFO dbmi;
|
||
|
||
//
|
||
// It is old style call so do the compatible thing.
|
||
// Let's validate some of the parameters
|
||
//
|
||
|
||
if ((iUsage != DIB_PAL_INDICES) &&
|
||
(iUsage != DIB_PAL_COLORS) &&
|
||
(iUsage != DIB_RGB_COLORS))
|
||
{
|
||
WARNING1("GreCreateDIBitmapComp failed because of invalid parameters\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// Cannot support the device passthrough formats (BI_JPEG, BI_PNG).
|
||
//
|
||
|
||
if (IS_BMI_PASSTHROUGH_IMAGE(pInitInfo))
|
||
{
|
||
WARNING1("GreCreateDIBitmapComp invalid pInitInfo (BITMAPINFOHEADER)\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
dbmi.cxBitmap = cx;
|
||
|
||
//
|
||
// Check for the upside down bitmaps.
|
||
//
|
||
|
||
if (cy < 0)
|
||
{
|
||
dbmi.cyBitmap = -cy;
|
||
}
|
||
else
|
||
{
|
||
dbmi.cyBitmap = cy;
|
||
}
|
||
|
||
HBITMAP hbmReturn = GreCreateCompatibleBitmap(hdc, (int) dbmi.cxBitmap, (int) dbmi.cyBitmap);
|
||
|
||
if (hbmReturn)
|
||
{
|
||
if ((fInit & CBM_INIT) &&
|
||
(pInitBits != NULL) &&
|
||
(pInitInfo != NULL))
|
||
{
|
||
if (GreSetDIBitsInternal(
|
||
hdc,
|
||
hbmReturn,
|
||
0,
|
||
(UINT) dbmi.cyBitmap,
|
||
pInitBits,
|
||
pInitInfo,
|
||
(UINT) iUsage,
|
||
cjMaxBits,
|
||
cjMaxInitInfo,
|
||
hcmXform
|
||
))
|
||
{
|
||
return(hbmReturn);
|
||
}
|
||
else
|
||
{
|
||
WARNING1("CreateDIBitmapComp failed SetDIBits compat\n");
|
||
}
|
||
}
|
||
else
|
||
{
|
||
return(hbmReturn);
|
||
}
|
||
|
||
GreDeleteObject(hbmReturn);
|
||
}
|
||
|
||
WARNING1("CreateDIBitmapComp failed CreateCompatBitmap\n");
|
||
return(0);
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreCreateDIBitmapReal
|
||
*
|
||
* Called by CreateDIBitmap from client when CREATEDIB is set and
|
||
* CreateDIBSection
|
||
*
|
||
* hdc - handle of device context
|
||
* pInfoHeader - bitmap size and format
|
||
* fInit - initialization flag
|
||
* pInitBits - initialization data
|
||
* pInitInfo - initialization color info
|
||
* iUsage - color-data usage
|
||
* cjMaxInitInfo - size of bitmapinfo
|
||
* cjMaxBits - size of bitmap
|
||
* hSection - For DIBSECTION, Section or NULL
|
||
* dwOffset - For DIBSECTION
|
||
* hSecure - For DIBSECTION, VM Secure handle
|
||
* fl - creation flags
|
||
* dwColorSpace - identifier of client side color space data
|
||
* ppvBits - receives pointer to the bitmap bits
|
||
*
|
||
* History:
|
||
*
|
||
* 07-Apr-1995 -by- Mark Enstrom [marke]
|
||
* add DIBSection support
|
||
* 03-Mar-1995 -by- Lingyun Wang [lingyunw]
|
||
* Changed from GreCreateDIBitmapInternal.
|
||
* 04-Dec-1990 -by- Patrick Haluptzok patrickh
|
||
\**************************************************************************/
|
||
|
||
HBITMAP
|
||
APIENTRY
|
||
GreCreateDIBitmapReal(
|
||
HDC hdc,
|
||
DWORD fInit,
|
||
LPBYTE pInitBits,
|
||
LPBITMAPINFO pInitInfo,
|
||
DWORD iUsage,
|
||
UINT cjMaxInitInfo,
|
||
UINT cjMaxBits,
|
||
HANDLE hSection,
|
||
DWORD dwOffset,
|
||
HANDLE hSecure,
|
||
FLONG fl,
|
||
ULONG_PTR dwColorSpace,
|
||
PVOID *ppvBits)
|
||
{
|
||
ULONG ulSize;
|
||
DEVBITMAPINFO dbmi;
|
||
|
||
//
|
||
// It is a new DIB bitmap creation. This code can essentially
|
||
// be used as the base for CreateDIBSection when it is written.
|
||
//
|
||
// Let's validate some of the parameters.
|
||
//
|
||
|
||
if (((iUsage != DIB_PAL_COLORS) &&
|
||
(iUsage != DIB_PAL_NONE) &&
|
||
(iUsage != DIB_RGB_COLORS)) ||
|
||
((iUsage == DIB_PAL_NONE) && ((fl & CDBI_INTERNAL) == 0)) ||
|
||
(pInitInfo == (LPBITMAPINFO) NULL) ||
|
||
(cjMaxInitInfo < sizeof(BITMAPINFOHEADER)) || // Check first so we can access biSize.
|
||
(cjMaxInitInfo < (ulSize = pInitInfo->bmiHeader.biSize)) ||
|
||
(IS_BMI_PASSTHROUGH_IMAGE(pInitInfo)) ||
|
||
(ulSize < sizeof(BITMAPINFOHEADER)))
|
||
{
|
||
WARNING1("GreCreateDIBitmapReal failed new DIB because of invalid parameters\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
UINT uiCompression;
|
||
dbmi.fl = 0;
|
||
|
||
PULONG pulColors;
|
||
ULONG ulClrUsed;
|
||
|
||
cjMaxInitInfo -= ((UINT) ulSize);
|
||
|
||
dbmi.cxBitmap = pInitInfo->bmiHeader.biWidth;
|
||
|
||
if (pInitInfo->bmiHeader.biHeight < 0)
|
||
{
|
||
dbmi.cyBitmap = -(pInitInfo->bmiHeader.biHeight);
|
||
dbmi.fl = BMF_TOPDOWN;
|
||
}
|
||
else
|
||
{
|
||
dbmi.cyBitmap = pInitInfo->bmiHeader.biHeight;
|
||
}
|
||
|
||
dbmi.iFormat = (UINT) pInitInfo->bmiHeader.biBitCount;
|
||
uiCompression = (UINT) pInitInfo->bmiHeader.biCompression;
|
||
ulClrUsed = (ULONG) pInitInfo->bmiHeader.biClrUsed;
|
||
pulColors = (PULONG) ((LPBYTE)pInitInfo+ulSize);
|
||
|
||
//
|
||
// Figure out what this guy is asking for
|
||
//
|
||
|
||
ULONG cColors;
|
||
FLONG iPalMode = PAL_INDEXED;
|
||
FLONG iPalType;
|
||
FLONG flRed;
|
||
FLONG flGre;
|
||
FLONG flBlu;
|
||
|
||
if (uiCompression == BI_RGB)
|
||
{
|
||
switch (dbmi.iFormat)
|
||
{
|
||
case 1:
|
||
dbmi.iFormat = BMF_1BPP;
|
||
cColors = 2;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 4:
|
||
dbmi.iFormat = BMF_4BPP;
|
||
cColors = 16;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 8:
|
||
dbmi.iFormat = BMF_8BPP;
|
||
cColors = 256;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
default:
|
||
|
||
if (iUsage == DIB_PAL_COLORS)
|
||
{
|
||
iUsage = DIB_RGB_COLORS;
|
||
}
|
||
|
||
cColors = 0;
|
||
iPalType = PAL_FIXED;
|
||
|
||
switch (dbmi.iFormat)
|
||
{
|
||
case 16:
|
||
dbmi.iFormat = BMF_16BPP;
|
||
flRed = 0x7c00;
|
||
flGre = 0x03e0;
|
||
flBlu = 0x001f;
|
||
iPalMode = PAL_BITFIELDS;
|
||
break;
|
||
case 24:
|
||
dbmi.iFormat = BMF_24BPP;
|
||
iPalMode = PAL_BGR;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
iPalMode = PAL_BGR;
|
||
break;
|
||
default:
|
||
WARNING1("CreateDIBitmapReal failed invalid bitcount in bmi for BI_RGB\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
}
|
||
}
|
||
else if (uiCompression == BI_BITFIELDS)
|
||
{
|
||
if (
|
||
(
|
||
(ulSize <= sizeof(BITMAPINFOHEADER)) &&
|
||
(cjMaxInitInfo < (sizeof(ULONG) * 3))
|
||
) ||
|
||
(iUsage != DIB_RGB_COLORS)
|
||
)
|
||
{
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
WARNING1("CreateDIBitmapReal 16bpp failed - no room for flags\n");
|
||
return((HBITMAP) 0);
|
||
}
|
||
|
||
//
|
||
// if BITMAPV4 or greater then masks are stored in info header
|
||
//
|
||
|
||
if (ulSize >= sizeof(BITMAPINFOHEADER))
|
||
{
|
||
pulColors = (PULONG) ((LPBYTE)pInitInfo+sizeof(BITMAPINFOHEADER));
|
||
}
|
||
|
||
flRed = pulColors[0];
|
||
flGre = pulColors[1];
|
||
flBlu = pulColors[2];
|
||
|
||
cColors = 0;
|
||
iPalMode = PAL_BITFIELDS;
|
||
iPalType = PAL_FIXED;
|
||
|
||
switch (dbmi.iFormat)
|
||
{
|
||
case 16:
|
||
dbmi.iFormat = BMF_16BPP;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
break;
|
||
default:
|
||
WARNING1("CreateDIBitmap failed invalid bitcount in bmi in BI_BITFIELDS\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
}
|
||
else if (uiCompression == BI_CMYK)
|
||
{
|
||
ASSERTGDI(iUsage == DIB_RGB_COLORS,
|
||
"CreateDIBitmap(BI_CMYK):iUsage should be DIB_RGB_COLORS\n");
|
||
|
||
DCOBJ dco(hdc);
|
||
|
||
//
|
||
// Current device context accept CMYK color ?
|
||
//
|
||
if (!dco.bValid() || !dco.pdc->bIsCMYKColor())
|
||
{
|
||
WARNING1("CreateDIBitmapReal:DC is not in CMYK color mode for BI_CMYK\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
switch (dbmi.iFormat)
|
||
{
|
||
case 1:
|
||
dbmi.iFormat = BMF_1BPP;
|
||
cColors = 2;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 4:
|
||
dbmi.iFormat = BMF_4BPP;
|
||
cColors = 16;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 8:
|
||
dbmi.iFormat = BMF_8BPP;
|
||
cColors = 256;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
cColors = 0;
|
||
iPalMode = PAL_CMYK;
|
||
iPalType = PAL_FIXED;
|
||
break;
|
||
default:
|
||
WARNING1("CreateDIBitmapReal failed invalid bitcount in bmi for BI_CMYK\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
WARNING1("CreateDIBitmap failed - invalid Compression\n");
|
||
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// Allocate a palette for this bitmap.
|
||
//
|
||
|
||
PALMEMOBJ palPerm;
|
||
|
||
if (!palPerm.bCreatePalette(iPalMode, cColors, (PULONG) NULL,
|
||
flRed, flGre, flBlu, iPalType))
|
||
{
|
||
WARNING1("Failed palette creation in GreCreateBitmap\n");
|
||
return(0);
|
||
}
|
||
|
||
dbmi.hpal = (HPALETTE) palPerm.hpal();
|
||
|
||
//
|
||
// Attempt to allocate the bitmap from handle manager.
|
||
//
|
||
|
||
SURFMEM SurfDimo;
|
||
PBYTE pDIB = (PBYTE) NULL;
|
||
HANDLE hDIB = NULL;
|
||
|
||
|
||
if (fl & CDBI_DIBSECTION)
|
||
{
|
||
//
|
||
// Let's mark the palette created as being a DIBSECTION palette
|
||
// so when we attempt to map it to another palette we try to
|
||
// make it identity before going through the closest match search.
|
||
//
|
||
|
||
palPerm.flPal(PAL_DIBSECTION);
|
||
|
||
|
||
//
|
||
// In kernel mode, pInitBits contains the DIBSection address
|
||
//
|
||
|
||
pDIB = pInitBits;
|
||
hDIB = hSection;
|
||
|
||
if (pDIB == (PVOID)NULL)
|
||
{
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// Clear pInitBits so we can fall through nicely later.
|
||
//
|
||
|
||
pInitBits = (LPBYTE) NULL;
|
||
}
|
||
else if (hdc)
|
||
{
|
||
DCOBJ dco(hdc);
|
||
|
||
if (dco.bValid() && dco.bUMPD())
|
||
dbmi.fl |= UMPD_SURFACE;
|
||
}
|
||
|
||
if (!SurfDimo.bCreateDIB(&dbmi, pDIB, hDIB, dwOffset, hSecure, dwColorSpace) ||
|
||
(SurfDimo.ps->bDIBSection() && (SurfDimo.ps->cjBits() != cjMaxBits)))
|
||
{
|
||
WARNING("GreCreateDIBitmap failed bCreateDIB or size mismatch\n");
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// Initialize bits if provided.
|
||
//
|
||
|
||
if (pInitBits != (LPBYTE) NULL)
|
||
{
|
||
ASSERTGDI(fInit & CBM_INIT, "CreateDIBitmap bits sent but no CBM_INIT set");
|
||
|
||
if (SurfDimo.ps->cjBits() > cjMaxBits)
|
||
{
|
||
WARNING1("CreateDIBitmap failed because invalid bitmap buffer size CBM_CREATEDIB\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
RtlCopyMemory(SurfDimo.ps->pvBits(), (PVOID) pInitBits, (UINT) SurfDimo.ps->cjBits());
|
||
}
|
||
|
||
//
|
||
// Check if it is not equal to 0. If it is not 0 use that as the number
|
||
// of palette entries to initialize. If it is 0 then cPalEntries has the
|
||
// correct number already computed in it.
|
||
//
|
||
|
||
if (ulClrUsed != 0)
|
||
{
|
||
if (ulClrUsed < cColors)
|
||
{
|
||
cColors = ulClrUsed;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Intitialize the palette
|
||
//
|
||
|
||
if (cColors)
|
||
{
|
||
ASSERTGDI(iUsage != DIB_PAL_INDICES, "ERROR logic error, should have returned FALSE");
|
||
|
||
switch (iUsage)
|
||
{
|
||
case DIB_RGB_COLORS:
|
||
if (cjMaxInitInfo < (cColors * 4))
|
||
{
|
||
WARNING1("CreateDIBitmap failed DIB_RGB_COLORS size buffer RGBQUAD\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// Copy bitmap color table into palette
|
||
//
|
||
|
||
if (IS_CMYK_BITMAP(uiCompression))
|
||
{
|
||
palPerm.vCopy_cmykquad(pulColors, 0, cColors);
|
||
}
|
||
else
|
||
{
|
||
palPerm.vCopy_rgbquad((RGBQUAD *) pulColors, 0, cColors);
|
||
}
|
||
|
||
//
|
||
// NOPALETTE is a private option for DirectDraw to permit the
|
||
// DIBSection to share its colour table with the display.
|
||
//
|
||
|
||
if ((fl & CDBI_NOPALETTE) && (dbmi.iFormat == BMF_8BPP))
|
||
{
|
||
BOOL b;
|
||
DCOBJ dco(hdc);
|
||
|
||
b = FALSE;
|
||
if (dco.bValid())
|
||
{
|
||
PDEVOBJ po(dco.hdev());
|
||
|
||
//
|
||
// Acquire the devlock to protect us from a dynamic mode
|
||
// change while we muck with po.ppalSurf():
|
||
//
|
||
|
||
DEVLOCKOBJ dlo(po);
|
||
|
||
if ((po.iDitherFormat() == BMF_8BPP) &&
|
||
(po.bIsPalManaged()) &&
|
||
(po.bDisplayPDEV()))
|
||
{
|
||
b = TRUE;
|
||
palPerm.apalColorSet(po.ppalSurf());
|
||
}
|
||
}
|
||
|
||
if (!b)
|
||
{
|
||
WARNING("Display not 8bpp, failing CreateDIBSection(CDBI_NOPALETTE)");
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case DIB_PAL_COLORS:
|
||
|
||
{
|
||
PUSHORT pusIndices;
|
||
|
||
if (cjMaxInitInfo < (cColors * sizeof(USHORT)))
|
||
{
|
||
WARNING1("CreateDIBitmap failed DIB_PAL_COLORS size buffer USHORT\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
pusIndices = (PUSHORT) pulColors;
|
||
|
||
//
|
||
// Validate the DC.
|
||
//
|
||
|
||
DCOBJ dco(hdc);
|
||
|
||
if (!dco.bValid())
|
||
{
|
||
WARNING1("CreateDIBitmap failed CBM_CREATEDIB because DIB_PAL_COLORS and invalid DC\n");
|
||
return(0);
|
||
}
|
||
{
|
||
//
|
||
// Hold the Devlock while munging around in the
|
||
// surface to protect against dynamic mode changing.
|
||
//
|
||
|
||
DEVLOCKOBJ dlo;
|
||
|
||
dlo.vLockNoDrawing(dco);
|
||
|
||
SURFACE *pSurf = dco.pSurfaceEff();
|
||
PDEVOBJ po(dco.hdev());
|
||
XEPALOBJ palSurf(pSurf->ppal() ? pSurf->ppal() : po.ppalSurf());
|
||
XEPALOBJ palDC(dco.ppal());
|
||
palPerm.vGetEntriesFrom(palDC, palSurf, pusIndices, cColors);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case DIB_PAL_NONE:
|
||
|
||
//
|
||
// This is so CreateDIBPatternBrush can call off to this to do the
|
||
// work and then init the palette himself.
|
||
//
|
||
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (ppvBits)
|
||
{
|
||
*ppvBits = SurfDimo.ps->pvBits();
|
||
}
|
||
|
||
//
|
||
// Make the palette a keeper and return.
|
||
//
|
||
|
||
SurfDimo.ps->vSetApiBitmap();
|
||
SurfDimo.vKeepIt();
|
||
palPerm.vKeepIt();
|
||
return((HBITMAP)SurfDimo.ps->hsurf());
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreSetDIBitsInternal
|
||
*
|
||
* API function - Sets the bits of a DIB to a bitmap.
|
||
*
|
||
* Arguments:
|
||
*
|
||
* hdc - handle of device context
|
||
* hbmp - handle of bitmap
|
||
* iStartScan - starting scan line
|
||
* cNumScans - number of scan lines
|
||
* pInitBits - array of bitmap bits
|
||
* pInitInfo - address of structure with bitmap data
|
||
* iUsage - type of color indices to use
|
||
* cjMaxBits - maximum size of pInitBits
|
||
* cjMaxInfo - maximum size of cjMaxInfo
|
||
* hcmXform - handle of color transformation (optional)
|
||
*
|
||
* History:
|
||
*
|
||
* 12-Mar-1991 -by- Patrick Haluptzok patrickh
|
||
\**************************************************************************/
|
||
|
||
int
|
||
APIENTRY
|
||
GreSetDIBits(
|
||
HDC hdc,
|
||
HBITMAP hbm,
|
||
UINT iStartScans,
|
||
UINT cNumScans,
|
||
LPBYTE pInitBits,
|
||
LPBITMAPINFO pInitInfo,
|
||
UINT iUsage)
|
||
{
|
||
PBITMAPINFO pbmi = pInitInfo;
|
||
INT iRet;
|
||
|
||
//
|
||
// if it is a COREHEADER, covert it
|
||
//
|
||
if (pInitInfo && (pInitInfo->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)))
|
||
{
|
||
pbmi = pbmiConvertInfo (pInitInfo, iUsage);
|
||
}
|
||
|
||
//
|
||
// Cannot support the device passthrough formats (BI_JPEG, BI_PNG).
|
||
//
|
||
|
||
if (IS_BMI_PASSTHROUGH_IMAGE(pInitInfo))
|
||
{
|
||
WARNING1("GreSetDIBits invalid pInitBits\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
iRet = GreSetDIBitsInternal(
|
||
hdc,
|
||
hbm,
|
||
iStartScans,
|
||
cNumScans,
|
||
pInitBits,
|
||
pbmi,
|
||
iUsage,
|
||
(UINT)~0,
|
||
(UINT)~0,
|
||
NULL);
|
||
|
||
if (pbmi && (pbmi != pInitInfo))
|
||
{
|
||
VFREEMEM (pbmi);
|
||
}
|
||
|
||
return (iRet);
|
||
}
|
||
|
||
int
|
||
APIENTRY
|
||
GreSetDIBitsInternal(
|
||
HDC hdc,
|
||
HBITMAP hbm,
|
||
UINT iStartScans,
|
||
UINT cNumScans,
|
||
LPBYTE pInitBits,
|
||
LPBITMAPINFO pInitInfo,
|
||
UINT iUsage,
|
||
UINT cjMaxBits,
|
||
UINT cjMaxInfo,
|
||
HANDLE hcmXform)
|
||
{
|
||
//
|
||
// Lock down and validate the bitmap. Make sure it's a bitmap.
|
||
//
|
||
|
||
HDC hdcTemp;
|
||
HPALETTE hpalTemp = (HPALETTE) 0;
|
||
HBITMAP hbmTemp;
|
||
int iReturn = 0;
|
||
BOOL bMakeDC = FALSE;
|
||
ULONG cx;
|
||
ULONG cy;
|
||
|
||
//
|
||
// Validate header and cannot support the device
|
||
// passthrough formats (BI_JPEG, BI_PNG).
|
||
//
|
||
|
||
if ((pInitInfo == (LPBITMAPINFO) NULL) ||
|
||
IS_BMI_PASSTHROUGH_IMAGE(pInitInfo))
|
||
{
|
||
WARNING1("GreSetDIBitsInternal failed - pInitInfo is invalid\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
}
|
||
else
|
||
{
|
||
ASSERTGDI (pInitInfo->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER), "setdibitstodevice,bad size\n");
|
||
|
||
cx = pInitInfo->bmiHeader.biWidth;
|
||
if (pInitInfo->bmiHeader.biHeight < 0)
|
||
{
|
||
cy = -pInitInfo->bmiHeader.biHeight;
|
||
}
|
||
else
|
||
{
|
||
cy = pInitInfo->bmiHeader.biHeight;
|
||
}
|
||
|
||
SURFREF soDest((HSURF)hbm);
|
||
|
||
if ((!soDest.bValid()) || (!soDest.ps->bApiBitmap()))
|
||
{
|
||
WARNING1("SetDIBits failed - Bitmap is not valid\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
||
}
|
||
else
|
||
{
|
||
if (soDest.ps->cRef() != 0)
|
||
{
|
||
hdcTemp = soDest.ps->hdc();
|
||
}
|
||
else
|
||
{
|
||
hdcTemp = (HDC) NULL;
|
||
}
|
||
|
||
if (hdcTemp == (HDC) NULL)
|
||
{
|
||
hdcTemp = GreCreateCompatibleDC(hdc);
|
||
bMakeDC = TRUE;
|
||
|
||
if (hdcTemp == (HDC) NULL)
|
||
{
|
||
WARNING1("GreSetDIBits failed CreateCompatibleDC, is hdc valid?\n");
|
||
}
|
||
}
|
||
|
||
if (hdcTemp != (HDC)NULL)
|
||
{
|
||
BOOL bSuccess = TRUE;
|
||
|
||
if (hdc != (HDC) NULL)
|
||
{
|
||
DCOBJ dco(hdc);
|
||
|
||
if (!dco.bValid())
|
||
{
|
||
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
||
WARNING1("SetDIBits failed - hdc is invalid\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
hpalTemp = (HPALETTE) GreSelectPalette(hdcTemp, (HPALETTE)dco.hpal(), (BOOL)TRUE);
|
||
}
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
|
||
hbmTemp = (HBITMAP)GreSelectBitmap(hdcTemp, (HBITMAP)hbm);
|
||
|
||
if (hbmTemp == (HBITMAP) 0)
|
||
{
|
||
WARNING1("GreSetDIBits failed to Select, is bitmap valid?\n");
|
||
}
|
||
else
|
||
{
|
||
|
||
iReturn = GreSetDIBitsToDeviceInternal(
|
||
hdcTemp,
|
||
0,
|
||
0,
|
||
cx,
|
||
cy,
|
||
0,
|
||
0,
|
||
iStartScans,
|
||
cNumScans,
|
||
pInitBits,
|
||
pInitInfo,
|
||
iUsage,
|
||
cjMaxBits,
|
||
cjMaxInfo,
|
||
FALSE,
|
||
hcmXform
|
||
);
|
||
|
||
if (hpalTemp != (HPALETTE) 0)
|
||
{
|
||
GreSelectPalette(hdcTemp, hpalTemp, TRUE);
|
||
}
|
||
|
||
GreSelectBitmap(hdcTemp, (HBITMAP)hbmTemp);
|
||
|
||
}
|
||
}
|
||
|
||
if (bMakeDC)
|
||
{
|
||
bDeleteDCInternal(hdcTemp,TRUE,FALSE);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return(iReturn);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreSetDIBitsToDevice
|
||
*
|
||
* API entry point for blting DIBS to a DC.
|
||
*
|
||
* Arguments:
|
||
*
|
||
* hdcDest - handle of device context
|
||
* xDst - x-coordinate of upper-left corner of dest. rect.
|
||
* yDst - y-coordinate of upper-left corner of dest. rect.
|
||
* cx - source rectangle width
|
||
* cy - source rectangle height
|
||
* xSrc - x-coordinate of lower-left corner of source rect.
|
||
* ySrc - y-coordinate of lower-left corner of source rect.
|
||
* iStartScan - first scan line in array
|
||
* cNumScan - number of scan lines
|
||
* pInitBits - address of array with DIB bits
|
||
* pInfoHeader - address of structure with bitmap info.
|
||
* iUsage - RGB or palette indices
|
||
* cjMaxBits - maximum soace of pInitBits
|
||
* cjMaxInfo - maximum soace ofpInfoHeader
|
||
* bTransformCoordinates - Transform necessary
|
||
*
|
||
* Return Value:
|
||
*
|
||
* Number of scan lines set or 0 for error
|
||
*
|
||
* History:
|
||
*
|
||
* 12-Mar-1991 -by- Patrick Haluptzok patrickh
|
||
\**************************************************************************/
|
||
|
||
// I believe nobody should be calling this, but just in case... (erick)
|
||
// The internal version is called by server.c
|
||
|
||
int
|
||
APIENTRY
|
||
GreSetDIBitsToDevice(
|
||
HDC hdcDest,
|
||
int xDst,
|
||
int yDst,
|
||
DWORD cx,
|
||
DWORD cy,
|
||
int xSrc,
|
||
int ySrc,
|
||
DWORD iStartScan,
|
||
DWORD cNumScan,
|
||
LPBYTE pInitBits,
|
||
LPBITMAPINFO pInfoHeader,
|
||
DWORD iUsage)
|
||
{
|
||
return(GreSetDIBitsToDeviceInternal(
|
||
hdcDest,
|
||
xDst,
|
||
yDst,
|
||
cx,
|
||
cy,
|
||
xSrc,
|
||
ySrc,
|
||
iStartScan,
|
||
cNumScan,
|
||
pInitBits,
|
||
pInfoHeader,
|
||
iUsage,
|
||
(UINT)~0,
|
||
(UINT)~0,
|
||
TRUE,
|
||
NULL));
|
||
}
|
||
|
||
|
||
int
|
||
APIENTRY
|
||
GreSetDIBitsToDeviceInternal(
|
||
HDC hdcDest,
|
||
int xDst,
|
||
int yDst,
|
||
DWORD cx,
|
||
DWORD cy,
|
||
int xSrc,
|
||
int ySrc,
|
||
DWORD iStartScan,
|
||
DWORD cNumScan,
|
||
LPBYTE pInitBits,
|
||
LPBITMAPINFO pInfoHeader,
|
||
DWORD iUsage,
|
||
UINT cjMaxBits,
|
||
UINT cjMaxInfo,
|
||
BOOL bTransformCoordinates,
|
||
HANDLE hcmXform)
|
||
{
|
||
// If the dc is mirrored then make x point to the most left point.
|
||
if (GreGetLayout(hdcDest) & LAYOUT_RTL) {
|
||
xDst += (cx - 1);
|
||
}
|
||
|
||
//
|
||
// Size of bitmap info header, copy out, it can change async.
|
||
//
|
||
|
||
ULONG ulSize;
|
||
|
||
//
|
||
// Let's validate the parameters so we don't gp-fault ourselves and
|
||
// to save checks later on.
|
||
//
|
||
|
||
if ((pInfoHeader == (LPBITMAPINFO) NULL) ||
|
||
(pInitBits == (LPBYTE) NULL) ||
|
||
((iUsage != DIB_RGB_COLORS) &&
|
||
(iUsage != DIB_PAL_COLORS) &&
|
||
(iUsage != DIB_PAL_INDICES)) ||
|
||
(cjMaxInfo < sizeof(BITMAPINFOHEADER)) ||
|
||
( pInfoHeader->bmiHeader.biSize < sizeof(BITMAPINFOHEADER)))
|
||
{
|
||
WARNING1("GreSetDIBitsToDevice failed because 1 of last 3 params is invalid\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
ulSize = pInfoHeader->bmiHeader.biSize;
|
||
|
||
//
|
||
// Get the info from the Header depending upon what kind it is.
|
||
//
|
||
|
||
UINT uiBitCount, uiCompression, uiWidth, uiPalUsed;
|
||
LONG lHeight;
|
||
PULONG pulColors;
|
||
DEVBITMAPINFO dbmi;
|
||
dbmi.fl = 0;
|
||
dbmi.hpal = 0;
|
||
|
||
uiBitCount = (UINT) pInfoHeader->bmiHeader.biBitCount;
|
||
uiCompression = (UINT) pInfoHeader->bmiHeader.biCompression;
|
||
uiWidth = (UINT) pInfoHeader->bmiHeader.biWidth;
|
||
lHeight = pInfoHeader->bmiHeader.biHeight;
|
||
uiPalUsed = (UINT) pInfoHeader->bmiHeader.biClrUsed;
|
||
pulColors = (PULONG) ((LPBYTE)pInfoHeader+ulSize);
|
||
|
||
if (lHeight < 0)
|
||
{
|
||
dbmi.fl = BMF_TOPDOWN;
|
||
|
||
if ((uiCompression != BI_RGB) && (uiCompression != BI_BITFIELDS) &&
|
||
(uiCompression != BI_JPEG) && (uiCompression != BI_PNG) &&
|
||
(uiCompression != BI_CMYK) && (uiCompression != BI_CMYKRLE4) &&
|
||
(uiCompression != BI_CMYKRLE8))
|
||
{
|
||
WARNING1("GreSetDIBits: TOP_DOWN RLE not allowed\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return (0);
|
||
}
|
||
|
||
lHeight = -lHeight;
|
||
}
|
||
|
||
//
|
||
// Now that cjMaxInfo has been validated for the header, adjust it to refer to
|
||
// the color table
|
||
//
|
||
|
||
cjMaxInfo -= (UINT)ulSize;
|
||
|
||
//
|
||
// Figure out what this guy is blting from.
|
||
//
|
||
|
||
ULONG cColorsMax;
|
||
FLONG iPalMode;
|
||
FLONG iPalType;
|
||
FLONG flRed;
|
||
FLONG flGre;
|
||
FLONG flBlu;
|
||
|
||
BOOL bRLE = FALSE;
|
||
|
||
if (uiCompression == BI_BITFIELDS)
|
||
{
|
||
//
|
||
// Handle 16 and 32 bit per pel bitmaps.
|
||
//
|
||
|
||
if ((ulSize <= sizeof(BITMAPINFOHEADER)) && (cjMaxInfo < (sizeof(ULONG) * 3)))
|
||
{
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
WARNING1("SetDIBitsToDevice 16/32bpp failed - not room for flags\n");
|
||
return(0);
|
||
}
|
||
|
||
if (iUsage == DIB_PAL_COLORS)
|
||
{
|
||
iUsage = DIB_RGB_COLORS;
|
||
}
|
||
|
||
switch (uiBitCount)
|
||
{
|
||
case 16:
|
||
dbmi.iFormat = BMF_16BPP;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
break;
|
||
default:
|
||
WARNING1("SetDIBitsToDevice failed for BI_BITFIELDS\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// if BITMAPV4 or greater then masks are stored in info header
|
||
//
|
||
|
||
if (ulSize > sizeof(BITMAPINFOHEADER))
|
||
{
|
||
pulColors = (PULONG) ((LPBYTE)pInfoHeader+sizeof(BITMAPINFOHEADER));
|
||
}
|
||
|
||
flRed = pulColors[0];
|
||
flGre = pulColors[1];
|
||
flBlu = pulColors[2];
|
||
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BITFIELDS;
|
||
iPalType = PAL_FIXED;
|
||
dbmi.cjBits = ((((uiBitCount * uiWidth) + 31) >> 5) << 2) * cNumScan;
|
||
}
|
||
else if (uiCompression == BI_RGB)
|
||
{
|
||
switch (uiBitCount)
|
||
{
|
||
case 1:
|
||
dbmi.iFormat = BMF_1BPP;
|
||
cColorsMax = 2;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 4:
|
||
dbmi.iFormat = BMF_4BPP;
|
||
cColorsMax = 16;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 8:
|
||
dbmi.iFormat = BMF_8BPP;
|
||
cColorsMax = 256;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
default:
|
||
|
||
if (iUsage == DIB_PAL_COLORS)
|
||
{
|
||
iUsage = DIB_RGB_COLORS;
|
||
}
|
||
|
||
cColorsMax = 0;
|
||
iPalType = PAL_FIXED;
|
||
|
||
switch (uiBitCount)
|
||
{
|
||
case 16:
|
||
dbmi.iFormat = BMF_16BPP;
|
||
flRed = 0x7c00;
|
||
flGre = 0x03e0;
|
||
flBlu = 0x001f;
|
||
iPalMode = PAL_BITFIELDS;
|
||
break;
|
||
case 24:
|
||
dbmi.iFormat = BMF_24BPP;
|
||
iPalMode = PAL_BGR;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
iPalMode = PAL_BGR;
|
||
break;
|
||
default:
|
||
WARNING1("SetDIBitsToDevice failed invalid bitcount in bmi BI_RGB\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
dbmi.cjBits = ((((uiBitCount * uiWidth) + 31) >> 5) << 2) * cNumScan;
|
||
}
|
||
else if (uiCompression == BI_CMYK)
|
||
{
|
||
ASSERTGDI(iUsage == DIB_RGB_COLORS,
|
||
"SetDIBitsToDevice(BI_CMYK):iUsage should be DIB_RGB_COLORS\n");
|
||
|
||
DCOBJ dcoDest(hdcDest);
|
||
|
||
//
|
||
// Current device context accept CMYK color ?
|
||
//
|
||
if (!dcoDest.bValid() || !dcoDest.pdc->bIsCMYKColor())
|
||
{
|
||
WARNING1("SetDIBitsToDevice:DC is not in CMYK color mode for BI_CMYK\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
switch (uiBitCount)
|
||
{
|
||
case 1:
|
||
dbmi.iFormat = BMF_1BPP;
|
||
cColorsMax = 2;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 4:
|
||
dbmi.iFormat = BMF_4BPP;
|
||
cColorsMax = 16;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 8:
|
||
dbmi.iFormat = BMF_8BPP;
|
||
cColorsMax = 256;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_CMYK;
|
||
iPalType = PAL_FIXED;
|
||
break;
|
||
default:
|
||
WARNING1("SetDIBitsToDevice failed invalid bitcount in bmi BI_CMYK\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
dbmi.cjBits = ((((uiBitCount * uiWidth) + 31) >> 5) << 2) * cNumScan;
|
||
}
|
||
else if ((uiCompression == BI_RLE4) || (uiCompression == BI_CMYKRLE4))
|
||
{
|
||
if (uiCompression == BI_CMYKRLE4)
|
||
{
|
||
ASSERTGDI(iUsage == DIB_RGB_COLORS,
|
||
"SetDIBitsToDevice(BI_CMYKRLE4):iUsage should be DIB_RGB_COLORS\n");
|
||
|
||
DCOBJ dcoDest(hdcDest);
|
||
|
||
//
|
||
// Current device context accept CMYK color ?
|
||
//
|
||
if (!dcoDest.bValid() || !dcoDest.pdc->bIsCMYKColor())
|
||
{
|
||
WARNING1("SetDIBitsToDevice:DC is not in CMYK color mode for BI_CMYKRLE4\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
if (uiBitCount != 4)
|
||
{
|
||
WARNING1("SetDIBitsToDevice invalid bitcount BI_RLE4\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
dbmi.iFormat = BMF_4RLE;
|
||
cColorsMax = 16;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
iStartScan = 0;
|
||
cNumScan = lHeight;
|
||
dbmi.cjBits = pInfoHeader->bmiHeader.biSizeImage;
|
||
bRLE = TRUE;
|
||
}
|
||
else if ((uiCompression == BI_RLE8) || (uiCompression == BI_CMYKRLE8))
|
||
{
|
||
if (uiCompression == BI_CMYKRLE8)
|
||
{
|
||
ASSERTGDI(iUsage == DIB_RGB_COLORS,
|
||
"SetDIBitsToDevice(BI_CMYKRLE8):iUsage should be DIB_RGB_COLORS\n");
|
||
|
||
DCOBJ dcoDest(hdcDest);
|
||
|
||
//
|
||
// Current dc context accept CMYK color ?
|
||
//
|
||
if (!dcoDest.bValid() || !dcoDest.pdc->bIsCMYKColor())
|
||
{
|
||
WARNING1("SetDIBitsToDevice:DC is not in CMYK color mode for BI_CMYKRLE8\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
if (uiBitCount != 8)
|
||
{
|
||
WARNING1("SetDIBitsToDevice invalid bitcount BI_RLE8\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
dbmi.iFormat = BMF_8RLE;
|
||
cColorsMax = 256;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
iStartScan = 0;
|
||
cNumScan = lHeight;
|
||
dbmi.cjBits = pInfoHeader->bmiHeader.biSizeImage;
|
||
bRLE = TRUE;
|
||
}
|
||
else if (uiCompression == BI_JPEG)
|
||
{
|
||
//
|
||
// The XLATEOBJ we setup for BI_JPEG is only valid for
|
||
// querying the ICM flags in the flXlate member.
|
||
//
|
||
|
||
dbmi.iFormat = BMF_JPEG;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BGR;
|
||
iPalType = PAL_FIXED;
|
||
iStartScan = 0;
|
||
//cNumScan = lHeight;
|
||
dbmi.cjBits = pInfoHeader->bmiHeader.biSizeImage;
|
||
}
|
||
else if (uiCompression == BI_PNG)
|
||
{
|
||
//
|
||
// The XLATEOBJ we setup for BI_PNG is only valid for
|
||
// querying the ICM flags in the flXlate member.
|
||
//
|
||
|
||
dbmi.iFormat = BMF_PNG;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BGR;
|
||
iPalType = PAL_FIXED;
|
||
iStartScan = 0;
|
||
//cNumScan = lHeight;
|
||
dbmi.cjBits = pInfoHeader->bmiHeader.biSizeImage;
|
||
}
|
||
else
|
||
{
|
||
WARNING1("GreSetDIBitsToDevice failed invalid Compression in header\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
ULONG cColors;
|
||
|
||
if (uiPalUsed != 0)
|
||
{
|
||
if (uiPalUsed <= cColorsMax)
|
||
{
|
||
cColors = uiPalUsed;
|
||
}
|
||
else
|
||
{
|
||
cColors = cColorsMax;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
cColors = cColorsMax;
|
||
}
|
||
|
||
if (cjMaxBits < dbmi.cjBits)
|
||
{
|
||
WARNING1("GreSetDIBitsToDevice failed because of invalid cjMaxBits\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
dbmi.cxBitmap = uiWidth;
|
||
dbmi.cyBitmap = (IS_PASSTHROUGH_IMAGE(uiCompression)) ? lHeight
|
||
: cNumScan;
|
||
|
||
//
|
||
// Lock the destination DC.
|
||
//
|
||
// This is our first constructor/destructor so from here on out
|
||
// we need to minimize the number of returns. Each return generates
|
||
// a bunch of destructors, bloating the code size.
|
||
//
|
||
|
||
DCOBJ dcoDest(hdcDest);
|
||
|
||
if (dcoDest.bValid())
|
||
{
|
||
PDEVOBJ po(dcoDest.hdev());
|
||
|
||
EPOINTL eptlDst(xDst,yDst);
|
||
|
||
//
|
||
// Check for state incompatible with BI_JPEG or BI_PNG support.
|
||
//
|
||
|
||
if (IS_PASSTHROUGH_IMAGE(pInfoHeader->bmiHeader.biCompression))
|
||
{
|
||
//
|
||
// Device must support image format
|
||
// No rotations allowed (checked below)
|
||
// DIB_RGB_COLORS only
|
||
// No hcmXform
|
||
//
|
||
|
||
if (!dcoDest.bSupportsPassthroughImage(pInfoHeader->bmiHeader.biCompression) ||
|
||
(iUsage != DIB_RGB_COLORS) || hcmXform)
|
||
{
|
||
//
|
||
// Return 0 for error.
|
||
//
|
||
|
||
WARNING("SetDIBitsToDevice -- invalid BI_JPEG/BI_PNG operation\n");
|
||
cNumScan = 0;
|
||
}
|
||
}
|
||
|
||
if (bTransformCoordinates)
|
||
{
|
||
EXFORMOBJ xoDest(dcoDest, WORLD_TO_DEVICE);
|
||
|
||
//
|
||
// Transform the dest point to DEVICE coordinates.
|
||
//
|
||
|
||
xoDest.bXform(eptlDst);
|
||
|
||
//
|
||
// Check for state incompatible with BI_JPEG or BI_PNG support.
|
||
//
|
||
|
||
if (cNumScan &&
|
||
IS_PASSTHROUGH_IMAGE(pInfoHeader->bmiHeader.biCompression))
|
||
{
|
||
//
|
||
// No rotations allowed
|
||
//
|
||
|
||
if (xoDest.bRotation())
|
||
{
|
||
//
|
||
// Return 0 for error.
|
||
//
|
||
|
||
WARNING("SetDIBitsToDevice -- invalid BI_JPEG/BI_PNG operation\n");
|
||
cNumScan = 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Make the rectangle well ordered.
|
||
//
|
||
|
||
ERECTL erclDest(eptlDst.x, eptlDst.y, eptlDst.x + cx, eptlDst.y + cy);
|
||
erclDest.vOrder();
|
||
|
||
if (!erclDest.bEmpty() && cNumScan)
|
||
{
|
||
//
|
||
// Accumulate bounds. We can do this before knowing if the operation is
|
||
// successful because bounds can be loose.
|
||
//
|
||
|
||
if (dcoDest.fjAccum())
|
||
{
|
||
dcoDest.vAccumulate(erclDest);
|
||
}
|
||
|
||
//
|
||
// Lock the Rao region if we are drawing on a display surface. The Rao
|
||
// region might otherwise change asynchronously. The DEVLOCKOBJ also makes
|
||
// sure that the VisRgn is up to date, calling the window manager if
|
||
// necessary to recompute it. It also protects us from having the
|
||
// surface change asynchronously by a dynamic mode change.
|
||
//
|
||
|
||
DEVLOCKOBJ dlo(dcoDest);
|
||
|
||
SURFACE *pSurfDest = dcoDest.pSurface();
|
||
|
||
//
|
||
// Return null operations.
|
||
//
|
||
|
||
if (pSurfDest != NULL)
|
||
{
|
||
//
|
||
// if color transform is not specified, use DC's color transform.
|
||
//
|
||
if (hcmXform == NULL)
|
||
{
|
||
hcmXform = dcoDest.pdc->hcmXform();
|
||
}
|
||
else
|
||
{
|
||
ICMMSG(("GreSetDIBitsToDeviceInternal():Bitmap has thier own colorspace\n"));
|
||
}
|
||
|
||
ULONG lIcmMode = dcoDest.pdc->lIcmMode();
|
||
|
||
if (IS_CMYK_COLOR(lIcmMode)) /* DC is CMYK color mode ? */
|
||
{
|
||
if ((hcmXform == NULL) || !IS_CMYK_BITMAP(uiCompression))
|
||
{
|
||
//
|
||
// DC mode is CMYK color, but bitmap itself is not.
|
||
// so clear CMYK color bit, so that XLATEOBJ will not
|
||
// have XO_FROM_CMYK
|
||
//
|
||
CLEAR_COLORTYPE(lIcmMode);
|
||
//
|
||
// then it's RGB.
|
||
//
|
||
lIcmMode |= DC_ICM_RGB_COLOR;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Allocate a palette for this bitmap
|
||
//
|
||
|
||
PALMEMOBJ palTemp;
|
||
XEPALOBJ palDest(pSurfDest->ppal());
|
||
XEPALOBJ palDestDC(dcoDest.ppal());
|
||
|
||
//
|
||
// Associate the DC's palette with the bitmap for use when
|
||
// converting DDBs to DIBs for dynamic mode changes.
|
||
//
|
||
|
||
if (!palDestDC.bIsPalDefault())
|
||
{
|
||
pSurfDest->hpalHint(palDestDC.hpal());
|
||
}
|
||
|
||
//
|
||
// bSuccess gets set to FALSE only if the following switch
|
||
// executes with error. We do this to avoid doing a
|
||
// return from the switch statement.
|
||
//
|
||
|
||
BOOL bSuccess = TRUE;
|
||
BOOL bNeedAssociatePalette = FALSE;
|
||
XLATEOBJ *pxlo;
|
||
EXLATEOBJ xlo;
|
||
|
||
switch (iUsage)
|
||
{
|
||
case DIB_RGB_COLORS:
|
||
|
||
if (palTemp.bCreatePalette(iPalMode, cColorsMax, (PULONG) NULL,
|
||
flRed, flGre, flBlu, iPalType))
|
||
{
|
||
if (cColors)
|
||
{
|
||
if (cjMaxInfo < (cColors * 4))
|
||
{
|
||
WARNING1("SetDIBitsToDevice failed DIB_RGB_COLORS bmi invalid size\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Copy bitmap color table into palette
|
||
//
|
||
|
||
if (IS_CMYK_BITMAP(uiCompression))
|
||
{
|
||
palTemp.vCopy_cmykquad(pulColors, 0, cColors);
|
||
}
|
||
else
|
||
{
|
||
palTemp.vCopy_rgbquad((RGBQUAD *) pulColors, 0, cColors);
|
||
}
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
|
||
//
|
||
// This is a special version of the constructor that doesn't search the
|
||
// cache and doesn't put it in the cache when it's done.
|
||
//
|
||
|
||
if (xlo.pInitXlateNoCache(
|
||
hcmXform,
|
||
lIcmMode,
|
||
palTemp,
|
||
palDest,
|
||
palDestDC,
|
||
0,
|
||
0,
|
||
0x00FFFFFF
|
||
)
|
||
)
|
||
{
|
||
pxlo = xlo.pxlo();
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Error is logged by bMakeXlate.
|
||
//
|
||
|
||
WARNING1("GreSetDIBitsToDevice failed XLATE init because of low memory\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// This is a special version of the constructor that doesn't search the
|
||
// cache and doesn't put it in the cache when it's done.
|
||
//
|
||
|
||
if (bSuccess)
|
||
{
|
||
if (xlo.pInitXlateNoCache(
|
||
hcmXform,
|
||
lIcmMode,
|
||
palTemp,
|
||
palDest,
|
||
palDestDC,
|
||
0,
|
||
0,
|
||
0x00FFFFFF
|
||
)
|
||
)
|
||
{
|
||
pxlo = xlo.pxlo();
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Error is logged by bMakeXlate.
|
||
//
|
||
|
||
WARNING1("GreSetDIBitsToDevice failed XLATE init because of low memory\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
WARNING1("Failed palette creation in SetDIBitsToDevice\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
break;
|
||
|
||
case DIB_PAL_COLORS:
|
||
|
||
if (cjMaxInfo < (cColors * sizeof(USHORT)))
|
||
{
|
||
WARNING1("SetDIBitsToDevice failed DIB_PAL_COLORS is invalid\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
if (!xlo.bMakeXlate((PUSHORT) pulColors, palDestDC, pSurfDest, cColors, cColorsMax))
|
||
{
|
||
WARNING1("GDISRV GreSetDIBitsToDevice failed bMakeXlate\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
pxlo = xlo.pxlo();
|
||
|
||
//
|
||
// If we are drawing to display meta-screen with multi-monitor system
|
||
// and it's colour-depth is not same for all those monitor.
|
||
// we need to create palette to map color to other-than primary
|
||
// monitor(s).
|
||
//
|
||
|
||
if (gbMultiMonMismatchColor && po.bDisplayPDEV())
|
||
{
|
||
if (palTemp.bCreatePalette(iPalMode, cColorsMax, (PULONG) NULL,
|
||
flRed, flGre, flBlu, iPalType))
|
||
{
|
||
XEPALOBJ palSurfEff(pSurfDest->ppal() ? pSurfDest->ppal() : po.ppalSurf());
|
||
|
||
//
|
||
// Keep DC (or Surface) palette entry to temporay palette.
|
||
//
|
||
|
||
palTemp.vGetEntriesFrom(palDestDC, palSurfEff, (PUSHORT)pulColors, cColors);
|
||
bNeedAssociatePalette = TRUE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case DIB_PAL_INDICES:
|
||
|
||
ULONG iFormatDC = pSurfDest->iFormat();
|
||
|
||
if ((iFormatDC == dbmi.iFormat) ||
|
||
((iFormatDC == BMF_4BPP) && (dbmi.iFormat == BMF_4RLE)) ||
|
||
((iFormatDC == BMF_8BPP) && (dbmi.iFormat == BMF_8RLE)))
|
||
{
|
||
pxlo = &xloIdent;
|
||
}
|
||
else
|
||
{
|
||
WARNING1("SetDIBitsToDevice failed - DIB_PAL_INDICES used - DIB not format of Dst\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Attempt to allocate the bitmap from handle manager.
|
||
//
|
||
|
||
SURFMEM SurfDimoTemp;
|
||
SurfDimoTemp.bCreateDIB(&dbmi, (PVOID) pInitBits);
|
||
|
||
if (bSuccess && (SurfDimoTemp.bValid()))
|
||
{
|
||
//
|
||
// Bug #69739
|
||
//
|
||
// Set uniqueness to zero so that it will not be cached by
|
||
// a driver (NetMeeting for example) down below.
|
||
//
|
||
|
||
SurfDimoTemp.ps->iUniq(0);
|
||
|
||
if (dlo.bValid())
|
||
{
|
||
//
|
||
// With a fixed DC origin we can change the destination to SCREEN coordinates.
|
||
//
|
||
|
||
erclDest += dcoDest.eptlOrigin();
|
||
|
||
if (bNeedAssociatePalette)
|
||
{
|
||
ASSERTGDI(SurfDimoTemp.ps->ppal() == NULL,
|
||
"SetDIBitsToDevice():Surface has palette already\n");
|
||
|
||
SurfDimoTemp.ps->ppal(palTemp.ppalGet());
|
||
}
|
||
|
||
//
|
||
// Lock the dest ldev.
|
||
//
|
||
|
||
PDEVOBJ pdo(pSurfDest->hdev());
|
||
|
||
//
|
||
// Handle RLE bitmaps here. We don't need to adjust src origin or dst rect
|
||
// since we must enumerate through the entire RLE.
|
||
//
|
||
|
||
if (bRLE)
|
||
{
|
||
//
|
||
// Compute the clipping complexity and maybe reduce the exclusion rectangle.
|
||
//
|
||
|
||
EPOINTL eptlSrc;
|
||
|
||
eptlSrc.x = xSrc;
|
||
eptlSrc.y = lHeight - ySrc - cy;
|
||
|
||
ECLIPOBJ co(dcoDest.prgnEffRao(), erclDest);
|
||
|
||
//
|
||
// Check the destination which is reduced by clipping.
|
||
//
|
||
|
||
if (!co.erclExclude().bEmpty())
|
||
{
|
||
//
|
||
// Exclude the pointer.
|
||
//
|
||
|
||
DEVEXCLUDEOBJ dxo(dcoDest,&co.erclExclude(),&co);
|
||
|
||
//
|
||
// Inc the target surface uniqueness
|
||
//
|
||
|
||
INC_SURF_UNIQ(pSurfDest);
|
||
|
||
//
|
||
// Dispatch the call. Give it no mask.
|
||
//
|
||
|
||
(*PPFNGET(pdo,CopyBits,pSurfDest->flags()))
|
||
(
|
||
pSurfDest->pSurfobj(), // Destination surface.
|
||
SurfDimoTemp.pSurfobj(), // Source surface.
|
||
(CLIPOBJ *)&co, // Clip object.
|
||
pxlo, // Palette translation object.
|
||
(RECTL *) &erclDest, // Destination rectangle.
|
||
(POINTL *) &eptlSrc // Source origin.
|
||
);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Handle BitBlts that have a source. Create a rect bounding the
|
||
// src and the bits that have been supplied.
|
||
//
|
||
|
||
EPOINTL eptlSrc;
|
||
ERECTL erclReduced;
|
||
|
||
eptlSrc.x = xSrc;
|
||
erclReduced.left = 0;
|
||
erclReduced.right = uiWidth;
|
||
|
||
eptlSrc.y = lHeight - ySrc - cy;
|
||
|
||
//
|
||
// When we are here lHeight is positive. The destination dimensions are
|
||
// determined from the height, iStartScan, and cNumScan.
|
||
//
|
||
|
||
erclReduced.top = lHeight - (iStartScan + cNumScan);
|
||
erclReduced.bottom = lHeight - iStartScan;
|
||
|
||
EPOINTL eptlOffset;
|
||
eptlOffset.x = erclDest.left - eptlSrc.x;
|
||
eptlOffset.y = erclDest.top - eptlSrc.y;
|
||
|
||
//
|
||
// First make sure it doesn't go off the edge of the src bitmap if we had
|
||
// the whole thing.
|
||
//
|
||
|
||
erclReduced += eptlOffset;
|
||
erclReduced *= erclDest;
|
||
|
||
if (!erclReduced.bEmpty())
|
||
{
|
||
//
|
||
// Compute the clipping complexity and maybe reduce the exclusion rectangle.
|
||
//
|
||
|
||
ECLIPOBJ co(dcoDest.prgnEffRao(), erclReduced);
|
||
|
||
//
|
||
// Check the destination which is reduced by clipping.
|
||
//
|
||
|
||
if (!co.erclExclude().bEmpty())
|
||
{
|
||
erclReduced = co.erclExclude();
|
||
|
||
//
|
||
// Compute the (reduced) origin.
|
||
//
|
||
|
||
eptlSrc.x = erclReduced.left - eptlOffset.x;
|
||
eptlSrc.y = erclReduced.top - eptlOffset.y;
|
||
|
||
//
|
||
// Transform the source point to DEVICE coordinates of the bitmap we
|
||
// have allocated.
|
||
//
|
||
|
||
eptlSrc.y -= lHeight - (iStartScan + cNumScan);
|
||
|
||
//
|
||
// Exclude the pointer.
|
||
//
|
||
|
||
DEVEXCLUDEOBJ dxo(dcoDest,&erclReduced,&co);
|
||
|
||
//
|
||
// Inc the target surface uniqueness
|
||
//
|
||
|
||
INC_SURF_UNIQ(pSurfDest);
|
||
|
||
BOOL bRes = (*PPFNGET(pdo,CopyBits,pSurfDest->flags()))
|
||
(pSurfDest->pSurfobj(), // Destination surface.
|
||
SurfDimoTemp.pSurfobj(), // Source surface.
|
||
(CLIPOBJ *)&co, // Clip object.
|
||
pxlo, // Palette translation object.
|
||
(RECTL *) &erclReduced, // Destination rectangle.
|
||
(POINTL *) &eptlSrc // Source origin.
|
||
);
|
||
|
||
if (!bRes)
|
||
{
|
||
WARNING1("GreSetDIBitsToDevice failed DrvCopyBits\n");
|
||
cNumScan = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (bNeedAssociatePalette)
|
||
{
|
||
SurfDimoTemp.ps->ppal(NULL);
|
||
}
|
||
}
|
||
}
|
||
else // if (bSuccess && (SurfDimoTemp.bValid()))
|
||
{
|
||
#if DBG
|
||
if (bSuccess)
|
||
{
|
||
WARNING1("Some silly switch failure in SetDIBitsToDevice\n");
|
||
}
|
||
else
|
||
{
|
||
WARNING1("GreSetDIBitsToDevice failed to allocate temporary bitmap\n");
|
||
}
|
||
#endif
|
||
cNumScan = 0;
|
||
}
|
||
}
|
||
else // if (pSurfDest != NULL)
|
||
{
|
||
WARNING1("SetDIBitsToDevice failed - pSurfDst == NULL\n");
|
||
}
|
||
}
|
||
else // if (!erclDest.bEmpty())
|
||
{
|
||
WARNING1("SetDIBitsToDevice failed - empty dst rect\n");
|
||
}
|
||
|
||
}
|
||
else // if (!dcoDest.bValid())
|
||
{
|
||
WARNING1("GreSetDIBitsToDevice failed because of invalid hdc parameter\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
cNumScan = 0;
|
||
}
|
||
|
||
return(cNumScan);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* BOOL bIdenticalFormat
|
||
*
|
||
* checks if the Source surface pal format is the same as the DIB pal format
|
||
* when DIB format is BI_RGB
|
||
*
|
||
* History:
|
||
* 3-Nov-1995 -by- Lingyun Wang [lingyunw]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
BOOL bIdenticalFormat (XEPALOBJ palSrc, INT iFormat)
|
||
{
|
||
FLONG flRedSrc, flGreSrc, flBluSrc;
|
||
FLONG flRedDst, flGreDst, flBluDst;
|
||
BOOL bRet = TRUE;
|
||
|
||
if (palSrc.bIsBitfields())
|
||
{
|
||
flRedSrc = palSrc.flRed();
|
||
flGreSrc = palSrc.flGre();
|
||
flBluSrc = palSrc.flBlu();
|
||
}
|
||
else
|
||
//
|
||
// RGB, BGR
|
||
//
|
||
{
|
||
ASSERTGDI (iFormat == BMF_32BPP, "bIdenticalFormat-16bpp non bitfield surf?\n");
|
||
|
||
flGreSrc = 0x0000FF00;
|
||
|
||
if (palSrc.bIsRGB())
|
||
{
|
||
flRedSrc = 0x000000FF;
|
||
flBluSrc = 0x00FF0000;
|
||
}
|
||
else
|
||
{
|
||
ASSERTGDI(palSrc.bIsBGR(), "What is it then?");
|
||
flRedSrc = 0x00FF0000;
|
||
flBluSrc = 0x000000FF;
|
||
}
|
||
}
|
||
|
||
|
||
if (iFormat == BMF_16BPP)
|
||
{
|
||
flRedDst = 0x7c00;
|
||
flGreDst = 0x03e0;
|
||
flBluDst = 0x001f;
|
||
}
|
||
//
|
||
// BMF_32BPP
|
||
//
|
||
else
|
||
{
|
||
flRedDst = 0x00FF0000;
|
||
flGreDst = 0x0000FF00;
|
||
flBluDst = 0x000000FF;
|
||
}
|
||
|
||
if ((flRedSrc != flRedDst) ||
|
||
(flGreSrc != flGreDst) ||
|
||
(flBluSrc != flBluDst))
|
||
{
|
||
bRet = FALSE;
|
||
}
|
||
|
||
return (bRet);
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreGetDIBits
|
||
*
|
||
* API entry point geting the DIB bits out of a bitmap.
|
||
*
|
||
* If they ask for the bits in the same format as they are stored
|
||
* internally we give them the exact same palette entries and bits.
|
||
* If they ask for a format NBPP different than they are internally
|
||
* stored we :
|
||
*
|
||
* for 1BPP give them black,white and blt to it.
|
||
* for 4BPP give them VGA colors and blt to it.
|
||
* for 8BPP give them a good spread of colors and blt to it.
|
||
* for 16BPP give them 5-5-5
|
||
* for 24BPP give them RGB.
|
||
* for 32BPP give them RGB.
|
||
*
|
||
* Arguments:
|
||
*
|
||
* hdc - handle of device context
|
||
* hBitmap - handle of bitmap
|
||
* iStartScan - first scan line to set in destination bitmap
|
||
* cNumScan - number of scan lines to copy
|
||
* pjBits - address of array for bitmap bits
|
||
* pBitsInfo - address of structure with bitmap data
|
||
* iUsage - RGB or palette index
|
||
* cjMaxBits - Maximum for pjBits
|
||
* cjMaxInfo - Maximum for pBitsInfo
|
||
*
|
||
* Returns:
|
||
*
|
||
* Number of scan lines copied, 0 for failure
|
||
*
|
||
*
|
||
* History:
|
||
* 12-Mar-1991 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
int
|
||
APIENTRY
|
||
GreGetDIBitsInternal(
|
||
HDC hdc,
|
||
HBITMAP hBitmap,
|
||
UINT iStartScan,
|
||
UINT cNumScan,
|
||
LPBYTE pjBits,
|
||
LPBITMAPINFO pBitsInfo,
|
||
UINT iUsage,
|
||
UINT cjMaxBits,
|
||
UINT cjMaxInfo)
|
||
{
|
||
//
|
||
// Let's make sure we are given valid input.
|
||
//
|
||
|
||
if (pBitsInfo == (LPBITMAPINFO) NULL)
|
||
{
|
||
WARNING1("GreGetDIBits failed with NULL BITMAPINFO parameter\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
switch(iUsage)
|
||
{
|
||
case DIB_PAL_INDICES:
|
||
case DIB_PAL_COLORS:
|
||
case DIB_RGB_COLORS:
|
||
break;
|
||
default:
|
||
|
||
WARNING1("GreGetDIBits failed with invalid DIB_ iUsage type\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// check to make sure that at least the minimum sized header will fit
|
||
//
|
||
|
||
if (cjMaxInfo < sizeof(BITMAPCOREHEADER))
|
||
{
|
||
WARNING1("GreGetDIBits failed cjMaxInfo\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// Because of CS we must set pjBits to NULL if it should be NULL
|
||
// This is indicated by cNumScan being 0.
|
||
//
|
||
|
||
if (cNumScan == 0)
|
||
{
|
||
pjBits = (PBYTE) NULL;
|
||
}
|
||
|
||
//
|
||
// Validate the bitmap.
|
||
//
|
||
|
||
SURFREF SurfBM((HSURF)hBitmap);
|
||
|
||
if (!SurfBM.bValid())
|
||
{
|
||
WARNING1("GreGetDIBits failed to lock down the bitmap\n");
|
||
return(0);
|
||
}
|
||
|
||
ULONG ulSize = pBitsInfo->bmiHeader.biSize;
|
||
|
||
//
|
||
// First check if they just want us to fill in the bmiinfo, no color
|
||
// table, no bits. This is indicated by NULL bits and 0 for bitcount.
|
||
//
|
||
|
||
if (pjBits == (PBYTE) NULL)
|
||
{
|
||
if (ulSize == sizeof(BITMAPCOREHEADER))
|
||
{
|
||
//
|
||
// If bitcount is 0 they want to know what we have.
|
||
//
|
||
|
||
if (((LPBITMAPCOREINFO) pBitsInfo)->bmciHeader.bcBitCount == 0)
|
||
{
|
||
((LPBITMAPCOREINFO) pBitsInfo)->bmciHeader.bcWidth = (USHORT) SurfBM.ps->sizl().cx;
|
||
|
||
((LPBITMAPCOREINFO) pBitsInfo)->bmciHeader.bcHeight = (USHORT) SurfBM.ps->sizl().cy;
|
||
((LPBITMAPCOREINFO) pBitsInfo)->bmciHeader.bcPlanes = 1;
|
||
((LPBITMAPCOREINFO) pBitsInfo)->bmciHeader.bcBitCount = (USHORT) gaulConvert[SurfBM.ps->iFormat()];
|
||
|
||
//
|
||
// the core header does not support 16/32 bpp bitmaps
|
||
//
|
||
|
||
if (((LPBITMAPCOREINFO) pBitsInfo)->bmciHeader.bcBitCount >= 16)
|
||
{
|
||
((LPBITMAPCOREINFO) pBitsInfo)->bmciHeader.bcBitCount = 24;
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (cjMaxInfo < sizeof(BITMAPINFOHEADER))
|
||
return(0);
|
||
|
||
//
|
||
// If bitcount is 0 they want to know what we have.
|
||
//
|
||
|
||
if (pBitsInfo->bmiHeader.biBitCount == 0)
|
||
{
|
||
//
|
||
// zero out extra fields that are not going to be filled up later
|
||
//
|
||
if (ulSize > sizeof(BITMAPINFOHEADER))
|
||
RtlZeroMemory((PVOID)pBitsInfo, ulSize);
|
||
|
||
pBitsInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
pBitsInfo->bmiHeader.biWidth = SurfBM.ps->sizl().cx;
|
||
pBitsInfo->bmiHeader.biHeight = SurfBM.ps->sizl().cy;
|
||
|
||
pBitsInfo->bmiHeader.biPlanes = 1;
|
||
pBitsInfo->bmiHeader.biCompression = BI_RGB;
|
||
pBitsInfo->bmiHeader.biBitCount = (USHORT) gaulConvert[SurfBM.ps->iFormat()];
|
||
|
||
//
|
||
// If it is a 16 bpp or 32 bpp bitmap, set the compression field
|
||
//
|
||
|
||
if ((pBitsInfo->bmiHeader.biBitCount == 16) ||
|
||
(pBitsInfo->bmiHeader.biBitCount == 32))
|
||
{
|
||
pBitsInfo->bmiHeader.biCompression = BI_BITFIELDS;
|
||
}
|
||
|
||
pBitsInfo->bmiHeader.biSizeImage = pBitsInfo->bmiHeader.biHeight *
|
||
((((pBitsInfo->bmiHeader.biBitCount * pBitsInfo->bmiHeader.biWidth)
|
||
+ 31) >> 5) << 2);
|
||
pBitsInfo->bmiHeader.biXPelsPerMeter = 0;
|
||
pBitsInfo->bmiHeader.biYPelsPerMeter = 0;
|
||
pBitsInfo->bmiHeader.biClrUsed =
|
||
pBitsInfo->bmiHeader.biClrImportant = gacPalEntries[SurfBM.ps->iFormat()];
|
||
|
||
//
|
||
// top down -vs- bottom up
|
||
// We need to put this at the end because we use the positive
|
||
// height to compute the size (above).
|
||
//
|
||
// On Win95/98, negative height is returned if it's top-down
|
||
// DIBSECTION. #196691 [lingyunw]
|
||
//
|
||
// We should flip the height here, but too much stuff already
|
||
// depends on the bad NT4 compatible behaviour of this code.
|
||
// Win9x has fixed this, so we should return and fix this in
|
||
// a later release.
|
||
//
|
||
//if ((SurfBM.ps->bDIBSection()||SurfBM.ps->bDirectDraw()) &&
|
||
// (SurfBM.ps->fjBitmap() & BMF_TOPDOWN))
|
||
//{
|
||
// pBitsInfo->bmiHeader.biHeight = -pBitsInfo->bmiHeader.biHeight;
|
||
//}
|
||
//
|
||
|
||
return(TRUE);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Ok they want us to pay attention to what is in the bmBitmapInfo.
|
||
//
|
||
|
||
//
|
||
// Cannot support the device passthrough formats (BI_JPEG, BI_PNG).
|
||
//
|
||
|
||
if (IS_BMI_PASSTHROUGH_IMAGE(pBitsInfo))
|
||
{
|
||
WARNING1("GreGetDIBits failed -- invalid pBitsInfo (BITMAPINFOHEADER)\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
DCOBJ dco(hdc);
|
||
|
||
if (!dco.bValid())
|
||
{
|
||
WARNING1("GreGetDIBits failed because invalid hdc\n");
|
||
return(0);
|
||
}
|
||
|
||
PDEVOBJ po(dco.hdev());
|
||
ASSERTGDI(po.bValid(), "ERROR po is invalid");
|
||
|
||
XEPALOBJ palDC(dco.ppal());
|
||
ASSERTGDI(palDC.bValid(), "ERROR palDC is invalid");
|
||
|
||
//
|
||
// Acquire the devlock here to protect against dynamic mode changes
|
||
// that affect the device palette. This also protects us if the
|
||
// bitmap is a Device Format Bitmap that is owned by the display
|
||
// driver.
|
||
//
|
||
|
||
DEVLOCKOBJ dlo(po);
|
||
|
||
PPALETTE ppalSrc;
|
||
|
||
if (!bIsCompatible(&ppalSrc, SurfBM.ps->ppal(), SurfBM.ps, dco.hdev()))
|
||
{
|
||
WARNING1("GreGetDIBits failed - bitmap not compatible with surface\n");
|
||
return(0);
|
||
}
|
||
|
||
XEPALOBJ palBM(ppalSrc);
|
||
PUSHORT pusIndices;
|
||
BOOL bCoreInfo;
|
||
DEVBITMAPINFO dbmi;
|
||
|
||
dbmi.fl = 0;
|
||
|
||
UINT uiWidth, uiHeight, uiBitCount, uiSizeScan, uiCompression;
|
||
|
||
if (ulSize == sizeof(BITMAPCOREHEADER))
|
||
{
|
||
bCoreInfo = TRUE;
|
||
pusIndices = (PUSHORT) ((LPBITMAPCOREINFO) pBitsInfo)->bmciColors;
|
||
uiWidth = (UINT) ((LPBITMAPCOREINFO) pBitsInfo)->bmciHeader.bcWidth;
|
||
uiHeight = (UINT) ((LPBITMAPCOREINFO) pBitsInfo)->bmciHeader.bcHeight;
|
||
((LPBITMAPCOREINFO) pBitsInfo)->bmciHeader.bcPlanes = 1;
|
||
uiBitCount = (UINT) ((LPBITMAPCOREINFO) pBitsInfo)->bmciHeader.bcBitCount;
|
||
uiSizeScan = ((((uiBitCount * uiWidth) + 31) >> 5) << 2);
|
||
uiCompression = BI_RGB;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// make sure the header is large enough for a full INFOHEADER
|
||
//
|
||
|
||
if (cjMaxInfo < sizeof(BITMAPINFOHEADER))
|
||
{
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// zero out extra fields
|
||
//
|
||
if (ulSize > sizeof(BITMAPINFOHEADER))
|
||
{
|
||
RtlZeroMemory((PVOID)((BYTE *)pBitsInfo+sizeof(BITMAPINFOHEADER)),
|
||
ulSize-sizeof(BITMAPINFOHEADER));
|
||
}
|
||
|
||
//
|
||
// First fill in bmiHeader
|
||
//
|
||
bCoreInfo = FALSE;
|
||
pusIndices = (PUSHORT) (pBitsInfo->bmiColors);
|
||
pBitsInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
pBitsInfo->bmiHeader.biPlanes = 1;
|
||
uiBitCount = (UINT) pBitsInfo->bmiHeader.biBitCount;
|
||
uiCompression = pBitsInfo->bmiHeader.biCompression;
|
||
uiWidth = (UINT) pBitsInfo->bmiHeader.biWidth;
|
||
|
||
if (pBitsInfo->bmiHeader.biHeight < 0)
|
||
{
|
||
dbmi.fl = BMF_TOPDOWN;
|
||
|
||
if ((uiCompression != BI_RGB) && (uiCompression != BI_BITFIELDS))
|
||
{
|
||
WARNING1("GreGetDIBits: TOP_DOWN RLE not allowed\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return (0);
|
||
}
|
||
|
||
uiHeight = (UINT) -pBitsInfo->bmiHeader.biHeight;
|
||
}
|
||
else
|
||
{
|
||
uiHeight = (UINT) pBitsInfo->bmiHeader.biHeight;
|
||
}
|
||
|
||
//
|
||
// Get a valid compression set in.
|
||
//
|
||
|
||
if (uiCompression == BI_BITFIELDS)
|
||
{
|
||
//
|
||
// We only give BI_BITFIELDS if they want 16 or 32 bpp.
|
||
//
|
||
|
||
if ((uiBitCount != 16) &&
|
||
(uiBitCount != 32))
|
||
{
|
||
uiCompression = pBitsInfo->bmiHeader.biCompression = BI_RGB;
|
||
}
|
||
}
|
||
else if (uiCompression == BI_RLE8)
|
||
{
|
||
//
|
||
// We only give BI_RLE8 if they want 8 bpp data.
|
||
//
|
||
|
||
if (uiBitCount != 8)
|
||
{
|
||
uiCompression = pBitsInfo->bmiHeader.biCompression = BI_RGB;
|
||
}
|
||
}
|
||
else if (uiCompression == BI_RLE4)
|
||
{
|
||
//
|
||
// We only give BI_RLE4 if they want 4 bpp data.
|
||
//
|
||
|
||
if (uiBitCount != 4)
|
||
{
|
||
uiCompression = pBitsInfo->bmiHeader.biCompression = BI_RGB;
|
||
}
|
||
}
|
||
else if (uiCompression == BI_CMYK)
|
||
{
|
||
//
|
||
// We will give BI_CMYK, if dc allowed.
|
||
//
|
||
if (dco.pdc->bIsCMYKColor())
|
||
{
|
||
uiCompression = pBitsInfo->bmiHeader.biCompression = BI_CMYK;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We give them BI_RGB.
|
||
//
|
||
|
||
uiCompression = pBitsInfo->bmiHeader.biCompression = BI_RGB;
|
||
}
|
||
|
||
uiSizeScan = ((((uiBitCount * uiWidth) + 31) >> 5) << 2);
|
||
|
||
if ((uiCompression == BI_RGB) || (uiCompression == BI_BITFIELDS))
|
||
{
|
||
pBitsInfo->bmiHeader.biSizeImage = uiSizeScan * uiHeight;
|
||
}
|
||
|
||
pBitsInfo->bmiHeader.biClrUsed = 0;
|
||
pBitsInfo->bmiHeader.biClrImportant = 0;
|
||
}
|
||
|
||
BOOL bRLE = (uiCompression == BI_RLE4) ||
|
||
(uiCompression == BI_RLE8);
|
||
|
||
//
|
||
// Get iStartScan and cNumScan in a valid range.
|
||
//
|
||
|
||
iStartScan = MIN(uiHeight, iStartScan);
|
||
cNumScan = MIN((uiHeight - iStartScan), cNumScan);
|
||
|
||
//
|
||
// check to see if all scans will fit in the passed buffer
|
||
//
|
||
|
||
if (!bRLE)
|
||
{
|
||
if (cjMaxBits < (uiSizeScan * cNumScan))
|
||
{
|
||
#if DBG
|
||
DbgPrint("ERROR GreGetDIBitsInternal %lu %lu %lu %lu %lu\n", cjMaxBits, uiSizeScan, cNumScan, iStartScan, uiHeight);
|
||
#endif
|
||
WARNING1("GreGetDIBits: cjMaxBits is to small\n");
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Find out what they are asking for
|
||
//
|
||
|
||
ULONG cColors;
|
||
dbmi.hpal = (HPALETTE) 0;
|
||
|
||
if (uiCompression == BI_BITFIELDS)
|
||
{
|
||
//
|
||
// Handle 16 and 32 bit per pel bitmaps.
|
||
//
|
||
|
||
if ((ulSize <= sizeof(BITMAPINFO)) && (cjMaxInfo < (sizeof(ULONG) * 3)))
|
||
{
|
||
WARNING1("GetDIBits 16/32bpp failed - not room for flags\n");
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
switch (uiBitCount)
|
||
{
|
||
case 1:
|
||
dbmi.iFormat = BMF_1BPP;
|
||
cColors = 2;
|
||
break;
|
||
case 4:
|
||
dbmi.iFormat = BMF_4BPP;
|
||
cColors = 16;
|
||
break;
|
||
case 8:
|
||
dbmi.iFormat = BMF_8BPP;
|
||
cColors = 256;
|
||
break;
|
||
default:
|
||
|
||
if (iUsage == DIB_PAL_COLORS)
|
||
{
|
||
iUsage = DIB_RGB_COLORS;
|
||
}
|
||
|
||
cColors = 0;
|
||
|
||
switch (uiBitCount)
|
||
{
|
||
case 16:
|
||
dbmi.iFormat = BMF_16BPP;
|
||
break;
|
||
case 24:
|
||
dbmi.iFormat = BMF_24BPP;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
break;
|
||
default:
|
||
WARNING1("GetDIBits failed invalid bitcount in bmi BI_RGB\n");
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Initialize a DIB and palette for them.
|
||
//
|
||
|
||
PALMEMOBJ palMem;
|
||
XEPALOBJ palTarg;
|
||
ULONG cEntryTemp;
|
||
|
||
if (iUsage == DIB_PAL_COLORS)
|
||
{
|
||
//
|
||
// We are guranteed to be getting for just the 1,4,8 BPP case here.
|
||
//
|
||
|
||
ASSERTGDI(palDC.cEntries() != 0, "Created 0 entry DC palette");
|
||
|
||
//
|
||
// Make sure the color table will fit in the BITMAPINFO
|
||
//
|
||
|
||
if (cjMaxInfo < (ulSize + cColors * sizeof(USHORT)))
|
||
{
|
||
WARNING1("GreGetDIBits: not enough memory for the color table DIB_PAL_COLORS\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// For a palette managed device we need to do special work
|
||
// to get the color table correct for 8bpp get. Grab sem
|
||
// so we can look at ptransFore.
|
||
//
|
||
|
||
SEMOBJ semo(ghsemPalette);
|
||
|
||
if ((!palBM.bValid()) && (dbmi.iFormat == BMF_8BPP) && (palDC.ptransFore() != NULL))
|
||
{
|
||
ASSERTGDI(po.bIsPalManaged(), "ERROR not palmanaged on invalid palbm");
|
||
|
||
palTarg.ppalSet(palBM.ppalGet());
|
||
|
||
//
|
||
// 0 it out like windows
|
||
//
|
||
|
||
for (cEntryTemp = 0; cEntryTemp < 256; cEntryTemp++)
|
||
{
|
||
pusIndices[cEntryTemp] = 0;
|
||
}
|
||
|
||
USHORT usTemp;
|
||
ASSERTGDI(palDC.cEntries() <= USHRT_MAX, "palDC.cEntries too large\n");
|
||
|
||
for (cEntryTemp = 0; cEntryTemp < 256; cEntryTemp++)
|
||
{
|
||
for (usTemp = 0; usTemp < (USHORT)palDC.cEntries(); usTemp++)
|
||
{
|
||
if (palDC.ptransFore()->ajVector[usTemp] == cEntryTemp)
|
||
{
|
||
pusIndices[cEntryTemp] = usTemp;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We need to create a palette to blt to.
|
||
//
|
||
|
||
if (!palMem.bCreatePalette(PAL_INDEXED, cColors,
|
||
(PULONG) NULL,
|
||
0, 0, 0, PAL_FIXED))
|
||
{
|
||
WARNING1("GetDIBits failed bCreatePalette for DIB_PAL_COLORS\n");
|
||
return(0);
|
||
}
|
||
|
||
palTarg.ppalSet(palMem.ppalGet());
|
||
|
||
//
|
||
// Initialize the pusIndices field.
|
||
//
|
||
|
||
for (cEntryTemp = 0; cEntryTemp < cColors; cEntryTemp++)
|
||
{
|
||
pusIndices[cEntryTemp] = (USHORT) cEntryTemp;
|
||
}
|
||
|
||
//
|
||
// We need to copy the RGB's in from the logical DC palette, reaching down when
|
||
// necessary.
|
||
//
|
||
|
||
XEPALOBJ palTemp(po.ppalSurf());
|
||
|
||
palTarg.vGetEntriesFrom(palDC, palBM.bValid() ? palBM : palTemp, pusIndices, cColors);
|
||
}
|
||
}
|
||
else if (iUsage == DIB_RGB_COLORS)
|
||
{
|
||
BOOL bCopyPal = FALSE;
|
||
|
||
if ((SurfBM.ps->iFormat() == dbmi.iFormat) && (palBM.bValid()))
|
||
{
|
||
bCopyPal = TRUE;
|
||
|
||
//
|
||
// for 16/32, do more checking
|
||
//
|
||
if ((uiCompression != BI_BITFIELDS) &&
|
||
((dbmi.iFormat == BMF_16BPP) || (dbmi.iFormat == BMF_32BPP)))
|
||
{
|
||
bCopyPal = bIdenticalFormat (palBM, dbmi.iFormat);
|
||
}
|
||
//
|
||
// for 24, check RGB order.
|
||
//
|
||
else if ((dbmi.iFormat == BMF_24BPP) && (palBM.bIsRGB()))
|
||
{
|
||
//
|
||
// Bitmap palette is PAL_RGB, but we need PAL_BGR.
|
||
//
|
||
bCopyPal = FALSE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// We can just use palBM, no temporary needed.
|
||
//
|
||
if (bCopyPal)
|
||
{
|
||
palTarg.ppalSet(palBM.ppalGet());
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// We need a temporary palette to fill in with the correct mix of colors and then to
|
||
// use in the xlateobj construction.
|
||
//
|
||
|
||
if (!palMem.bCreatePalette(cColors ? PAL_INDEXED :
|
||
((dbmi.iFormat == BMF_16BPP) ? PAL_BITFIELDS : PAL_BGR),
|
||
cColors,
|
||
(PULONG) NULL,
|
||
0x00007C00, 0x000003E0, 0x0000001F, PAL_FIXED))
|
||
{
|
||
WARNING1("GetDIBits failed bCreatePalette\n");
|
||
return(0);
|
||
}
|
||
|
||
palTarg.ppalSet(palMem.ppalGet());
|
||
|
||
|
||
if ((SurfBM.ps->iFormat() == dbmi.iFormat) && (dbmi.iFormat == BMF_8BPP))
|
||
{
|
||
//
|
||
// This is the 8BPP palette managed bitmap case. There is no palette and
|
||
// we need to construct the correct colors based on the DC's logical palette.
|
||
//
|
||
|
||
//
|
||
// We init the pusIndices to just point into the DC palette and then pull the
|
||
// RGB's out with the same logic we use in CreateDIBitmap. Then we fill the
|
||
// pusIndices with the correct RGB's.
|
||
//
|
||
// Initialize the pusIndices field.
|
||
//
|
||
|
||
for (cEntryTemp = 0; cEntryTemp < cColors; cEntryTemp++)
|
||
{
|
||
pusIndices[cEntryTemp] = (USHORT) cEntryTemp;
|
||
}
|
||
|
||
//
|
||
// Get the correct palette setup
|
||
//
|
||
|
||
XEPALOBJ palTemp(po.ppalSurf());
|
||
|
||
palTarg.vGetEntriesFrom(palDC, palTemp, pusIndices, cColors);
|
||
palTarg.vInit256Default();
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Fill in a general mix of colors. Don't use more colors
|
||
// than the source bitmap has.
|
||
//
|
||
// Actually use as many colors as the destination has. To be
|
||
// Compatible with Windows Millenium.
|
||
//
|
||
|
||
switch(dbmi.iFormat)
|
||
{
|
||
case BMF_1BPP:
|
||
|
||
palTarg.vInitMono();
|
||
break;
|
||
|
||
case BMF_4BPP:
|
||
|
||
palTarg.vInitVGA();
|
||
break;
|
||
|
||
case BMF_8BPP:
|
||
|
||
palTarg.vInit256Rainbow();
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// Fill in the color table.
|
||
//
|
||
|
||
if (bCoreInfo)
|
||
{
|
||
if (cjMaxInfo < (sizeof(BITMAPCOREHEADER) + cColors * 3))
|
||
{
|
||
WARNING1("GreGetDIBits: not enough memory for the color table2\n");
|
||
return(0);
|
||
}
|
||
|
||
if ((uiBitCount != 16) &&
|
||
(uiBitCount != 24) &&
|
||
(uiBitCount != 32))
|
||
{
|
||
//
|
||
// It's the 1,4,8 bpp case in which case we have to write
|
||
// out information.
|
||
//
|
||
|
||
palTarg.vFill_triples((RGBTRIPLE *) pusIndices,
|
||
0, cColors);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (uiCompression == BI_BITFIELDS)
|
||
{
|
||
// If uiCompression == BI_BITFIELDS we should have space for
|
||
// 3 DWORD color masks which will be filled in below. Do
|
||
// this only if we have enough space for 3 masks.
|
||
|
||
ASSERTGDI(cColors == 0,"GreGetDIBits: BI_BITFIELDS & cColors != 0\n");
|
||
if (cjMaxInfo >= sizeof(BITMAPINFOHEADER) + 3*sizeof(DWORD))
|
||
cColors = 3;
|
||
}
|
||
|
||
if (cjMaxInfo < (sizeof(BITMAPINFOHEADER) + cColors * 4))
|
||
{
|
||
WARNING1("GreGetDIBits: not enough memory for the color table33\n");
|
||
return(0);
|
||
}
|
||
|
||
if (palTarg.flPal() & PAL_BRUSHHACK)
|
||
{
|
||
RtlCopyMemory(pusIndices,(PUSHORT) palTarg.apalColorGet(),
|
||
cColors * sizeof(SHORT));
|
||
}
|
||
else if ((uiCompression == BI_BITFIELDS) ||
|
||
(uiBitCount == 1) ||
|
||
(uiBitCount == 4) ||
|
||
(uiBitCount == 8))
|
||
{
|
||
//
|
||
// We don't fill it in if it's BI_RGB and 16/24/32.
|
||
//
|
||
|
||
palTarg.vFill_rgbquads((RGBQUAD *) pusIndices,
|
||
0, cColors);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// This is the DIB_PAL_INDICES case
|
||
//
|
||
|
||
if (dbmi.iFormat != SurfBM.ps->iFormat())
|
||
{
|
||
WARNING1("GetDIBits failed DIB_PAL_INDICES - incompat DIB/bitmap format\n");
|
||
return(0);
|
||
}
|
||
|
||
palTarg.ppalSet(palBM.ppalGet());
|
||
}
|
||
|
||
//
|
||
// Now get the xlate ready.
|
||
//
|
||
|
||
XLATEOBJ *pxlo;
|
||
EXLATEOBJ xlo;
|
||
|
||
if (xlo.bInitXlateObj(
|
||
dco.pdc->hcmXform(),
|
||
dco.pdc->lIcmMode(),
|
||
palBM,
|
||
palTarg,
|
||
palDC,
|
||
palDC,
|
||
0,
|
||
0x00FFFFFF,
|
||
0))
|
||
{
|
||
pxlo = xlo.pxlo();
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// bInitXlateObj will log the correct error.
|
||
//
|
||
|
||
WARNING1("GreGetDIBits failed bInitXlateObj\n");
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// If they just want the color table leave now.
|
||
//
|
||
|
||
if ((pjBits == (PBYTE) NULL) &&
|
||
(!bRLE))
|
||
{
|
||
return(TRUE);
|
||
}
|
||
|
||
LPBYTE pjCompressionBits;
|
||
|
||
if (bRLE)
|
||
{
|
||
if (cNumScan == 0)
|
||
cNumScan = uiHeight;
|
||
|
||
pjCompressionBits = NULL;
|
||
}
|
||
else
|
||
{
|
||
pjCompressionBits = pjBits;
|
||
}
|
||
|
||
//
|
||
// Attempt to allocate the bitmap from handle manager.
|
||
//
|
||
|
||
dbmi.cxBitmap = uiWidth;
|
||
dbmi.cyBitmap = cNumScan;
|
||
|
||
//
|
||
// Create the dest surface.
|
||
//
|
||
|
||
SURFMEM SurfDimoTemp;
|
||
SurfDimoTemp.bCreateDIB(&dbmi, (PVOID) pjCompressionBits);
|
||
|
||
if (!SurfDimoTemp.bValid())
|
||
{
|
||
return(0);
|
||
}
|
||
|
||
ASSERTGDI((pjCompressionBits == NULL) ||
|
||
(pjCompressionBits == SurfDimoTemp.ps->pvBits()),
|
||
"ERROR compression invalid bits");
|
||
|
||
//
|
||
// For non-RLE the assignment below does nothing. For RLE we have
|
||
// it gets the pointer to the bits we allocated.
|
||
//
|
||
|
||
pjCompressionBits = (PBYTE) SurfDimoTemp.ps->pvBits();
|
||
|
||
SurfDimoTemp.ps->hdev(dco.hdev());
|
||
|
||
//
|
||
// Zero fill the memory allocated.
|
||
//
|
||
|
||
RtlZeroMemory(SurfDimoTemp.ps->pvBits(), (UINT) SurfDimoTemp.ps->cjBits());
|
||
|
||
//
|
||
// Fill in pjBits
|
||
//
|
||
|
||
ERECTL erclDest(0, 0, dbmi.cxBitmap, dbmi.cyBitmap);
|
||
EPOINTL eptlSrc(0, uiHeight -
|
||
(iStartScan + cNumScan));
|
||
|
||
//
|
||
// Compute the offset between source and dest, in screen coordinates.
|
||
//
|
||
|
||
EPOINTL eptlOffset;
|
||
ERECTL erclReduced;
|
||
|
||
eptlOffset.x = erclDest.left - eptlSrc.x; // == -eptlSrc
|
||
eptlOffset.y = erclDest.top - eptlSrc.y;
|
||
|
||
erclReduced.left = 0 + eptlOffset.x;
|
||
erclReduced.top = eptlOffset.y;
|
||
erclReduced.right = SurfBM.ps->sizl().cx + eptlOffset.x;
|
||
erclReduced.bottom = SurfBM.ps->sizl().cy + eptlOffset.y;
|
||
|
||
//
|
||
// Intersect the dest with the source.
|
||
//
|
||
|
||
erclDest *= erclReduced;
|
||
|
||
if (erclDest.bEmpty())
|
||
{
|
||
return(0);
|
||
}
|
||
|
||
//
|
||
// The bitmap may be a DFB. Synchronization should have been taken
|
||
// care by the devlock that we already acquired.
|
||
//
|
||
|
||
ASSERTGDI(!(SurfBM.ps->bUseDevlock()) ||
|
||
(SurfBM.ps->hdev() == po.hdev()), "Devlock not acquired");
|
||
|
||
EngCopyBits(SurfDimoTemp.pSurfobj(),
|
||
SurfBM.pSurfobj(),
|
||
(CLIPOBJ *) NULL,
|
||
pxlo,
|
||
(PRECTL) &erclDest,
|
||
(PPOINTL) &eptlSrc);
|
||
|
||
if (bRLE)
|
||
{
|
||
//
|
||
// If pjBits is NULL we want these to write the size to hold the
|
||
// compressed bits in the header. If pjBits is not NULL we want
|
||
// to compress the data into the buffer and fail returning 0 if
|
||
// the buffer is not big enough.
|
||
//
|
||
|
||
if (uiCompression == BI_RLE4)
|
||
{
|
||
pBitsInfo->bmiHeader.biSizeImage = EncodeRLE4(
|
||
pjCompressionBits,
|
||
pjBits,
|
||
uiWidth,
|
||
cNumScan,
|
||
pBitsInfo->bmiHeader.biSizeImage
|
||
);
|
||
}
|
||
else if (uiCompression == BI_RLE8)
|
||
{
|
||
pBitsInfo->bmiHeader.biSizeImage = EncodeRLE8(
|
||
pjCompressionBits,
|
||
pjBits,
|
||
uiWidth,
|
||
cNumScan,
|
||
pBitsInfo->bmiHeader.biSizeImage
|
||
);
|
||
}
|
||
|
||
//
|
||
// if the encoded data doesn't fit into the buffer
|
||
// the encode routines return 0 and we do the same
|
||
|
||
if (pBitsInfo->bmiHeader.biSizeImage == 0)
|
||
{
|
||
return(0);
|
||
}
|
||
}
|
||
|
||
return(erclDest.bottom - erclDest.top);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreSetBitmapDimension
|
||
*
|
||
* API entry point for setting the sizlDim of the bitmap.
|
||
* sizlDim is not used by GDI, but is kept around for the user to query.
|
||
*
|
||
* Returns: TRUE if successful, FALSE for failure.
|
||
*
|
||
* History:
|
||
* 02-May-1991 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL
|
||
APIENTRY
|
||
GreSetBitmapDimension(
|
||
HBITMAP hbm,
|
||
int ulX,
|
||
int ulY,
|
||
LPSIZE pSize)
|
||
{
|
||
BOOL bReturn = FALSE;
|
||
SURFREF Surf((HSURF)hbm);
|
||
|
||
if (Surf.bValid())
|
||
{
|
||
if (Surf.ps->bApiBitmap())
|
||
{
|
||
SIZEL sizl;
|
||
|
||
if (pSize != (LPSIZE) NULL)
|
||
{
|
||
*pSize = Surf.ps->sizlDim();
|
||
}
|
||
|
||
sizl.cx = ulX;
|
||
sizl.cy = ulY;
|
||
Surf.ps->sizlDim(sizl);
|
||
bReturn = TRUE;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
||
}
|
||
|
||
return(bReturn);
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreGetBitmapDimension
|
||
*
|
||
* API entry point for getting the sizlDim of the bitmap.
|
||
* sizlDim is not used by GDI, but is kept around for the user to query.
|
||
*
|
||
* Returns: TRUE if successful, FALSE for failure.
|
||
*
|
||
* History:
|
||
* 02-May-1991 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL
|
||
APIENTRY
|
||
GreGetBitmapDimension(
|
||
HBITMAP hbm,
|
||
LPSIZE pSize)
|
||
{
|
||
BOOL bReturn = FALSE;
|
||
SURFREF Surf((HSURF)hbm);
|
||
|
||
if (Surf.bValid())
|
||
{
|
||
if (Surf.ps->bApiBitmap())
|
||
{
|
||
if (pSize != (LPSIZE) NULL)
|
||
{
|
||
*pSize = Surf.ps->sizlDim();
|
||
bReturn = TRUE;
|
||
}
|
||
else
|
||
{
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
|
||
}
|
||
|
||
return(bReturn);
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* GreStretchDIBits
|
||
*
|
||
* API entry for stretching a DIB to a DC.
|
||
*
|
||
* Arguments:
|
||
*
|
||
* hdc - handle of device context
|
||
* xDst - x-coordinate of upper-left corner of dest. rect.
|
||
* yDst - y-coordinate of upper-left corner of dest. rect.
|
||
* cWidthDest - width of destination rectangle
|
||
* cHeightDest - height of destination rectangle
|
||
* xSrc - x-coordinate of upper-left corner of source rect.
|
||
* ySrc - y-coordinate of upper-left corner of source rect.
|
||
* cWidthSrc - width of source rectangle
|
||
* cHeightSrc - height of source rectangle
|
||
* pInitBits - address of bitmap bits
|
||
* pInfoHeader - address of bitmap data
|
||
* iUsage - usage
|
||
* rop4 - raster operation code
|
||
* cjMaxInfo - maximum size of pInfoHeader
|
||
* cjMaxBits - maximum size of pIintBits
|
||
*
|
||
* Return Value:
|
||
*
|
||
* Number of scan lines copied or 0 for error
|
||
*
|
||
* History:
|
||
*
|
||
* 10-May-1991 -by- Patrick Haluptzok patrickh
|
||
\**************************************************************************/
|
||
|
||
int
|
||
APIENTRY
|
||
GreStretchDIBits(
|
||
HDC hdc,
|
||
int xDst,
|
||
int yDst,
|
||
int cWidthDest,
|
||
int cHeightDest,
|
||
int xSrc,
|
||
int ySrc,
|
||
int cWidthSrc,
|
||
int cHeightSrc,
|
||
LPBYTE pjBits,
|
||
LPBITMAPINFO pInfoHeader,
|
||
DWORD iUsage,
|
||
DWORD Rop)
|
||
{
|
||
PBITMAPINFO pbmi = pInfoHeader;
|
||
INT iRet = 0;
|
||
|
||
//
|
||
// if it is a COREHEADER, covert it
|
||
//
|
||
if (pInfoHeader && (pInfoHeader->bmiHeader.biSize == sizeof(BITMAPCOREHEADER)))
|
||
{
|
||
pbmi = pbmiConvertInfo (pInfoHeader, iUsage);
|
||
}
|
||
|
||
iRet = GreStretchDIBitsInternal(hdc,
|
||
xDst,
|
||
yDst,
|
||
cWidthDest,
|
||
cHeightDest,
|
||
xSrc,
|
||
ySrc,
|
||
cWidthSrc,
|
||
cHeightSrc,
|
||
pjBits,
|
||
pbmi,
|
||
iUsage,
|
||
Rop,
|
||
(UINT)~0,
|
||
(UINT)~0,
|
||
NULL);
|
||
|
||
if (pbmi && (pbmi != pInfoHeader))
|
||
{
|
||
VFREEMEM (pbmi);
|
||
}
|
||
|
||
return (iRet);
|
||
}
|
||
|
||
#define DIB_FLIP_X 1
|
||
#define DIB_FLIP_Y 2
|
||
|
||
|
||
int
|
||
APIENTRY
|
||
GreStretchDIBitsInternal(
|
||
HDC hdc,
|
||
int xDst,
|
||
int yDst,
|
||
int cWidthDest,
|
||
int cHeightDest,
|
||
int xSrc,
|
||
int ySrc,
|
||
int cWidthSrc,
|
||
int cHeightSrc,
|
||
LPBYTE pInitBits,
|
||
LPBITMAPINFO pInfoHeader,
|
||
DWORD iUsage,
|
||
DWORD rop4,
|
||
UINT cjMaxInfo,
|
||
UINT cjMaxBits,
|
||
HANDLE hcmXform)
|
||
{
|
||
int iRetHeight = 0;
|
||
|
||
#if DBG
|
||
if (pInfoHeader)
|
||
{
|
||
ASSERTGDI (pInfoHeader->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER), "bad header\n");
|
||
}
|
||
#endif
|
||
//
|
||
// Process the rop and get the A-vector notation.
|
||
//
|
||
|
||
int ropCode = (rop4 >> 16) & 0x000000FF;
|
||
|
||
ULONG ulAvec = (ULONG) gajRop3[ropCode];
|
||
|
||
//
|
||
// Check for no source required.
|
||
//
|
||
|
||
if (!(ulAvec & AVEC_NEED_SOURCE))
|
||
{
|
||
iRetHeight = NtGdiPatBlt(hdc,xDst,yDst,cWidthDest,cHeightDest, rop4);
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Validate the hdc.
|
||
//
|
||
|
||
DCOBJ dcoDest(hdc);
|
||
|
||
if (!dcoDest.bValid())
|
||
{
|
||
WARNING1("StretchDIBits failed - invalid DC\n");
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// Let's validate the parameters so we don't gp-fault ourselves.
|
||
//
|
||
// Size in header, copy it out, it can change.
|
||
//
|
||
|
||
ULONG ulSize;
|
||
|
||
if ((pInfoHeader == (LPBITMAPINFO) NULL) ||
|
||
(pInitBits == (LPBYTE) NULL) ||
|
||
((iUsage != DIB_RGB_COLORS) &&
|
||
(iUsage != DIB_PAL_COLORS) &&
|
||
(iUsage != DIB_PAL_INDICES)) ||
|
||
(cjMaxInfo < sizeof(BITMAPCOREHEADER)) || // Check first that we can access biSize.
|
||
(cjMaxInfo < (ulSize = pInfoHeader->bmiHeader.biSize)) ||
|
||
(ulSize < sizeof(BITMAPINFOHEADER)))
|
||
{
|
||
WARNING1("GreStretchDIBits failed because 1 of 3 params is invalid\n");
|
||
}
|
||
else
|
||
{
|
||
|
||
ULONG jStretchBltMode = dcoDest.pdc->jStretchBltMode();
|
||
|
||
//
|
||
// This is used to hold the height of the bitmap in.
|
||
//
|
||
|
||
int yHeight;
|
||
|
||
//
|
||
// Get the transform now, we'll need it later
|
||
//
|
||
|
||
EXFORMOBJ exo(dcoDest, WORLD_TO_DEVICE);
|
||
|
||
//
|
||
// Check for state incompatible with BI_JPEG or BI_PNG support.
|
||
//
|
||
|
||
if (IS_PASSTHROUGH_IMAGE(pInfoHeader->bmiHeader.biCompression))
|
||
{
|
||
//
|
||
// Device must support image format
|
||
// Only support rop 0xCCCC
|
||
// No rotations allowed
|
||
// DIB_RGB_COLORS only
|
||
// No hcmXform
|
||
//
|
||
|
||
if (!dcoDest.bSupportsPassthroughImage(pInfoHeader->bmiHeader.biCompression) ||
|
||
(ropCode != 0xcc) || exo.bRotation() ||
|
||
(iUsage != DIB_RGB_COLORS) || hcmXform)
|
||
{
|
||
//
|
||
// Return 0 for error.
|
||
//
|
||
|
||
WARNING("StretchDIBits -- invalid BI_JPEG/BI_PNG operation\n");
|
||
return iRetHeight;
|
||
}
|
||
}
|
||
|
||
//
|
||
// if it is one to one mapping, lets just call SetDIBitsToDevice
|
||
//
|
||
|
||
if ((cWidthDest == cWidthSrc) &&
|
||
(cHeightDest == cHeightSrc) &&
|
||
(cHeightSrc > 0) &&
|
||
(cWidthSrc > 0) &&
|
||
((xSrc | ySrc) == 0) &&
|
||
(ropCode == 0xcc) &&
|
||
(jStretchBltMode != HALFTONE))
|
||
{
|
||
if (exo.bTranslationsOnly())
|
||
{
|
||
yHeight = (int)ABS(pInfoHeader->bmiHeader.biHeight);
|
||
cHeightSrc = min(cHeightSrc, yHeight);
|
||
|
||
return(GreSetDIBitsToDeviceInternal(
|
||
hdc,
|
||
xDst,
|
||
yDst,
|
||
cWidthDest,
|
||
cHeightDest,
|
||
xSrc,
|
||
ySrc,
|
||
ySrc,
|
||
cHeightSrc,
|
||
pInitBits,
|
||
pInfoHeader,
|
||
iUsage,
|
||
cjMaxBits,
|
||
cjMaxInfo,
|
||
TRUE,
|
||
hcmXform));
|
||
}
|
||
}
|
||
|
||
//
|
||
// We really just want to blt it into a temporary DIB and then
|
||
// blt it out.
|
||
//
|
||
// Calls with DIB_PAL_COLORS will fail HTBlt since there is no
|
||
// src pal. On mono printers, this looks really bad with no gray scale.
|
||
// Make it go thru GreStretchBlt so we won't lose HALFTONE here.
|
||
// [lingyunw]
|
||
//
|
||
BOOL bForceHalftone = FALSE;
|
||
|
||
if ((iUsage == DIB_PAL_COLORS))
|
||
{
|
||
DEVLOCKOBJ dlo(dcoDest);
|
||
|
||
if (dcoDest.pSurface() && dcoDest.pSurface()->iFormat() == BMF_1BPP)
|
||
{
|
||
bForceHalftone = TRUE;
|
||
}
|
||
}
|
||
|
||
if ((ropCode != 0xcc) || (exo.bRotation()) || bForceHalftone)
|
||
{
|
||
//
|
||
// Set up src rectangle in upper-left coordinates.
|
||
//
|
||
|
||
yHeight = (int)pInfoHeader->bmiHeader.biHeight;
|
||
|
||
int ySrcNew;
|
||
|
||
if (yHeight > 0)
|
||
{
|
||
ySrcNew = yHeight - ySrc - cHeightSrc;
|
||
}
|
||
else
|
||
{
|
||
ySrcNew = ySrc;
|
||
}
|
||
|
||
//
|
||
// We have to decompress it first and then call StretchBlt
|
||
//
|
||
|
||
HDC hdcTemp = GreCreateCompatibleDC(hdc);
|
||
|
||
UINT uiCompression = (UINT) pInfoHeader->bmiHeader.biCompression;
|
||
|
||
HBITMAP hbm;
|
||
|
||
//
|
||
// Let GreCreateDIBitmapComp to decompress RLEs
|
||
//
|
||
if ((uiCompression != BI_RLE8) && (uiCompression != BI_RLE4))
|
||
{
|
||
hbm = GreCreateDIBitmapReal(hdc,
|
||
CBM_INIT,
|
||
pInitBits,
|
||
pInfoHeader,
|
||
iUsage,
|
||
cjMaxInfo,
|
||
cjMaxBits,
|
||
(HANDLE)0,
|
||
0,
|
||
(HANDLE)0,
|
||
0,
|
||
0,
|
||
NULL);
|
||
}
|
||
else
|
||
{
|
||
hbm = GreCreateDIBitmapComp(hdc,
|
||
((BITMAPINFOHEADER *) pInfoHeader)->biWidth,
|
||
((BITMAPINFOHEADER *) pInfoHeader)->biHeight,
|
||
CBM_INIT,
|
||
pInitBits,
|
||
pInfoHeader,
|
||
iUsage,
|
||
cjMaxInfo,
|
||
cjMaxBits,
|
||
CDBI_INTERNAL,
|
||
hcmXform
|
||
);
|
||
|
||
}
|
||
|
||
if ((hdcTemp == (HDC) NULL) || (hbm == (HBITMAP) NULL))
|
||
{
|
||
//
|
||
// The creation calls will log the correct errors.
|
||
//
|
||
|
||
WARNING1("StretchDIBits failed to allocate temp DC and temp bitmap\n");
|
||
bDeleteDCInternal(hdcTemp,TRUE,FALSE);
|
||
GreDeleteObject(hbm);
|
||
}
|
||
else
|
||
{
|
||
|
||
HBITMAP hbmTemp = (HBITMAP)GreSelectBitmap(hdcTemp, (HBITMAP)hbm);
|
||
ASSERTGDI(hbmTemp == STOCKOBJ_BITMAP, "ERROR GDI SetDIBits");
|
||
|
||
//
|
||
// Send them off to someone we know can do it.
|
||
//
|
||
|
||
BOOL bReturn = GreStretchBltInternal
|
||
(
|
||
hdc,
|
||
xDst,
|
||
yDst,
|
||
cWidthDest,
|
||
cHeightDest,
|
||
hdcTemp,
|
||
xSrc,ySrcNew,
|
||
cWidthSrc,
|
||
cHeightSrc,
|
||
rop4,
|
||
(DWORD) 0x00FFFFFF,
|
||
STRETCHBLT_ENABLE_ICM
|
||
);
|
||
|
||
bDeleteDCInternal(hdcTemp,TRUE,FALSE);
|
||
GreDeleteObject(hbm);
|
||
|
||
if (bReturn)
|
||
{
|
||
iRetHeight = yHeight;
|
||
}
|
||
}
|
||
|
||
return(iRetHeight);
|
||
}
|
||
|
||
//
|
||
// Get the info from the Header depending upon what kind it is.
|
||
//
|
||
|
||
UINT uiBitCount, uiCompression, uiWidth, uiPalUsed;
|
||
PULONG pulColors;
|
||
DEVBITMAPINFO dbmi;
|
||
dbmi.fl = 0;
|
||
BOOL bSuccess = TRUE;
|
||
|
||
uiBitCount = (UINT) pInfoHeader->bmiHeader.biBitCount;
|
||
uiCompression = (UINT) pInfoHeader->bmiHeader.biCompression;
|
||
uiWidth = (UINT) pInfoHeader->bmiHeader.biWidth;
|
||
yHeight = (int) pInfoHeader->bmiHeader.biHeight;
|
||
uiPalUsed = (UINT) pInfoHeader->bmiHeader.biClrUsed;
|
||
pulColors = (PULONG) ((LPBYTE)pInfoHeader+ulSize);
|
||
|
||
if (yHeight < 0)
|
||
{
|
||
dbmi.fl = BMF_TOPDOWN;
|
||
yHeight = -yHeight;
|
||
}
|
||
|
||
//
|
||
// Now that cjMaxInfo has been validated for the header, adjust it to refer to
|
||
// the color table
|
||
//
|
||
|
||
cjMaxInfo -= (UINT)ulSize;
|
||
|
||
//
|
||
// Figure out what this guy is blting from.
|
||
//
|
||
|
||
ULONG cColorsMax;
|
||
FLONG iPalMode;
|
||
FLONG iPalType;
|
||
FLONG flRed;
|
||
FLONG flGre;
|
||
FLONG flBlu;
|
||
BOOL bRLE = FALSE;
|
||
|
||
if (uiCompression == BI_BITFIELDS)
|
||
{
|
||
//
|
||
// Handle 16 and 32 bit per pel bitmaps.
|
||
//
|
||
|
||
if ((ulSize <= sizeof(BITMAPINFO)) && (cjMaxInfo < (sizeof(ULONG) * 3)))
|
||
{
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
WARNING1("SetDIBitsToDevice 16/32bpp failed - not room for flags\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
|
||
if (iUsage == DIB_PAL_COLORS)
|
||
{
|
||
iUsage = DIB_RGB_COLORS;
|
||
}
|
||
|
||
switch (uiBitCount)
|
||
{
|
||
case 16:
|
||
dbmi.iFormat = BMF_16BPP;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
break;
|
||
default:
|
||
WARNING1("SetDIBitsToDevice failed for BI_BITFIELDS\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
//
|
||
// if BITMAPV4 or greater then masks are stored in info header
|
||
//
|
||
|
||
if (ulSize >= sizeof(BITMAPINFOHEADER))
|
||
{
|
||
pulColors = (PULONG) ((LPBYTE)pInfoHeader+sizeof(BITMAPINFOHEADER));
|
||
}
|
||
|
||
flRed = pulColors[0];
|
||
flGre = pulColors[1];
|
||
flBlu = pulColors[2];
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BITFIELDS;
|
||
iPalType = PAL_FIXED;
|
||
dbmi.cjBits = ((((uiBitCount * uiWidth) + 31) >> 5) << 2) * yHeight;
|
||
}
|
||
}
|
||
else if (uiCompression == BI_RGB)
|
||
{
|
||
switch (uiBitCount)
|
||
{
|
||
case 1:
|
||
dbmi.iFormat = BMF_1BPP;
|
||
cColorsMax = 2;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 4:
|
||
dbmi.iFormat = BMF_4BPP;
|
||
cColorsMax = 16;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 8:
|
||
dbmi.iFormat = BMF_8BPP;
|
||
cColorsMax = 256;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
default:
|
||
|
||
if (iUsage == DIB_PAL_COLORS)
|
||
{
|
||
iUsage = DIB_RGB_COLORS;
|
||
}
|
||
|
||
switch (uiBitCount)
|
||
{
|
||
case 16:
|
||
dbmi.iFormat = BMF_16BPP;
|
||
flRed = 0x7c00;
|
||
flGre = 0x03e0;
|
||
flBlu = 0x001f;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BITFIELDS;
|
||
iPalType = PAL_FIXED;
|
||
break;
|
||
case 24:
|
||
dbmi.iFormat = BMF_24BPP;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BGR;
|
||
iPalType = PAL_FIXED;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BGR;
|
||
iPalType = PAL_FIXED;
|
||
break;
|
||
default:
|
||
WARNING1("SetDIBitsToDevice failed invalid bitcount in bmi BI_RGB\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
dbmi.cjBits = ((((uiBitCount * uiWidth) + 31) >> 5) << 2) * yHeight;
|
||
}
|
||
}
|
||
else if (uiCompression == BI_CMYK)
|
||
{
|
||
ASSERTGDI(iUsage == DIB_RGB_COLORS,
|
||
"StretchDIBits(BI_CMYK):iUsage should be DIB_RGB_COLORS\n");
|
||
|
||
DCOBJ dco(hdc);
|
||
|
||
//
|
||
// Current device context accept CMYK color ?
|
||
//
|
||
if (!dco.bValid() || !dco.pdc->bIsCMYKColor())
|
||
{
|
||
WARNING1("SetDIBitsToDevice:DC is not in CMYK color mode for BI_CMYK\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
switch (uiBitCount)
|
||
{
|
||
case 1:
|
||
dbmi.iFormat = BMF_1BPP;
|
||
cColorsMax = 2;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 4:
|
||
dbmi.iFormat = BMF_4BPP;
|
||
cColorsMax = 16;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 8:
|
||
dbmi.iFormat = BMF_8BPP;
|
||
cColorsMax = 256;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_CMYK;
|
||
iPalType = PAL_FIXED;
|
||
break;
|
||
default:
|
||
WARNING1("SetDIBitsToDevice failed invalid bitcount in bmi BI_CMYK\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
dbmi.cjBits = ((((uiBitCount * uiWidth) + 31) >> 5) << 2) * yHeight;
|
||
}
|
||
}
|
||
else if ((uiCompression == BI_RLE4) || (uiCompression == BI_CMYKRLE4))
|
||
{
|
||
if (uiCompression == BI_CMYKRLE4)
|
||
{
|
||
ASSERTGDI(iUsage == DIB_RGB_COLORS,
|
||
"StretchDIBits(BI_CMYKRLE4):iUsage should be DIB_RGB_COLORS\n");
|
||
|
||
DCOBJ dco(hdc);
|
||
|
||
//
|
||
// Current device context accept CMYK color ?
|
||
//
|
||
if (!dco.bValid() || !dco.pdc->bIsCMYKColor())
|
||
{
|
||
WARNING1("SetDIBitsToDevice:DC is not in CMYK color mode for BI_CMYKRLE4\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
if (uiBitCount != 4)
|
||
{
|
||
WARNING1("StretchDIBits invalid bitcount BI_RLE4\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
dbmi.iFormat = BMF_4RLE;
|
||
cColorsMax = 16;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
dbmi.cjBits = pInfoHeader->bmiHeader.biSizeImage;
|
||
bRLE = TRUE;
|
||
}
|
||
}
|
||
else if ((uiCompression == BI_RLE8) || (uiCompression == BI_CMYKRLE8))
|
||
{
|
||
if (uiCompression == BI_CMYKRLE8)
|
||
{
|
||
ASSERTGDI(iUsage == DIB_RGB_COLORS,
|
||
"StretchDIBits(BI_CMYKRLE8):iUsage should be DIB_RGB_COLORS\n");
|
||
|
||
DCOBJ dco(hdc);
|
||
|
||
//
|
||
// Current device context accept CMYK color ?
|
||
//
|
||
if (!dco.bValid() || !dco.pdc->bIsCMYKColor())
|
||
{
|
||
WARNING1("SetDIBitsToDevice:DC is not in CMYK color mode for BI_CMYKRLE8\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
if (uiBitCount != 8)
|
||
{
|
||
WARNING1("StretchDIBits invalid bitcount BI_RLE8\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
dbmi.iFormat = BMF_8RLE;
|
||
cColorsMax = 256;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
dbmi.cjBits = pInfoHeader->bmiHeader.biSizeImage;
|
||
bRLE = TRUE;
|
||
}
|
||
}
|
||
else if (uiCompression == BI_JPEG)
|
||
{
|
||
//
|
||
// The XLATEOBJ we setup for BI_JPEG is only valid for
|
||
// querying the ICM flags in the flXlate member.
|
||
//
|
||
|
||
dbmi.iFormat = BMF_JPEG;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BGR;
|
||
iPalType = PAL_FIXED;
|
||
dbmi.cjBits = pInfoHeader->bmiHeader.biSizeImage;
|
||
}
|
||
else if (uiCompression == BI_PNG)
|
||
{
|
||
//
|
||
// The XLATEOBJ we setup for BI_PNG is only valid for
|
||
// querying the ICM flags in the flXlate member.
|
||
//
|
||
|
||
dbmi.iFormat = BMF_PNG;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BGR;
|
||
iPalType = PAL_FIXED;
|
||
dbmi.cjBits = pInfoHeader->bmiHeader.biSizeImage;
|
||
}
|
||
else
|
||
{
|
||
WARNING1("GreStretchDIBits failed invalid Compression in header\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
//
|
||
// if color transform is not specified, use DC's color transform.
|
||
//
|
||
|
||
if (hcmXform == NULL)
|
||
{
|
||
hcmXform = dcoDest.pdc->hcmXform();
|
||
}
|
||
else
|
||
{
|
||
ICMMSG(("GreStretchDIBitsInternal():Bitmap has thier own colorspace\n"));
|
||
}
|
||
|
||
ULONG lIcmMode = dcoDest.pdc->lIcmMode();
|
||
|
||
if (IS_CMYK_COLOR(lIcmMode)) /* DC is CMYK color mode ? */
|
||
{
|
||
if ((hcmXform == NULL) || !IS_CMYK_BITMAP(uiCompression))
|
||
{
|
||
//
|
||
// DC mode is CMYK color, but bitmap itself is not.
|
||
// so clear CMYK color bit, so that XLATEOBJ will not
|
||
// have XO_FROM_CMYK
|
||
//
|
||
CLEAR_COLORTYPE(lIcmMode);
|
||
//
|
||
// then it's RGB.
|
||
//
|
||
lIcmMode |= DC_ICM_RGB_COLOR;
|
||
}
|
||
}
|
||
|
||
dbmi.cxBitmap = uiWidth;
|
||
dbmi.cyBitmap = yHeight;
|
||
|
||
ULONG cColors;
|
||
|
||
if (uiPalUsed != 0)
|
||
{
|
||
if (uiPalUsed <= cColorsMax)
|
||
{
|
||
cColors = uiPalUsed;
|
||
}
|
||
else
|
||
{
|
||
cColors = cColorsMax;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
cColors = cColorsMax;
|
||
}
|
||
|
||
if (cjMaxBits < dbmi.cjBits)
|
||
{
|
||
WARNING1("GreStretchDIBits failed because of invalid cjMaxBits\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
}
|
||
else
|
||
{
|
||
PDEVOBJ po(dcoDest.hdev());
|
||
ERECTL erclTrg(xDst, yDst, xDst + cWidthDest, yDst + cHeightDest);
|
||
|
||
//
|
||
// Transform the dest point to DEVICE coordinates.
|
||
//
|
||
|
||
EXFORMOBJ xoDest(dcoDest, WORLD_TO_DEVICE);
|
||
|
||
if (!xoDest.bXform(erclTrg))
|
||
{
|
||
WARNING1("StretchDIBits failed to transform coordinates\n");
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Return null operations.
|
||
//
|
||
|
||
if (erclTrg.bEmpty())
|
||
{
|
||
iRetHeight = cHeightSrc;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Windows uses 'last point' exclusion on StretchBlt calls.
|
||
// This means we can't simply 'order' a rectangle, we must
|
||
// Flip it, remember that it has flipped and adjust the
|
||
// coordinates to match Windows, this is sick and twisted
|
||
// but it's compatible. [donalds] 03-Jun-1993
|
||
//
|
||
|
||
FLONG flFlip = 0;
|
||
LONG lTmp;
|
||
|
||
if (erclTrg.left > erclTrg.right)
|
||
{
|
||
lTmp = erclTrg.left, erclTrg.left = erclTrg.right, erclTrg.right = lTmp;
|
||
|
||
//
|
||
// WINBUG #274633 3-19-2000 andarsov. When the transformation has the
|
||
// bMirrored flag, it does the increment of left, right itself.
|
||
// The check below prevents the double increment, and losing of a pixel column.
|
||
//
|
||
|
||
if (!xoDest.bMirrored)
|
||
{
|
||
erclTrg.left++;
|
||
erclTrg.right++;
|
||
}
|
||
|
||
flFlip ^= DIB_FLIP_X;
|
||
}
|
||
|
||
if (erclTrg.top > erclTrg.bottom)
|
||
{
|
||
lTmp = erclTrg.top, erclTrg.top = erclTrg.bottom, erclTrg.bottom = lTmp;
|
||
|
||
erclTrg.top++;
|
||
erclTrg.bottom++;
|
||
|
||
flFlip ^= DIB_FLIP_Y;
|
||
}
|
||
|
||
//
|
||
// We need a well ordered rectangle to compute clipping and exclusion with.
|
||
//
|
||
|
||
PALMEMOBJ palTemp;
|
||
|
||
if (iUsage == DIB_RGB_COLORS)
|
||
{
|
||
//
|
||
// Allocate a palette for this bitmap.
|
||
//
|
||
|
||
if (!palTemp.bCreatePalette(iPalMode,
|
||
cColorsMax,
|
||
(PULONG) NULL,
|
||
flRed,
|
||
flGre,
|
||
flBlu,
|
||
iPalType
|
||
)
|
||
)
|
||
{
|
||
WARNING1("Failed palette creation in StretchDIBits\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
DEVLOCKOBJ dlo(dcoDest);
|
||
SURFACE *pSurfDst = dcoDest.pSurfaceEff();
|
||
|
||
dbmi.fl |= dcoDest.bUMPD() ? UMPD_SURFACE : 0;
|
||
|
||
dbmi.hpal = 0;
|
||
|
||
//
|
||
// Attempt to allocate the bitmap.
|
||
//
|
||
|
||
SURFMEM SurfDimoTemp;
|
||
|
||
if (bRLE)
|
||
{
|
||
DEVBITMAPINFO dbmiRLE;
|
||
SURFMEM SurfDimoRLE;
|
||
|
||
dbmiRLE = dbmi;
|
||
|
||
if (!SurfDimoRLE.bCreateDIB(&dbmiRLE, pInitBits))
|
||
{
|
||
WARNING("GreStretchDIBits failed SurfDimoRLE alloc\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Well StretchBlt can't handle RLE's, so we unpack it into
|
||
// SurfDimoTemp which must be an uncompressed format.
|
||
//
|
||
|
||
if (dbmi.iFormat == BMF_4RLE)
|
||
{
|
||
dbmi.iFormat = BMF_4BPP;
|
||
}
|
||
else
|
||
{
|
||
dbmi.iFormat = BMF_8BPP;
|
||
}
|
||
|
||
if (!SurfDimoTemp.bCreateDIB(&dbmi, NULL))
|
||
{
|
||
WARNING("GreStretchDIBits failed\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
ERECTL erclTemp(0,0, dbmi.cxBitmap, dbmi.cyBitmap);
|
||
|
||
EngCopyBits(SurfDimoTemp.pSurfobj(),
|
||
SurfDimoRLE.pSurfobj(),
|
||
(CLIPOBJ *) NULL,
|
||
NULL,
|
||
(PRECTL) &erclTemp,
|
||
(PPOINTL) &gptl00
|
||
);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (!SurfDimoTemp.bCreateDIB(&dbmi,pInitBits))
|
||
{
|
||
WARNING("GreStretchDIBits failed\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
//
|
||
// Lock the Rao region if we are drawing on a display surface. The Rao
|
||
// region might otherwise change asynchronously. The DEVLOCKOBJ also makes
|
||
// sure that the VisRgn is up to date, calling the window manager if
|
||
// necessary to recompute it. It also protects us from pSurfDest
|
||
// being changed asynchronously by a dynamic mode change.
|
||
//
|
||
|
||
DEVLOCKOBJ dlo(dcoDest);
|
||
|
||
SURFACE *pSurfDest = dcoDest.pSurfaceEff();
|
||
XEPALOBJ palDest(pSurfDest->ppal());
|
||
XEPALOBJ palDestDC(dcoDest.ppal());
|
||
XLATEOBJ *pxlo;
|
||
EXLATEOBJ xlo;
|
||
BOOL bNeedAssociatePalette = FALSE;
|
||
|
||
//
|
||
// Associate the DC's palette with the bitmap for use when
|
||
// converting DDBs to DIBs for dynamic mode changes.
|
||
//
|
||
|
||
if (!palDestDC.bIsPalDefault())
|
||
{
|
||
pSurfDest->hpalHint(palDestDC.hpal());
|
||
}
|
||
|
||
switch (iUsage)
|
||
{
|
||
case DIB_RGB_COLORS:
|
||
|
||
if (cColors)
|
||
{
|
||
if (cjMaxInfo < (cColors * 4))
|
||
{
|
||
WARNING1("StretchDIBits failed DIB_RGB_COLORS bmi invalid size\n");
|
||
bSuccess = FALSE;
|
||
|
||
//
|
||
// break out of case
|
||
//
|
||
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Copy bitmap color table into palette
|
||
//
|
||
|
||
if (IS_CMYK_BITMAP(uiCompression))
|
||
{
|
||
palTemp.vCopy_cmykquad(pulColors, 0, cColors);
|
||
}
|
||
else
|
||
{
|
||
palTemp.vCopy_rgbquad((RGBQUAD *) pulColors, 0, cColors);
|
||
}
|
||
}
|
||
|
||
//
|
||
// This is a special version of the constructor that doesn't search the
|
||
// cache and doesn't put it in the cache when it's done.
|
||
//
|
||
|
||
if (NULL == xlo.pInitXlateNoCache(
|
||
hcmXform,
|
||
lIcmMode,
|
||
palTemp,
|
||
palDest,
|
||
palDestDC,
|
||
0,
|
||
0,
|
||
0x00FFFFFF
|
||
)
|
||
)
|
||
{
|
||
//
|
||
// Error message is already logged.
|
||
//
|
||
|
||
WARNING1("GreStretchDIBits failed XLATE init\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// This is a special version of the constructor that doesn't search the
|
||
// cache and doesn't put it in the cache when it's done.
|
||
//
|
||
|
||
if (NULL == xlo.pInitXlateNoCache(
|
||
hcmXform,
|
||
lIcmMode,
|
||
palTemp,
|
||
palDest,
|
||
palDestDC,
|
||
0,
|
||
0,
|
||
0x00FFFFFF
|
||
)
|
||
)
|
||
{
|
||
//
|
||
// Error message is already logged.
|
||
//
|
||
|
||
WARNING1("GreStretchDIBits failed XLATE init\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
}
|
||
|
||
pxlo = xlo.pxlo();
|
||
break;
|
||
|
||
case DIB_PAL_COLORS:
|
||
|
||
if (cjMaxInfo < (cColors * sizeof(USHORT)))
|
||
{
|
||
WARNING1("StretchDIBits failed DIB_PAL_COLORS is invalid\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
if (!xlo.bMakeXlate(
|
||
(PUSHORT) pulColors,
|
||
palDestDC,
|
||
pSurfDest,
|
||
cColors,
|
||
cColorsMax))
|
||
{
|
||
WARNING1("GDISRV GreStretchDIBits failed bMakeXlate\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
pxlo = xlo.pxlo();
|
||
|
||
//
|
||
// If we are drawing to display meta-screen with multi-monitor
|
||
// system and it's colour-depth is not same for all those monitor.
|
||
// we need to create palette to map color to other-than primary
|
||
// monitor(s).
|
||
//
|
||
|
||
if (gbMultiMonMismatchColor && po.bDisplayPDEV())
|
||
{
|
||
if (palTemp.bCreatePalette(iPalMode, cColorsMax, (PULONG) NULL,
|
||
flRed, flGre, flBlu, iPalType))
|
||
{
|
||
XEPALOBJ palSurfEff(pSurfDest->ppal() ? \
|
||
pSurfDest->ppal() : po.ppalSurf());
|
||
|
||
//
|
||
// Keep DC (or Surface) palette entry to temporay palette.
|
||
//
|
||
|
||
palTemp.vGetEntriesFrom(palDestDC, palSurfEff,
|
||
(PUSHORT)pulColors, cColors);
|
||
|
||
bNeedAssociatePalette = TRUE;
|
||
}
|
||
else
|
||
{
|
||
WARNING1("GreStretchDIBitsInternal: Failed to create temporary palette");
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case DIB_PAL_INDICES:
|
||
|
||
if (pSurfDest->iFormat() != dbmi.iFormat)
|
||
{
|
||
WARNING1("StretchDIBits failed - DIB_PAL_INDICES used - DIB not format of Dst\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
pxlo = &xloIdent;
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
|
||
//
|
||
// Accumulate bounds. We can do this before knowing if the operation is
|
||
// successful because bounds can be loose.
|
||
//
|
||
|
||
if (dcoDest.fjAccum())
|
||
{
|
||
dcoDest.vAccumulate(erclTrg);
|
||
}
|
||
|
||
//
|
||
// Bail out if this is an INFO_DC, but only after we have the attempted to grab devlock
|
||
//
|
||
|
||
if (dcoDest.bFullScreen())
|
||
{
|
||
iRetHeight = yHeight;
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// now bail out if the devlock failed for any other reason
|
||
//
|
||
|
||
if (!dlo.bValid())
|
||
{
|
||
WARNING1("GreStretchDIBits failed the DEVLOCK\n");
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// With a fixed DC origin we can change the destination to SCREEN coordinates.
|
||
//
|
||
|
||
erclTrg += dcoDest.eptlOrigin();
|
||
|
||
//
|
||
// Handle BitBlts that have a source. Create a rect bounding the
|
||
// src and the bits that have been supplied.
|
||
//
|
||
|
||
EPOINTL eptlSrc;
|
||
ERECTL erclSrc;
|
||
|
||
erclSrc.left = xSrc;
|
||
|
||
//
|
||
// If the DIB is regular PM DIB the coordinates are lower-left and need
|
||
// to adjusted to upper left.
|
||
//
|
||
|
||
//
|
||
// fix a bug for JPEG/TOPDOWN case
|
||
// the same problem occurs for general DIBs but it's too risky
|
||
// to fix now
|
||
//
|
||
if ((uiCompression == BI_JPEG) && (dbmi.fl & BMF_TOPDOWN))
|
||
{
|
||
erclSrc.top = ySrc;
|
||
}
|
||
else
|
||
{
|
||
erclSrc.top = yHeight - ySrc - cHeightSrc;
|
||
}
|
||
|
||
erclSrc.bottom = erclSrc.top + cHeightSrc;
|
||
erclSrc.right = erclSrc.left + cWidthSrc;
|
||
|
||
//
|
||
// Order the Src rectangle, flipping Dst to reflect it.
|
||
//
|
||
|
||
if (erclSrc.left > erclSrc.right)
|
||
{
|
||
lTmp = erclSrc.left, erclSrc.left = erclSrc.right, erclSrc.right = lTmp;
|
||
|
||
erclSrc.left++;
|
||
erclSrc.right++;
|
||
|
||
flFlip ^= DIB_FLIP_X;
|
||
}
|
||
|
||
if (erclSrc.top > erclSrc.bottom)
|
||
{
|
||
lTmp = erclSrc.top, erclSrc.top = erclSrc.bottom, erclSrc.bottom = lTmp;
|
||
|
||
erclSrc.top++;
|
||
erclSrc.bottom++;
|
||
|
||
flFlip ^= DIB_FLIP_Y;
|
||
}
|
||
|
||
//
|
||
// Make sure some portion of the source is on the src surface.
|
||
//
|
||
|
||
if ((erclSrc.right <= 0) ||
|
||
(erclSrc.bottom <= 0) ||
|
||
(erclSrc.left >= SurfDimoTemp.ps->sizl().cx) ||
|
||
(erclSrc.top >= SurfDimoTemp.ps->sizl().cy) ||
|
||
(erclSrc.bEmpty()))
|
||
{
|
||
|
||
//
|
||
// Well nothing is visible, let's get out of here.
|
||
//
|
||
|
||
WARNING1("GreStretchDIBits nothing visible in SRC rectangle\n");
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// Compute the clipping complexity and maybe reduce the exclusion rectangle.
|
||
//
|
||
|
||
ECLIPOBJ co(dcoDest.prgnEffRao(), erclTrg);
|
||
|
||
//
|
||
// Check the destination which is reduced by clipping.
|
||
//
|
||
|
||
if (co.erclExclude().bEmpty())
|
||
{
|
||
iRetHeight = yHeight;
|
||
}
|
||
else
|
||
{
|
||
if (bNeedAssociatePalette)
|
||
{
|
||
ASSERTGDI(SurfDimoTemp.ps->ppal() == NULL,
|
||
"SetDIBitsToDevice():Surface has palette already\n");
|
||
|
||
SurfDimoTemp.ps->ppal(palTemp.ppalGet());
|
||
}
|
||
|
||
//
|
||
// Exclude the pointer.
|
||
//
|
||
|
||
DEVEXCLUDEOBJ dxo(dcoDest,&erclTrg,&co);
|
||
|
||
//
|
||
// Get the function pointer.
|
||
//
|
||
|
||
PFN_DrvStretchBlt pfn;
|
||
|
||
//
|
||
// There are a bunch of conditions that we don't want to
|
||
// call the driver, so we make pfn point to the Eng
|
||
// function. But if the destination is a meta, we want it
|
||
// to actually call the Mul layer.
|
||
//
|
||
// WINBUG #357937 4-3-2001 jasonha Meta DEVBITMAPs must go thru Mul layer
|
||
// Don't check iType:
|
||
// DEVICE/DEVBITMAP -> MulStretchBlt
|
||
// BITMAP (not hooked) -> EngStretchBlt
|
||
|
||
PDEVOBJ pdoDest(pSurfDest->hdev());
|
||
|
||
pfn = PPFNGET(pdoDest, StretchBlt, pSurfDest->flags());
|
||
|
||
if ((pSurfDest->flags() & HOOK_StretchBlt) && !pdoDest.bMetaDriver())
|
||
{
|
||
// Don't call the driver if it doesn't do halftone.
|
||
|
||
if (jStretchBltMode == HALFTONE)
|
||
{
|
||
if (!(dcoDest.flGraphicsCaps() & GCAPS_HALFTONE))
|
||
pfn = (PFN_DrvStretchBlt)EngStretchBlt;
|
||
}
|
||
|
||
//
|
||
// Don't call the driver if the source rectangle exceeds
|
||
// the source surface. Some drivers punt using a duplicate
|
||
// of the source SURFOBJ, but without preserving its
|
||
// sizlBitmap member.
|
||
// This causes a source clipping bug (77102).
|
||
//
|
||
|
||
if((erclSrc.left < 0) ||
|
||
(erclSrc.top < 0) ||
|
||
(erclSrc.right > SurfDimoTemp.ps->sizl().cx) ||
|
||
(erclSrc.bottom > SurfDimoTemp.ps->sizl().cy))
|
||
{
|
||
pfn = (PFN_DrvStretchBlt)EngStretchBlt;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Reflect the accumulated flipping on the target
|
||
//
|
||
|
||
if (flFlip & DIB_FLIP_X)
|
||
{
|
||
lTmp = erclTrg.left, erclTrg.left = erclTrg.right, erclTrg.right = lTmp;
|
||
}
|
||
|
||
if (flFlip & DIB_FLIP_Y)
|
||
{
|
||
lTmp = erclTrg.top, erclTrg.top = erclTrg.bottom, erclTrg.bottom = lTmp;
|
||
}
|
||
|
||
//
|
||
// Inc the target surface uniqueness
|
||
//
|
||
|
||
INC_SURF_UNIQ(pSurfDest);
|
||
|
||
//
|
||
// Dispatch the call.
|
||
//
|
||
|
||
|
||
BOOL bRes = (*pfn)(pSurfDest->pSurfobj(),
|
||
SurfDimoTemp.pSurfobj(),
|
||
(SURFOBJ *) NULL,
|
||
(CLIPOBJ *)&co,
|
||
pxlo,
|
||
(dcoDest.pColorAdjustment()->caFlags & CA_DEFAULT) ?
|
||
(PCOLORADJUSTMENT)NULL : dcoDest.pColorAdjustment(),
|
||
&dcoDest.pdc->ptlFillOrigin(),
|
||
&erclTrg,
|
||
&erclSrc,
|
||
NULL,
|
||
(ULONG) jStretchBltMode
|
||
);
|
||
|
||
if (bRes)
|
||
{
|
||
iRetHeight = yHeight;
|
||
}
|
||
else
|
||
{
|
||
WARNING1("GreStretchDIBits failed DrvStretchBlt\n");
|
||
}
|
||
|
||
if (bNeedAssociatePalette)
|
||
{
|
||
SurfDimoTemp.ps->ppal(NULL);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
return(iRetHeight);
|
||
}
|
||
|
||
/**************************************************************************\
|
||
* psurfCreateDIBSurfaceAndXform
|
||
*
|
||
* Create Surface and Palette from DIB input
|
||
*
|
||
* Arguments:
|
||
*
|
||
*
|
||
*
|
||
* Return Value:
|
||
*
|
||
*
|
||
*
|
||
* History:
|
||
*
|
||
* 2/18/1997 Mark Enstrom [marke]
|
||
*
|
||
\**************************************************************************/
|
||
|
||
PSURFACE
|
||
psurfCreateDIBSurface(
|
||
HDC hdcDest,
|
||
LPBYTE pInitBits,
|
||
LPBITMAPINFO pInfoHeader,
|
||
DWORD iUsage,
|
||
UINT cjMaxInfo,
|
||
UINT cjMaxBits
|
||
)
|
||
{
|
||
SURFMEM SurfDimoTemp;
|
||
BOOL bSuccess = TRUE;
|
||
|
||
#if DBG
|
||
if (pInfoHeader)
|
||
{
|
||
ASSERTGDI (pInfoHeader->bmiHeader.biSize >= sizeof(BITMAPINFOHEADER), "bad header\n");
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Validate the hdc.
|
||
//
|
||
|
||
DCOBJ dcoDest(hdcDest);
|
||
|
||
if (!dcoDest.bValid())
|
||
{
|
||
WARNING1("psurfCreateDIBSurfaceAndXform failed - invalid DC\n");
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Let's validate the parameters so we don't gp-fault ourselves.
|
||
//
|
||
// Size in header, copy it out, it can change.
|
||
//
|
||
|
||
ULONG ulSize;
|
||
|
||
if ((pInfoHeader == (LPBITMAPINFO) NULL) ||
|
||
(pInitBits == (LPBYTE) NULL) ||
|
||
((iUsage != DIB_RGB_COLORS) &&
|
||
(iUsage != DIB_PAL_COLORS) &&
|
||
(iUsage != DIB_PAL_INDICES)) ||
|
||
(cjMaxInfo < sizeof(BITMAPCOREHEADER)) || // Check first that we can access biSize.
|
||
(cjMaxInfo < (ulSize = pInfoHeader->bmiHeader.biSize)) ||
|
||
(ulSize < sizeof(BITMAPINFOHEADER)))
|
||
{
|
||
WARNING1("psurfCreateDIBSurfaceAndXform failed input parameter validation\n");
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// This is used to hold the height of the bitmap in.
|
||
//
|
||
|
||
int yHeight;
|
||
|
||
//
|
||
// Get the info from the Header depending upon what kind it is.
|
||
//
|
||
|
||
BOOL bSuccess = TRUE;
|
||
UINT uiBitCount, uiCompression, uiWidth, uiPalUsed;
|
||
PULONG pulColors;
|
||
DEVBITMAPINFO dbmi;
|
||
|
||
dbmi.fl = 0;
|
||
|
||
uiBitCount = (UINT) pInfoHeader->bmiHeader.biBitCount;
|
||
uiCompression = (UINT) pInfoHeader->bmiHeader.biCompression;
|
||
|
||
uiWidth = (UINT) pInfoHeader->bmiHeader.biWidth;
|
||
yHeight = (int) pInfoHeader->bmiHeader.biHeight;
|
||
|
||
uiPalUsed = (UINT) pInfoHeader->bmiHeader.biClrUsed;
|
||
pulColors = (PULONG) ((LPBYTE)pInfoHeader+ulSize);
|
||
|
||
if (yHeight < 0)
|
||
{
|
||
dbmi.fl = BMF_TOPDOWN;
|
||
yHeight = -yHeight;
|
||
}
|
||
|
||
//
|
||
// Now that cjMaxInfo has been validated for the header, adjust it to refer to
|
||
// the color table
|
||
//
|
||
|
||
cjMaxInfo -= (UINT)ulSize;
|
||
|
||
//
|
||
// Figure out what this guy is blting from.
|
||
//
|
||
|
||
ULONG cColorsMax;
|
||
FLONG iPalMode;
|
||
FLONG iPalType;
|
||
FLONG flRed;
|
||
FLONG flGre;
|
||
FLONG flBlu;
|
||
BOOL bRLE = FALSE;
|
||
|
||
if (uiCompression == BI_BITFIELDS)
|
||
{
|
||
//
|
||
// Handle 16 and 32 bit per pel bitmaps.
|
||
//
|
||
|
||
if ((ulSize <= sizeof(BITMAPINFO)) && (cjMaxInfo < (sizeof(ULONG) * 3)))
|
||
{
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
WARNING1("psurfCreateDIBSurfaceAndXform failed - not room for flags\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// if BITMAPV4 or greater then masks are stored in info header
|
||
//
|
||
|
||
if (ulSize >= sizeof(BITMAPINFOHEADER))
|
||
{
|
||
pulColors = (PULONG) ((LPBYTE)pInfoHeader+sizeof(BITMAPINFOHEADER));
|
||
}
|
||
|
||
flRed = pulColors[0];
|
||
flGre = pulColors[1];
|
||
flBlu = pulColors[2];
|
||
|
||
if (iUsage == DIB_PAL_COLORS)
|
||
{
|
||
iUsage = DIB_RGB_COLORS;
|
||
}
|
||
|
||
switch (uiBitCount)
|
||
{
|
||
case 16:
|
||
dbmi.iFormat = BMF_16BPP;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
break;
|
||
default:
|
||
WARNING1("SetDIBitsToDevice failed for BI_BITFIELDS\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BITFIELDS;
|
||
iPalType = PAL_FIXED;
|
||
dbmi.cjBits = ((((uiBitCount * uiWidth) + 31) >> 5) << 2) * yHeight;
|
||
|
||
}
|
||
}
|
||
else if (uiCompression == BI_RGB)
|
||
{
|
||
switch (uiBitCount)
|
||
{
|
||
case 1:
|
||
dbmi.iFormat = BMF_1BPP;
|
||
cColorsMax = 2;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 4:
|
||
dbmi.iFormat = BMF_4BPP;
|
||
cColorsMax = 16;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 8:
|
||
dbmi.iFormat = BMF_8BPP;
|
||
cColorsMax = 256;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
default:
|
||
|
||
if (iUsage == DIB_PAL_COLORS)
|
||
{
|
||
iUsage = DIB_RGB_COLORS;
|
||
}
|
||
|
||
switch (uiBitCount)
|
||
{
|
||
case 16:
|
||
dbmi.iFormat = BMF_16BPP;
|
||
flRed = 0x7c00;
|
||
flGre = 0x03e0;
|
||
flBlu = 0x001f;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BITFIELDS;
|
||
iPalType = PAL_FIXED;
|
||
break;
|
||
case 24:
|
||
dbmi.iFormat = BMF_24BPP;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BGR;
|
||
iPalType = PAL_FIXED;
|
||
break;
|
||
case 32:
|
||
//
|
||
// This is for alpha API, assume
|
||
// 32 bpp BGR input is BGRA
|
||
//
|
||
dbmi.iFormat = BMF_32BPP;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_BGR;
|
||
iPalType = PAL_FIXED;
|
||
break;
|
||
default:
|
||
WARNING1("psurfCreateDIBSurfaceAndXform failed invalid bitcount in bmi BI_RGB\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
dbmi.cjBits = ((((uiBitCount * uiWidth) + 31) >> 5) << 2) * yHeight;
|
||
}
|
||
}
|
||
else if (uiCompression == BI_CMYK)
|
||
{
|
||
ASSERTGDI(iUsage == DIB_RGB_COLORS,
|
||
"psurfCreateDIBSurface(BI_CMYK):iUsage should be DIB_RGB_COLORS\n");
|
||
|
||
DCOBJ dcoDest(hdcDest);
|
||
|
||
//
|
||
// Current dc context accept CMYK color ?
|
||
//
|
||
if (!dcoDest.bValid() || !dcoDest.pdc->bIsCMYKColor())
|
||
{
|
||
WARNING1("psurfCreateDIBSurface:DC is not in CMYK color mode for BI_CMYK\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
else
|
||
{
|
||
switch (uiBitCount)
|
||
{
|
||
case 1:
|
||
dbmi.iFormat = BMF_1BPP;
|
||
cColorsMax = 2;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 4:
|
||
dbmi.iFormat = BMF_4BPP;
|
||
cColorsMax = 16;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 8:
|
||
dbmi.iFormat = BMF_8BPP;
|
||
cColorsMax = 256;
|
||
iPalMode = PAL_INDEXED;
|
||
iPalType = PAL_FREE;
|
||
break;
|
||
case 32:
|
||
dbmi.iFormat = BMF_32BPP;
|
||
cColorsMax = 0;
|
||
iPalMode = PAL_CMYK;
|
||
iPalType = PAL_FIXED;
|
||
break;
|
||
default:
|
||
WARNING1("psurfCreateDIBSurfaceAndXform failed invalid bitcount in bmi BI_RGB\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
dbmi.cjBits = ((((uiBitCount * uiWidth) + 31) >> 5) << 2) * yHeight;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// rle not supported
|
||
//
|
||
|
||
WARNING1("psurfCreateDIBSurfaceAndXform does not support RLE\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
dbmi.cxBitmap = uiWidth;
|
||
dbmi.cyBitmap = yHeight;
|
||
|
||
ULONG cColors;
|
||
|
||
if (uiPalUsed != 0)
|
||
{
|
||
if (uiPalUsed <= cColorsMax)
|
||
{
|
||
cColors = uiPalUsed;
|
||
}
|
||
else
|
||
{
|
||
cColors = cColorsMax;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
cColors = cColorsMax;
|
||
}
|
||
|
||
if (cjMaxBits < dbmi.cjBits)
|
||
{
|
||
WARNING1("psurfCreateDIBSurfaceAndXform failed because of invalid cjMaxBits\n");
|
||
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
||
}
|
||
else
|
||
{
|
||
PALMEMOBJ palTemp;
|
||
|
||
//
|
||
// Allocate a palette for this bitmap.
|
||
//
|
||
|
||
if (!palTemp.bCreatePalette(iPalMode,
|
||
cColorsMax,
|
||
(PULONG) NULL,
|
||
flRed,
|
||
flGre,
|
||
flBlu,
|
||
iPalType
|
||
)
|
||
)
|
||
{
|
||
WARNING1("psurfCreateDIBSurfaceAndXform: Failed palette creation\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
if (bSuccess && palTemp.bValid())
|
||
{
|
||
//
|
||
// need palette, is not locked in!
|
||
//
|
||
|
||
palTemp.vKeepIt();
|
||
dbmi.hpal = palTemp.hpal();
|
||
|
||
//
|
||
// Attempt to allocate the bitmap.
|
||
//
|
||
|
||
if (!SurfDimoTemp.bCreateDIB(&dbmi,pInitBits))
|
||
{
|
||
WARNING("psurfCreateDIBSurfaceAndXform failed bCreateDIB\n");
|
||
bSuccess = FALSE;
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
//
|
||
// Lock the Rao region if we are drawing on a display surface. The Rao
|
||
// region might otherwise change asynchronously. The DEVLOCKOBJ also makes
|
||
// sure that the VisRgn is up to date, calling the window manager if
|
||
// necessary to recompute it. It also protects us from pSurfDest
|
||
// being changed asynchronously by a dynamic mode change.
|
||
//
|
||
|
||
DEVLOCKOBJ dlo(dcoDest);
|
||
|
||
SURFACE *pSurfDest = dcoDest.pSurfaceEff();
|
||
XEPALOBJ palDest(pSurfDest->ppal());
|
||
XEPALOBJ palDestDC(dcoDest.ppal());
|
||
|
||
switch (iUsage)
|
||
{
|
||
case DIB_RGB_COLORS:
|
||
|
||
if (cColors)
|
||
{
|
||
if (cjMaxInfo < (cColors * 4))
|
||
{
|
||
WARNING1("psurfCreateDIBSurfaceAndXform: failed DIB_RGB_COLORS bmi invalid size\n");
|
||
bSuccess = FALSE;
|
||
|
||
//
|
||
// break out of case
|
||
//
|
||
|
||
break;
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Copy bitmap color table into palette
|
||
//
|
||
|
||
if (IS_CMYK_BITMAP(uiCompression))
|
||
{
|
||
palTemp.vCopy_cmykquad(pulColors, 0, cColors);
|
||
}
|
||
else
|
||
{
|
||
palTemp.vCopy_rgbquad((RGBQUAD *) pulColors, 0, cColors);
|
||
}
|
||
}
|
||
}
|
||
break;
|
||
|
||
case DIB_PAL_COLORS:
|
||
|
||
{
|
||
//
|
||
// translate PAL_INDICIES into colors
|
||
// from dc palette
|
||
//
|
||
|
||
ULONG palIndex;
|
||
|
||
PUSHORT pDibPalColor = (PUSHORT)pulColors;
|
||
|
||
//
|
||
// DIB_PAL_COLOR array is direct user input, verify
|
||
//
|
||
|
||
for (palIndex=0;palIndex<cColors;palIndex++)
|
||
{
|
||
PALETTEENTRY PalEntry;
|
||
ULONG TempIndex = pDibPalColor[palIndex];
|
||
|
||
if (TempIndex > 256)
|
||
{
|
||
TempIndex = 0;
|
||
}
|
||
|
||
PalEntry = palDestDC.palentryGet(TempIndex);
|
||
|
||
PalEntry.peFlags = 0;
|
||
|
||
palTemp.palentrySet(palIndex,PalEntry);
|
||
}
|
||
|
||
palTemp.vUpdateTime();
|
||
}
|
||
|
||
break;
|
||
|
||
//
|
||
// error case, don't support DIB_PAL_INDICIES
|
||
//
|
||
|
||
default:
|
||
bSuccess = FALSE;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (bSuccess)
|
||
{
|
||
//
|
||
// keep but ref count is 0
|
||
//
|
||
|
||
SurfDimoTemp.vKeepIt();
|
||
|
||
return(SurfDimoTemp.ps);
|
||
}
|
||
else
|
||
{
|
||
return(NULL);
|
||
}
|
||
}
|