You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5046 lines
175 KiB
5046 lines
175 KiB
/******************************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)) ||
|
|
(pInitInfo->bmiHeader.biWidth < 0))
|
|
{
|
|
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);
|
|
}
|
|
}
|