Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2722 lines
77 KiB

/******************************Module*Header*******************************\
* Module Name:
*
* icmapi.cxx
*
* Abstract
*
* This module implements Integrated Color match API support
*
* Author:
*
* Mark Enstrom (marke) 9-27-93
*
* Copyright (c) 1993-1999 Microsoft Corporation
\**************************************************************************/
#include "precomp.hxx"
extern "C" {
ULONG GreGetBitmapBitsSize(CONST BITMAPINFO *pbmi); // in ntgdi.c
BOOL bInitICM();
}
#pragma alloc_text(INIT, bInitICM)
PCOLORSPACE gpStockColorSpace;
HCOLORSPACE ghStockColorSpace;
UINT giIcmGammaRange;
#if DBG_ICM
ULONG IcmDebugLevel = 0;
#endif
#define sRGB_PROFILENAME L"sRGB Color Space Profile.icm"
LOGCOLORSPACEW gcsStockColorSpace = {
LCS_SIGNATURE,
0x400,
sizeof(LOGCOLORSPACEW),
LCS_CALIBRATED_RGB,
LCS_GM_IMAGES,
{
{0x000006b91,0x000003db8,0x00000070e},
{0x000005793,0x00000a9ba,0x000001bf4},
{0x0000038aa,0x00000188e,0x000012888}
},
0x23333, // 2.2
0x23333, // 2.2
0x23333, // 2.2
0};
#define MAX_COLORTABLE 256
//
// iIcmControlFlags
//
#define ICM_CONTROL_WIN95_COLORSPACE 0x00010000 // Win95 compatible colorspace
//
// Misc. macros
//
#define ALIGN_DWORD(nBytes) (((nBytes) + 3) & ~3)
//
// ICM supports output color mode (originally come from ICM.H)
//
#define BM_RGBTRIPLETS 0x0002
#define BM_xRGBQUADS 0x0008
#define BM_xBGRQUADS 0x0010
#define BM_CMYKQUADS 0x0020
#define BM_KYMCQUADS 0x0305
//
// ICM modes list
//
// if (IS_HOST_ICM(pdca->lIcmMode))
// {
// if (pdca->hcmXform)
// {
// if (IS_CMYK_COLOR(pdca->lIcmMode))
// {
// Host ICM ON, CMYK color mode.
// With CMYK color mode, we should have valid color transform.
// }
// else
// {
// Host ICM ON, RGB color mode.
// }
// }
// else
// {
// Host ICM ON, RGB color mode,
// But no color translation because src == dst color space.
// }
// }
// else if (IS_DEVICE_ICM(pdca->lIcmMode))
// {
// Device ICM ON.
// }
// else if (IS_OUTSIDEDC_ICM(pdca->lIcmMode))
// {
// Application ICM ON.
// }
//
/******************************Public*Routine******************************\
* GreCreateColorSpace
*
* Arguments:
*
* Return Value:
*
* History:
*
* 9/25/1996 Mark Enstrom [marke]
*
\**************************************************************************/
HCOLORSPACE
GreCreateColorSpace(
PLOGCOLORSPACEEXW pLogColorSpaceEx
)
{
ICMAPI(("GreCreateColorSpace\n"));
HCOLORSPACE hRet = NULL;
PCOLORSPACE pColorSpace;
//
// Check the validation of this color space.
//
if ((pLogColorSpaceEx->lcsColorSpace.lcsSignature != LCS_SIGNATURE) ||
(pLogColorSpaceEx->lcsColorSpace.lcsVersion != 0x400) ||
(pLogColorSpaceEx->lcsColorSpace.lcsSize != sizeof(LOGCOLORSPACEW)))
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return (NULL);
}
//
// Allocate COLORSPACE object.
//
pColorSpace = (PCOLORSPACE) ALLOCOBJ(sizeof(COLORSPACE), ICMLCS_TYPE, FALSE);
if (pColorSpace == (PCOLORSPACE)NULL)
{
WARNING("bCreateColorSpace failed memory allocation\n");
}
else
{
//
// Register LOGCOLORSPACE handle.
//
hRet = (HCOLORSPACE)HmgInsertObject(
pColorSpace,
HMGR_ALLOC_ALT_LOCK,
ICMLCS_TYPE);
if (hRet)
{
//
// Copy LOGCOLORSPACE into COLORSPACE object.
//
pColorSpace->lcsSignature(pLogColorSpaceEx->lcsColorSpace.lcsSignature);
pColorSpace->lcsVersion(pLogColorSpaceEx->lcsColorSpace.lcsVersion);
pColorSpace->lcsSize(pLogColorSpaceEx->lcsColorSpace.lcsSize);
pColorSpace->lcsCSType(pLogColorSpaceEx->lcsColorSpace.lcsCSType);
pColorSpace->lcsIntent(pLogColorSpaceEx->lcsColorSpace.lcsIntent);
pColorSpace->vSETlcsEndpoints(&(pLogColorSpaceEx->lcsColorSpace.lcsEndpoints));
pColorSpace->lcsGammaRed(pLogColorSpaceEx->lcsColorSpace.lcsGammaRed);
pColorSpace->lcsGammaGreen(pLogColorSpaceEx->lcsColorSpace.lcsGammaGreen);
pColorSpace->lcsGammaBlue(pLogColorSpaceEx->lcsColorSpace.lcsGammaBlue);
pColorSpace->vSETlcsFilename((PWCHAR)&(pLogColorSpaceEx->lcsColorSpace.lcsFilename[0]),MAX_PATH);
pColorSpace->lcsExFlags(pLogColorSpaceEx->dwFlags);
//
// Decrement color space handle which increment at creation time.
//
DEC_SHARE_REF_CNT(pColorSpace);
ICMMSG(("GreCreateColorSpace():Object %x: ref. count = %d\n",
hRet,HmgQueryAltLock((HOBJ)hRet)));
}
else
{
FREEOBJ(pColorSpace,ICMLCS_TYPE);
}
}
return(hRet);
}
/******************************Public*Routine******************************\
*
* Routine Name
*
* NtGdiCreateColorSpace
*
* Routine Description:
*
* Create a color space object - stub
*
* Arguments:
*
* pLogColorSpace - Logical Color space passed in. This will be used as the
* user-mode visible protion of this object
*
* Return Value:
*
* Handle to ColorSpace object or NULL on failure
*
\**************************************************************************/
HANDLE
APIENTRY
NtGdiCreateColorSpace(
PLOGCOLORSPACEEXW pLogColorSpaceEx
)
{
ICMAPI(("NtGdiCreateColorSpace\n"));
HANDLE hRet = NULL;
BOOL bStatus = TRUE;
LOGCOLORSPACEEXW tmpLcsEx;
__try
{
ProbeForRead(pLogColorSpaceEx,sizeof(LOGCOLORSPACEEXW),sizeof(ULONG));
RtlCopyMemory(&tmpLcsEx,pLogColorSpaceEx,sizeof(LOGCOLORSPACEEXW));
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
bStatus = FALSE;
}
if (bStatus)
{
hRet = (HANDLE)GreCreateColorSpace(&tmpLcsEx);
}
return(hRet);
}
/******************************Public*Routine******************************\
* bDeleteColorSpace
*
* Arguments:
*
* Return Value:
*
* History:
*
* 9/20/1996 Mark Enstrom [marke]
*
\**************************************************************************/
BOOL
bDeleteColorSpace(
HCOLORSPACE hColorSpace
)
{
ICMAPI(("bDeleteColorSpace\n"));
BOOL bRet = FALSE;
PCOLORSPACE pColorSpace;
if (DIFFHANDLE(hColorSpace,ghStockColorSpace))
{
ICMMSG(("bDeleteColorSpace():Object %x: ref. count = %d\n",
hColorSpace,HmgQueryAltLock((HOBJ)hColorSpace)));
//
// Try to remove handle from hmgr. This will fail if the color space
// is locked down on any threads or if it has been marked global or
// un-deleteable.
//
pColorSpace = (PCOLORSPACE)HmgRemoveObject(
(HOBJ)hColorSpace,
0,
0,
TRUE,
ICMLCS_TYPE);
if (pColorSpace != (PCOLORSPACE)NULL)
{
FREEOBJ(pColorSpace,ICMLCS_TYPE);
bRet = TRUE;
}
else
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
WARNING("Couldn't remove COLORSPACE object");
}
}
else
{
//
// Under Win31 deleting stock objects returns True.
//
bRet = TRUE;
}
return(bRet);
}
/******************************Public*Routine******************************\
* NtGdiDeleteColorSpace
*
* Routine Description:
*
* Delete a color space object
*
* Arguments:
*
* hColorSpace - Handle of Logical Color Space to delete
*
* Return Value:
*
* BOOL status
*
\**************************************************************************/
BOOL
APIENTRY
NtGdiDeleteColorSpace(
HANDLE hColorSpace
)
{
ICMAPI(("NtGdiDeleteColorSpace\n"));
//
// Delete ColorSpace
//
return(bDeleteColorSpace((HCOLORSPACE)hColorSpace));
}
/******************************Public*Routine******************************\
*
* Routine Name
*
* NtGdiSetColorSpace
*
* Routine Description:
*
* Set Color Space for DC
*
* Arguments:
*
* hdc - handle of dc
* hColorSpace - handle of color space
*
* Return Value:
*
* BOOL Status
*
\**************************************************************************/
BOOL
APIENTRY
NtGdiSetColorSpace(
HDC hdc,
HCOLORSPACE hColorSpace
)
{
BOOL bReturn = FALSE;
ICMAPI(("NtGdiSetColorSpace\n"));
//
// validate the DC
//
XDCOBJ dco(hdc);
if (dco.bValid())
{
//
// is it a different colorspace
//
if (DIFFHANDLE(hColorSpace,dco.pdc->hColorSpace()))
{
//
// now validate HColorSpace
//
COLORSPACEREF ColorSpaceSel(hColorSpace);
if (ColorSpaceSel.bValid())
{
//
// dec ref count of old color space.
//
DEC_SHARE_REF_CNT((PCOLORSPACE)dco.pdc->pColorSpace());
ICMMSG(("NtGdiSetColorSpace():Old Object %x: ref. count = %d\n",
dco.pdc->hColorSpace(),HmgQueryAltLock((HOBJ)dco.pdc->hColorSpace())));
//
// set color space handle in dc
//
dco.pdc->hColorSpace(hColorSpace);
dco.pdc->pColorSpace(ColorSpaceSel.pColorSpace());
//
// up the ref count of the selected color space.
//
INC_SHARE_REF_CNT(ColorSpaceSel.pColorSpace());
ICMMSG(("NtGdiSetColorSpace():New Object %x: ref. count = %d\n",
dco.pdc->hColorSpace(),HmgQueryAltLock((HOBJ)dco.pdc->hColorSpace())-1));
/* -1: because of COLORSPACEREF locks this, then actuall number is N-1 */
//
// We are succeed to select.
//
bReturn = TRUE;
}
else
{
//
// keep color space as same as current.
//
}
}
else
{
//
// Same handle has been selected.
//
bReturn = TRUE;
}
dco.vUnlockFast();
}
return(bReturn);
}
#ifdef _IA64_
//
// There is a compiler bug that shows up in this function.
// Disable optimization until it is fixed.
//
#pragma optimize( "", off )
#endif
/******************************Public*Routine******************************\
* GreSetICMMode()
*
* History:
*
* Write it:
* 27-Jan-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
GreSetICMMode(
HDC hdc,
ULONG nCommand,
ULONG iReqData
)
{
ICMMSG(("GreSetICMMode\n"));
BOOL bRet = TRUE;
XDCOBJ dco(hdc);
if(!dco.bValid())
{
WARNING("GreSetICMMode(): Invalid DC\n");
return (FALSE);
}
DEVLOCKOBJ dlo;
if (dlo.bLock(dco))
{
ULONG NewReqMode, OldReqMode;
ULONG NewMode,OldMode;
ULONG NewColorType, OldColorType;
PDEVOBJ po(dco.hdev());
//
// Check target surface
//
SURFACE *pSurface = dco.pSurface();
//
// Get current ICM destination color type
//
NewColorType = OldColorType = GET_COLORTYPE(dco.pdc->lIcmMode());
//
// Get current ICM mode.
//
NewMode = OldMode = ICM_MODE(dco.pdc->lIcmMode());
//
// Get previous requested mode.
//
NewReqMode = OldReqMode = REQ_ICM_MODE(dco.pdc->lIcmMode());
switch (nCommand)
{
case ICM_SET_MODE:
ICMMSG(("GreSetICMMode():Update ICM mode -> %x\n",iReqData));
//
// iReqData should be one of these.
//
switch (iReqData)
{
case REQ_ICM_OFF:
//
// Turn off ICM.
//
// (should preserve alt mode)
//
NewReqMode = REQ_ICM_OFF;
NewMode = (ICM_ALT_MODE(dco.pdc->lIcmMode()) | DC_ICM_OFF);
break;
case REQ_ICM_HOST:
case REQ_ICM_DEVICE:
case REQ_ICM_OUTSIDEDC:
//
// Update new requested mode.
//
NewReqMode = iReqData;
//
// Figure out ICM mode from requested mode.
//
NewMode = ICM_REQ_TO_MODE(NewReqMode);
//
// We don't allow "ICM on Device" with non-DDB surface.
//
if (IS_ICM_DEVICE_REQUESTED(NewReqMode))
{
if (po.bValid())
{
//
// ICM on Device is requested, check driver's capacity.
//
if (po.flGraphicsCaps() & GCAPS_ICM)
{
//
// DC is device DC. (not, info or memory)
//
if (dco.dctp() != DCTYPE_MEMORY)
{
//
// OK, we can enable device ICM.
//
}
else
{
ICMMSG(("NtGdiSetIcmMode():DC is memory DC, but device icm requested\n"));
//
// Enable host ICM instead.
//
NewMode = DC_ICM_HOST;
}
}
else
{
WARNING("GreSetICMMode(): ICM on Device is requested, but driver could not.\n");
//
// Oh!, device driver does *not* support ICM on device or driver.
// Turn on ICM on HOST.
//
NewMode = DC_ICM_HOST;
}
}
else
{
//
// we will keep current mode. and return false.
//
bRet = FALSE;
}
}
if (bRet)
{
//
// Should preserve alt mode through ICM mode change.
//
NewMode |= ICM_ALT_MODE(dco.pdc->lIcmMode());
}
break;
default:
//
// Unknown request mode.
//
bRet = FALSE;
}
break;
case ICM_SET_CALIBRATE_MODE:
ICMMSG(("GreSetICMMode():Update ICM device calibrate -> %x\n",iReqData));
if (iReqData)
{
NewMode |= DC_ICM_DEVICE_CALIBRATE;
}
else
{
NewMode &= ~DC_ICM_DEVICE_CALIBRATE;
}
break;
case ICM_SET_COLOR_MODE:
case ICM_CHECK_COLOR_MODE:
ICMMSG(("GreSetICMMode():Update ICM colortype -> %x\n",iReqData));
//
// iReqData should be one of these.
//
switch (iReqData)
{
case BM_xRGBQUADS:
case BM_xBGRQUADS:
// Clear lazy color correction.
//
// NewMode &= ~DC_ICM_LAZY_CORRECTION;
//
// Note: bitmap might have color which expected to corrected later.
//
// Set color type as RGB.
//
NewColorType = DC_ICM_RGB_COLOR;
break;
case BM_CMYKQUADS:
case BM_KYMCQUADS:
if (po.bValid())
{
//
// Set color type as CMYK.
//
NewColorType = DC_ICM_CMYK_COLOR;
//
// Check device driver could handle CMYK color or not
//
if (po.flGraphicsCaps() & GCAPS_CMYKCOLOR)
{
//
// We don't allow "CMYK color" with non-DDB surface.
//
if (dco.dctp() != DCTYPE_MEMORY)
{
//
// We can go with CMYK color.
//
}
else
{
ICMMSG(("NtGdiSetIcmMode():Enable lazy color correction\n"));
//
// Memory DC can only hold RGB based color,
// so RGB to CMYK color translation will happen when
// apps does BitBlt onto real device surface from this
// compatible surface.
//
NewMode |= DC_ICM_LAZY_CORRECTION;
NewColorType = DC_ICM_RGB_COLOR;
}
}
else
{
//
// Driver could not handle, ICM could not turn on.
//
WARNING("GreSetICMMode(): Device driver could not handle CMYK color\n");
//
// we will keep current code. and return false.
//
bRet = FALSE;
}
}
else
{
bRet = FALSE;
}
break;
default:
ICMMSG(("GreSetICMMode():Unknown color type\n"));
//
// Unknown color mode.
//
bRet = FALSE;
}
break;
default :
ICMMSG(("GreSetICMMode():Unknown command\n"));
bRet = FALSE;
break;
}
if (bRet && (nCommand != ICM_CHECK_COLOR_MODE))
{
if ((OldMode != NewMode) || (OldReqMode != NewReqMode) || (OldColorType != NewColorType))
{
//
// Update ICM mode. (we will keep original request mode and colortype).
//
// kernel side.
//
dco.pdc->lIcmMode(NewColorType|NewReqMode|NewMode);
// and, client side (need to preserve usermode only flags).
//
ULONG UserModeFlag = (dco.pdc->lIcmModeClient() & DC_ICM_USERMODE_FLAG);
dco.pdc->lIcmModeClient(NewColorType|NewReqMode|NewMode|UserModeFlag);
if (OldMode != NewMode)
{
SURFACE *pSurfDest = dco.pSurface();
XEPALOBJ palDestDC(dco.ppal());
if (palDestDC.bValid())
{
//
// update all drawing state
//
palDestDC.vUpdateTime();
if (pSurfDest != NULL)
{
XEPALOBJ palDestSurf(pSurfDest->ppal());
if (palDestSurf.bValid())
{
//
// update palette.
//
palDestSurf.vUpdateTime();
}
}
}
}
ICMMSG(("NtGdiSetIcmMode():ICM mode were changed to %x\n",dco.pdc->lIcmMode()));
}
else
{
ICMMSG(("NtGdiSetIcmMode():ICM mode were NOT changed!\n"));
}
}
}
else
{
//
// Fail to enable ICM for fullscreen DC.
//
}
dco.vUnlockFast();
return(bRet);
}
#ifdef _IA64_
#pragma optimize( "", on )
#endif
/******************************Public*Routine******************************\
* NtGdiSetIcmMode
*
* ICM mode changed, update all times
*
* History:
*
* Write it:
* 27-Jan-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL WINAPI
NtGdiSetIcmMode(
HDC hdc,
ULONG nCommand,
ULONG ulMode
)
{
ICMMSG(("NtGdiSetIcmMode\n"));
return(GreSetICMMode(hdc,nCommand,ulMode));
}
/******************************Public*Routine******************************\
* GreCreateColorTransform
*
* Arguments:
*
* Return Value:
*
* History:
*
* Write it:
* 27-Jan-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
HANDLE
GreCreateColorTransform(
HDC hdc,
LPLOGCOLORSPACEW pLogColorSpaceW,
PVOID pvSrcProfile,
ULONG cjSrcProfile,
PVOID pvDstProfile,
ULONG cjDstProfile,
PVOID pvTrgProfile,
ULONG cjTrgProfile
)
{
HANDLE hRet = NULL;
ICMAPI(("GreCreateColorTransform\n"));
//
// Check the validation of this color space.
//
if ((pLogColorSpaceW->lcsSignature != LCS_SIGNATURE) ||
(pLogColorSpaceW->lcsVersion != 0x400) ||
(pLogColorSpaceW->lcsSize != sizeof(LOGCOLORSPACEW)))
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return (NULL);
}
XDCOBJ dcoDst(hdc);
if (dcoDst.bValid())
{
if (!dcoDst.pdc->bInFullScreen())
{
COLORTRANSFORMOBJ CXFormObj;
//
// Create new color transform object.
//
hRet = CXFormObj.hCreate(dcoDst,
pLogColorSpaceW,
pvSrcProfile,
cjSrcProfile,
pvDstProfile,
cjDstProfile,
pvTrgProfile,
cjTrgProfile);
if (!hRet)
{
WARNING("GreCreateColorTransform fail to allocate object\n");
SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
}
}
else
{
WARNING("GreCreateColorTransform(): hdc is full screen\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
}
dcoDst.vUnlockFast();
}
else
{
WARNING("GreCreateColorTransform(): hdc is invalid\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
}
return (hRet);
}
/******************************Public*Routine******************************\
* NtGdiCreateColorTransform
*
* Arguments:
*
* Return Value:
*
* History:
*
* Write it:
* 27-Jan-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
HANDLE WINAPI
NtGdiCreateColorTransform(
HDC hdc,
LPLOGCOLORSPACEW pLogColorSpaceW,
PVOID pvSrcProfile,
ULONG cjSrcProfile,
PVOID pvDestProfile,
ULONG cjDestProfile,
PVOID pvTargetProfile,
ULONG cjTargetProfile
)
{
HANDLE hColorTransform = NULL;
LOGCOLORSPACEW KmLogColorSpaceW;
HANDLE hSecureSource = NULL;
HANDLE hSecureDestination = NULL;
HANDLE hSecureTarget = NULL;
PVOID pKmSrcProfile = NULL;
PVOID pKmDstProfile = NULL;
PVOID pKmTrgProfile = NULL;
BOOL bError = FALSE;
ICMAPI(("NtGdiCreateColorTransform\n"));
__try
{
if (pLogColorSpaceW)
{
//
// Copy LOGCOLORSPACE
//
ProbeForRead(pLogColorSpaceW,sizeof(LOGCOLORSPACEW),sizeof(ULONG));
RtlCopyMemory(&KmLogColorSpaceW,pLogColorSpaceW,sizeof(LOGCOLORSPACEW));
}
else
{
//
// We need LOGCOLORSPACE, at least.
//
return (NULL);
}
//
// Lock down client side mapped files.
//
if (pvSrcProfile && cjSrcProfile)
{
ProbeForRead(pvSrcProfile,cjSrcProfile,sizeof(BYTE));
hSecureSource = MmSecureVirtualMemory(pvSrcProfile,cjSrcProfile,PAGE_READONLY);
if (hSecureSource)
{
pKmSrcProfile = pvSrcProfile;
}
else
{
WARNING("NtGdiCreateColorTransform():Fail to lock source profile\n");
bError = TRUE;
}
}
if (pvDestProfile && cjDestProfile)
{
ProbeForRead(pvDestProfile,cjDestProfile,sizeof(BYTE));
hSecureDestination = MmSecureVirtualMemory(pvDestProfile,cjDestProfile,PAGE_READONLY);
if (hSecureDestination)
{
pKmDstProfile = pvDestProfile;
}
else
{
WARNING("NtGdiCreateColorTransform():Fail to lock destination profile\n");
bError = TRUE;
}
}
if (pvTargetProfile && cjTargetProfile)
{
ProbeForRead(pvTargetProfile,cjTargetProfile,sizeof(BYTE));
hSecureTarget = MmSecureVirtualMemory(pvTargetProfile,cjTargetProfile,PAGE_READONLY);
if (hSecureTarget)
{
pKmTrgProfile = pvTargetProfile;
}
else
{
WARNING("NtGdiCreateColorTransform():Fail to lock target profile\n");
bError = TRUE;
}
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("NtGdiCreateColorTransform(): Fail to lock usermode parameters\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
bError = TRUE;
}
if (!bError)
{
//
// Create Color Transform.
//
hColorTransform = GreCreateColorTransform(hdc,
&KmLogColorSpaceW,
pKmSrcProfile,
cjSrcProfile,
pKmDstProfile,
cjDestProfile,
pKmTrgProfile,
cjTargetProfile);
if (!hColorTransform)
{
WARNING("GreCreateColorTransform() failed\n");
}
}
if (hSecureSource)
{
MmUnsecureVirtualMemory(hSecureSource);
}
if (hSecureDestination)
{
MmUnsecureVirtualMemory(hSecureDestination);
}
if (hSecureTarget)
{
MmUnsecureVirtualMemory(hSecureTarget);
}
return (hColorTransform);
}
/******************************Public*Routine******************************\
* GreDeleteColorTransform
*
* Arguments:
*
* Return Value:
*
* History:
*
* Feb.21.1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
GreDeleteColorTransform(
HDC hdc,
HANDLE hColorTransform
)
{
ICMAPI(("GreDeleteColorTransform\n"));
BOOL bRet = FALSE;
//
// Lock DC, call driver to delete color transform.
// if the driver doesn't support this call, this is an
// error
//
XDCOBJ dcoDst(hdc);
//
// Validate the destination DC.
//
if (dcoDst.bValid())
{
if (dcoDst.pdc->bInFullScreen())
{
WARNING("GreCreateColorTransform(): hdc is full screen\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
}
else
{
COLORTRANSFORMOBJ CXFormObj(hColorTransform);
if (CXFormObj.bValid())
{
//
// Delete it
//
bRet = CXFormObj.bDelete(dcoDst);
}
}
dcoDst.vUnlock();
}
else
{
WARNING1("ERORR GreGdiDeleteColorTransform called on invalid DC\n");
}
return(bRet);
}
/******************************Public*Routine******************************\
* NtGdiDeleteColorTransform
*
* Arguments:
*
* Return Value:
*
* History:
*
* 5-Aug-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL
NtGdiDeleteColorTransform(
HDC hdc,
HANDLE hColorTransform
)
{
ICMAPI(("NtGdiDeleteColorTransform\n"));
return (GreDeleteColorTransform(hdc,hColorTransform));
}
/******************************Public*Routine******************************\
* GreCheckBitmapBits
*
* Arguments:
*
* Return Value:
*
* History:
*
* Write it:
* 27-Jan-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
GreCheckBitmapBits(
HDC hdc,
HANDLE hColorTransform,
DEVBITMAPINFO *pdbmi,
PVOID pvBits,
PBYTE paResults)
{
ICMAPI(("GreCheckBitmapBits\n"));
BOOL bRet = FALSE;
XDCOBJ dco(hdc);
if (dco.bValid())
{
DEVLOCKOBJ dlo;
if (dlo.bLock(dco))
{
PDEVOBJ po(dco.hdev());
if (po.bValid())
{
if (PPFNVALID(po, IcmCheckBitmapBits))
{
//
// We need to pass driver's transform handle to driver.
//
COLORTRANSFORMOBJ CXFormObj(hColorTransform);
if (CXFormObj.bValid())
{
SURFMEM SurfDimoTemp;
SurfDimoTemp.bCreateDIB(pdbmi,pvBits);
if (SurfDimoTemp.bValid())
{
//
// Call device driver.
//
bRet = (*PPFNDRV(po, IcmCheckBitmapBits))(
po.dhpdev(),
CXFormObj.hGetDeviceColorTransform(),
SurfDimoTemp.pSurfobj(),
paResults);
}
}
}
else
{
WARNING("GreCheckBitmapBits called on device that does not support call\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
}
}
}
dco.vUnlockFast();
}
return (bRet);
}
/******************************Public*Routine******************************\
* NtGdiCheckBitmapBits
*
* Arguments:
*
* Return Value:
*
* History:
*
* Write it:
* 27-Jan-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL WINAPI
NtGdiCheckBitmapBits(
HDC hdc,
HANDLE hColorTransform,
PVOID pvBits,
ULONG bmFormat,
DWORD dwWidth,
DWORD dwHeight,
DWORD dwStride,
PBYTE paResults)
{
ICMAPI(("NtGdiCheckBitmapBits\n"));
ULONG ulBytesPerPixel;
ULONG ulSizeInByte;
ULONG ulSizeForResult;
HANDLE hSecureBits = NULL;
HANDLE hSecureRets = NULL;
DEVBITMAPINFO dbmi;
BOOL bRet = TRUE;
//
// limitted support.
//
if (
(bmFormat != BM_RGBTRIPLETS) || (dwHeight != 1)
)
{
WARNING("NtGdiCheckBitmapBits(): Format is not supported, yet\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// So, far, we only support RGBTRIPLE format, and n x 1 bitmap.
//
ulBytesPerPixel = sizeof(RGBTRIPLE);
ulSizeInByte = ALIGN_DWORD(dwWidth * ulBytesPerPixel);
ulSizeForResult = dwWidth;
//
// dwStride should be equal to ulSizeInByte,
// because we should only has 1 height bitmap.
//
if (dwStride != ulSizeInByte)
{
WARNING("NtGdiCheckBitmapBits(): Format is not supported, yet\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// Fill up DEVBITMAPINFO
//
dbmi.iFormat = BMF_24BPP;
dbmi.cxBitmap = dwWidth;
dbmi.cyBitmap = dwHeight;
dbmi.cjBits = ulSizeInByte;
dbmi.hpal = NULL;
dbmi.fl = 0;
//
// Lock down user mode memory for bitmap and result buffer
//
__try
{
ProbeForRead(pvBits,ulSizeInByte,sizeof(DWORD));
ProbeForRead(paResults,ulSizeForResult,sizeof(BYTE));
hSecureBits = MmSecureVirtualMemory(pvBits, ulSizeInByte, PAGE_READONLY);
hSecureRets = MmSecureVirtualMemory(paResults, ulSizeForResult, PAGE_READWRITE);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("NtGdiCheckBitmapBits():Error in capture usermode memory\n");
bRet = FALSE;
}
if (bRet && hSecureBits && hSecureRets)
{
bRet = GreCheckBitmapBits(hdc,hColorTransform,
&dbmi,pvBits,
(PBYTE)paResults);
}
if (hSecureBits)
{
MmUnsecureVirtualMemory(hSecureBits);
}
if (hSecureRets)
{
MmUnsecureVirtualMemory(hSecureRets);
}
return (bRet);
}
/******************************Public*Routine******************************\
* NtGdiColorCorrectPalette
*
* If this is a query operation then:
* If the DC has ICM enabled NON_DEVICE and
* the palette is not already color corrected then
* Get the logical palette entries and return to app in array provided
*
*
* If this is a set operation and the DC has ICM_NON_DEVICE and the palette
* is ok then set the palette entries.
*
* If this is a set operation and the DC is DEVICE then do nothing
* --Maybe call device driver if it exports ICM calls
*
*
* NOTE: if hpalette is moved to dcattr, then this routine can be
* eliminated and done byt get/set palette entries from user mode
*
* Arguments:
*
* Return Value:
*
* History:
*
* 15-Aug-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
ULONG
APIENTRY
NtGdiColorCorrectPalette(
HDC hdc,
HPALETTE hpal,
ULONG FirstEntry,
ULONG NumberOfEntries,
PALETTEENTRY *ppalEntry,
ULONG Command)
{
ICMAPI(("NtGdiColorCorrectPalette\n"));
DCOBJ dcoDst(hdc);
EPALOBJ pal((HPALETTE) hpal);
ULONG ulRet = 0;
if (dcoDst.bValid() && pal.bValid())
{
if ((NumberOfEntries == 0) ||
(NumberOfEntries > pal.cEntries()) ||
(FirstEntry > pal.cEntries()) ||
((FirstEntry + NumberOfEntries) > pal.cEntries()))
{
WARNING("NtGdiColorCorrectPalette(): Invalid parameter\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return(ulRet);
}
if (IS_ICM_HOST(dcoDst.pdc->lIcmMode()))
{
if (Command == ColorPaletteQuery)
{
//
// check palette for already colorcorrected flag
//
__try
{
ProbeForWrite(ppalEntry,sizeof(PALETTEENTRY) * NumberOfEntries,sizeof(PALETTEENTRY));
//
// Get palette entries.
//
ulRet = pal.ulGetEntries(FirstEntry, NumberOfEntries, ppalEntry, FALSE);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("NtGdiColorCorrectPalette():Error in GetEntries\n");
ulRet = 0;
}
}
else if (Command == ColorPaletteSet)
{
__try
{
ProbeForRead(ppalEntry,sizeof(PALETTEENTRY) * NumberOfEntries,sizeof(PALETTEENTRY));
//
// Set palette entries.
//
ulRet = pal.ulSetEntries(FirstEntry, NumberOfEntries, ppalEntry);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("NtGdiColorCorrectPalette():Error in SetEntries\n");
ulRet = 0;
}
}
}
else
{
WARNING("NtGdiColorCorrectPalette(): Invalid ICM mode\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
}
}
else
{
WARNING("NtGdiColorCorrectPalette(): Invalid hdc or hpal\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
}
return(ulRet);
}
/******************************Public*Routine******************************\
* GreGetDeviceGammaRampInternal
*
* History:
*
* Wrote it:
* 28.Jun.2000 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
GreGetDeviceGammaRampInternal(
HDEV hdev,
LPVOID lpGammaRamp
)
{
BOOL bRet = FALSE;
PDEVOBJ po(hdev);
//
// GetDeviceGammaRamp is only for display device.
//
if (po.bValid() && po.bDisplayPDEV())
{
//
// Check color depth is not less than 8 bpp (need 256 color at least)
//
if ((po.iDitherFormat() == BMF_8BPP) ||
(po.iDitherFormat() == BMF_16BPP) ||
(po.iDitherFormat() == BMF_24BPP) ||
(po.iDitherFormat() == BMF_32BPP))
{
//
// Check this PDEV has thier own GammaTable or not.
//
if (po.bHasGammaRampTable())
{
ICMMSG(("GreGetDeviceGammaRamp(): Use PDEV's GammaRamp Table\n"));
//
// Copy from PDEV's GammaRamp buffer.
//
RtlCopyMemory(lpGammaRamp,po.pvGammaRampTable(),MAX_COLORTABLE * sizeof(WORD) * 3);
}
else
{
ICMMSG(("GreGetDeviceGammaRamp(): Use default GammaRamp Table\n"));
//
// Fill up with ident. GammaRamp
//
LPWORD lpRed = (LPWORD)lpGammaRamp;
LPWORD lpGreen = (LPWORD)lpGammaRamp + MAX_COLORTABLE;
LPWORD lpBlue = (LPWORD)lpGammaRamp + MAX_COLORTABLE + MAX_COLORTABLE;
//
// Indent. GammaRamp is 0x0000 -> 0xFF00 for each R,G and B.
// And LOBYTE is 0, only HIBYTE has value from 0 to 0xFF.
//
for (UINT i = 0; i < MAX_COLORTABLE; i++)
{
lpRed[i] = lpGreen[i] = lpBlue[i] = (WORD)(i << 8);
}
}
//
// Filled up the buffer, return TRUE.
//
bRet = TRUE;
}
else
{
ICMMSG(("GreGetDeviceGammaRamp(): Surface is less than 8 bpp\n"));
}
}
else
{
ICMMSG(("GreGetDeviceGammaRamp(): DC might not be display\n"));
}
return (bRet);
}
/******************************Public*Routine******************************\
* GreGetDeviceGammaRamp
*
* History:
*
* Wrote it:
* 1.Apr.1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
GreGetDeviceGammaRamp(
HDC hdc,
LPVOID lpGammaRamp
)
{
ICMAPI(("GreGetDeviceGammaRamp\n"));
BOOL bRet = FALSE;
XDCOBJ dco(hdc);
if (dco.bValid())
{
//
// DC should not be info or meta DC.
//
if (dco.dctp() == DCTYPE_DIRECT)
{
DEVLOCKOBJ dlo;
if (dlo.bLock(dco))
{
bRet = GreGetDeviceGammaRampInternal(dco.hdev(),lpGammaRamp);
}
}
dco.vUnlockFast();
}
if (!bRet)
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
}
return (bRet);
}
/******************************Public*Routine******************************\
* NtGdiGetDeviceGammaRamp
*
* History:
*
* Wrote it:
* 1.Apr.1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
NtGdiGetDeviceGammaRamp(
HDC hdc,
LPVOID lpGammaRamp
)
{
ICMAPI(("NtGdiGetDeviceGammaRamp\n"));
BOOL bRet = FALSE;
if (lpGammaRamp)
{
HANDLE hSecure = NULL;
BOOL bError = FALSE;
__try
{
ProbeForWrite(lpGammaRamp, MAX_COLORTABLE * sizeof(WORD) * 3, sizeof(WORD));
hSecure = MmSecureVirtualMemory(lpGammaRamp, MAX_COLORTABLE * sizeof(WORD) * 3, PAGE_READWRITE);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("NtGdiGetDeviceGammaRamp: Fail to capture usermode buffer\n");
bError = TRUE;
}
if ((bError == FALSE) && hSecure)
{
bRet = GreGetDeviceGammaRamp(hdc,lpGammaRamp);
}
if (hSecure)
{
MmUnsecureVirtualMemory(hSecure);
}
}
else
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
}
return(bRet);
}
/******************************Public*Routine******************************\
* GreSetDeviceGammaRampInternal
*
* History:
*
* Wrote it:
* 1.Apr.1997 -by- Hideyuki Nagase [hideyukn]
* 2.Nov.1998 -by- Scott MacDonald [smac] Split it into two functions
\**************************************************************************/
BOOL
GreSetDeviceGammaRampInternal(
HDEV hdev,
LPVOID lpGammaRamp,
BOOL bDoRangeCheck
)
{
ICMAPI(("GreSetDeviceGammaRampInternal\n"));
BOOL bRet = FALSE;
PDEVOBJ po(hdev);
//
// GetDeviceGammaRamp is only for display device.
//
if (po.bValid() && po.bDisplayPDEV())
{
BOOL bUsePalette = FALSE;
BOOL bValidBPP = FALSE;
//
// Check color depth is not less than 8 bpp (need 256 color at least)
//
if ((po.iDitherFormat() == BMF_8BPP) ||
(po.iDitherFormat() == BMF_16BPP) ||
(po.iDitherFormat() == BMF_24BPP) ||
(po.iDitherFormat() == BMF_32BPP))
{
if ((PPFNVALID(po, IcmSetDeviceGammaRamp)) &&
(po.flGraphicsCaps2() & GCAPS2_CHANGEGAMMARAMP))
{
//
// Driver supports DrvSetDeviceGammaRamp()
//
bValidBPP = TRUE;
}
else
{
//
// Driver does not suppprt it, but we can sinulate it
// with palette only for 8 bpp case.
//
if ((po.iDitherFormat() == BMF_8BPP) && po.bIsPalManaged())
{
//
// For 8 bpp surface, we can adjust color via
// palette on device if palettalized device.
//
bUsePalette = TRUE;
bValidBPP = TRUE;
}
}
}
else
{
//
// Can not set GammaRamp for 1/4 bpp surface
//
}
//
// PDEV's bpp is suite for set GammaRamp ?
//
if (bValidBPP)
{
BOOL bNeedCallDriver = TRUE;
BOOL bDefaultGammaRamp = !bDoRangeCheck;
BOOL bSameGammaRamp = FALSE;
if (po.bHasGammaRampTable())
{
//
// If this PDEV is already has GammaRamp table, we will check
// this is same as the table what we are going to set.
//
if (RtlCompareMemory(po.pvGammaRampTable(),
lpGammaRamp,
MAX_COLORTABLE * sizeof(WORD) * 3)
== (MAX_COLORTABLE * sizeof(WORD) * 3))
{
//
// Same
//
bSameGammaRamp = TRUE;
}
}
if (bSameGammaRamp)
{
ICMMSG(("GreSetDeviceGammaRamp(): Same GammaRamp is already selected\n"));
//
// Same GammaRamp is already selected, nothing need to do.
//
bRet = TRUE;
}
else
{
//
// Scan the input GammaRamp to check within the range.
//
LPWORD lpRed = (LPWORD)lpGammaRamp;
LPWORD lpGreen = (LPWORD)lpGammaRamp + MAX_COLORTABLE;
LPWORD lpBlue = (LPWORD)lpGammaRamp + MAX_COLORTABLE + MAX_COLORTABLE;
INT iRange = (INT)(giIcmGammaRange);
//
// if we encounter any Gamma outside range, break!
//
for (UINT i = 0; ((i < MAX_COLORTABLE) && (bNeedCallDriver == TRUE)); i++)
{
UINT iAveGamma = i;
UINT iRed = (UINT)(lpRed[i] >> 8);
UINT iGreen = (UINT)(lpGreen[i] >> 8);
UINT iBlue = (UINT)(lpBlue[i] >> 8);
INT iRangeMax = (INT)(iAveGamma + iRange);
INT iRangeMin = (INT)(iAveGamma - iRange);
ICMMSG(("iRangeMax = %x:iRangeMix = %x:iRed = %x:iGreen = %x:iBlue = %x\n",
iRangeMax, iRangeMin,(INT)iRed,(INT)iGreen,(INT)iBlue));
if ((((INT)iRed < iRangeMin) || ((INT)iRed > iRangeMax) ||
((INT)iGreen < iRangeMin) || ((INT)iGreen > iRangeMax) ||
((INT)iBlue < iRangeMin) || ((INT)iBlue > iRangeMax)) &&
bDoRangeCheck)
{
//
// The Gamma is out of range, don't need call driver
//
bNeedCallDriver = FALSE;
}
//
// Check if the GammaRamp is ident. or not.
//
if (bDefaultGammaRamp &&
((lpRed[i] != (iAveGamma << 8)) ||
(lpGreen[i] != (iAveGamma << 8)) ||
(lpBlue[i] != (iAveGamma << 8))))
{
ICMMSG(("GreSetDeviceGammaRamp():Not ident. GammaRamp\n"));
bDefaultGammaRamp = FALSE;
}
}
if (bNeedCallDriver)
{
if (bUsePalette && bDefaultGammaRamp)
{
//
// If we will use palette, and GammaRamp are going to changed to
// default, we don't need to have GammaRamp table.
//
if (po.bHasGammaRampTable())
{
ICMMSG(("GreSetDeviceGammaRamp():Default GammaRamp (need update palette)\n"));
//
// The specified GammaRamp is ident., don't need to keep it.
//
po.bHasGammaRampTable(FALSE);
VFREEMEM(po.pvGammaRampTable());
po.pvGammaRampTable(NULL);
}
else
{
ICMMSG(("GreSetDeviceGammaRamp():Default GammaRamp (no palette call)\n"));
//
// If we don't have GammaRamp table in PDEV, it means
// we are in defult already. So don't need to call driver
// (= don't need to update palette.)
//
bNeedCallDriver = FALSE;
}
}
else
{
//
// Check this PDEV has thier own GammaTable or not.
//
if (!po.bHasGammaRampTable())
{
ICMMSG(("GreSetDeviceGammaRamp(): Allocate GammaRamp Table\n"));
//
// Allocate GammaRamp table for this PDEV
//
LPVOID pv = (LPVOID) PALLOCNOZ(MAX_COLORTABLE * sizeof(WORD) * 3,'mciG');
if (pv)
{
//
// Mark this PDEV has GammaTable.
//
po.pvGammaRampTable(pv);
po.bHasGammaRampTable(TRUE);
}
else
{
WARNING("GreSetDeviceGammaRamp():Fail to allocate GammaRamp table\n");
//
// Error, we don't need to call driver.
//
bNeedCallDriver = FALSE;
}
}
}
if (bNeedCallDriver)
{
if (po.bHasGammaRampTable())
{
ICMMSG(("GreSetDeviceGammaRamp():Updating GammaRamp Table in PDEV...\n"));
//
// Save new GammaRamp into PDEV.
//
RtlCopyMemory(po.pvGammaRampTable(),lpGammaRamp,
MAX_COLORTABLE * sizeof(WORD) * 3);
}
//
// Update GammaRamp on device using PDEV's GammaRamp Table.
//
bRet = UpdateGammaRampOnDevice(po.hdev(),TRUE);
if (bDefaultGammaRamp && po.bHasGammaRampTable())
{
ICMMSG(("GreSetDeviceGammaRamp():Default GammaRamp is setted (non-palette)\n"));
//
// The specified GammaRamp is ident., don't need to keep it.
//
po.bHasGammaRampTable(FALSE);
VFREEMEM(po.pvGammaRampTable());
po.pvGammaRampTable(NULL);
}
}
else
{
//
// Fail... couldn't call driver and return false.
//
bRet = FALSE;
}
}
else
{
ICMMSG(("GreSetDeviceGammaRamp(): GammaRamp is out of range\n"));
}
}
}
else
{
ICMMSG(("GreSetDeviceGammaRamp(): Surface/Driver does not support loadable GammaRamp\n"));
}
}
return (bRet);
}
/******************************Public*Routine******************************\
* GreSetDeviceGammaRamp
*
* History:
*
* Wrote it:
* 1.Apr.1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
GreSetDeviceGammaRamp(
HDC hdc,
LPVOID lpGammaRamp,
BOOL bDoRangeCheck
)
{
ICMAPI(("GreSetDeviceGammaRamp\n"));
BOOL bRet = FALSE;
XDCOBJ dco(hdc);
if (dco.bValid())
{
//
// DC should not be info or meta DC.
//
if (dco.dctp() == DCTYPE_DIRECT)
{
DEVLOCKOBJ dlo;
if (dlo.bLock(dco))
{
bRet = GreSetDeviceGammaRampInternal(dco.hdev(),
lpGammaRamp,
bDoRangeCheck);
}
}
dco.vUnlockFast();
}
if (!bRet)
{
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
}
return (bRet);
}
/******************************Public*Routine******************************\
* NtGdiSetDeviceGammaRamp
*
* History:
*
* Wrote it:
* 1.Apr.1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
NtGdiSetDeviceGammaRamp(
HDC hdc,
LPVOID lpGammaRamp
)
{
ICMAPI(("NtGdiSetDeviceGammaRamp\n"));
BOOL bRet = FALSE;
if (lpGammaRamp)
{
HANDLE hSecure = NULL;
BOOL bError = FALSE;
__try
{
ProbeForRead(lpGammaRamp, MAX_COLORTABLE * sizeof(WORD) * 3, sizeof(WORD));
hSecure = MmSecureVirtualMemory(lpGammaRamp, MAX_COLORTABLE * sizeof(WORD) * 3, PAGE_READONLY);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("NtGdiSetDeviceGammaRamp: Fail to capture usermode buffer\n");
bError = TRUE;
}
if ((bError == FALSE) && hSecure)
{
bRet = GreSetDeviceGammaRamp(hdc,lpGammaRamp,TRUE);
}
if (hSecure)
{
MmUnsecureVirtualMemory(hSecure);
}
}
else
{
SAVE_ERROR_CODE(ERROR_INVALID_HANDLE);
}
return(bRet);
}
/******************************Public*Routine******************************\
* cjGetLogicalColorSpace
*
* Arguments:
*
* Return Value:
*
* History:
*
* 9/20/1996 Mark Enstrom [marke]
*
\**************************************************************************/
INT
cjGetLogicalColorSpace(
HANDLE hColorSpace,
INT cjBuffer,
LPVOID lpvBuffer
)
{
ICMAPI(("cjGetLogicalColorSpace\n"));
INT cRet = 0;
if (cjBuffer >= sizeof(LOGCOLORSPACEW) && (lpvBuffer != NULL))
{
COLORSPACEREF ColorSpace((HCOLORSPACE)hColorSpace);
if (ColorSpace.bValid())
{
LPLOGCOLORSPACEW lpLogColorSpace = (LPLOGCOLORSPACEW)lpvBuffer;
lpLogColorSpace->lcsSignature = ColorSpace.pColorSpace()->lcsSignature();
lpLogColorSpace->lcsVersion = ColorSpace.pColorSpace()->lcsVersion();
lpLogColorSpace->lcsSize = ColorSpace.pColorSpace()->lcsSize();
lpLogColorSpace->lcsCSType = ColorSpace.pColorSpace()->lcsCSType();
lpLogColorSpace->lcsIntent = ColorSpace.pColorSpace()->lcsIntent();
ColorSpace.pColorSpace()->vGETlcsEndpoints(&lpLogColorSpace->lcsEndpoints);
lpLogColorSpace->lcsGammaRed = ColorSpace.pColorSpace()->lcsGammaRed();
lpLogColorSpace->lcsGammaGreen= ColorSpace.pColorSpace()->lcsGammaGreen();
lpLogColorSpace->lcsGammaBlue = ColorSpace.pColorSpace()->lcsGammaBlue();
ColorSpace.pColorSpace()->vGETlcsFilename((PWCHAR)&lpLogColorSpace->lcsFilename[0],MAX_PATH);
if (cjBuffer >= sizeof(LOGCOLORSPACEEXW))
{
PLOGCOLORSPACEEXW lpLogColorSpaceEx = (PLOGCOLORSPACEEXW)lpvBuffer;
lpLogColorSpaceEx->dwFlags = ColorSpace.pColorSpace()->lcsExFlags();
cRet = sizeof(LOGCOLORSPACEEXW);
}
else
{
cRet = sizeof(LOGCOLORSPACEW);
}
}
}
return cRet;
}
/******************************Public*Routine******************************\
* GreIcmQueryBrushBitmap
*
* Arguments:
*
* Return Value:
*
* History:
*
* Rewrite it:
* 27-Jan-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
GreIcmQueryBrushBitmap(
HDC hdc,
HBRUSH hbrush,
PBITMAPINFO pbmiDIB,
PVOID pvBits,
ULONG *pulBits,
DWORD *piUsage,
BOOL *pbAlreadyTran
)
{
BOOL bRet = FALSE;
DWORD iUsage = DIB_RGB_COLORS;
BOOL bAlreadyTran = FALSE;
PBYTE pDIBits = NULL;
ULONG ulSizeInfo = sizeof(BITMAPINFO) + ((MAX_COLORTABLE - 1) * sizeof(RGBQUAD));
ICMAPI(("GreIcmQueryBrushBitmap\n"));
if ((pbmiDIB == NULL) || (piUsage == NULL) || (pbAlreadyTran == NULL) || (pulBits == NULL))
{
return FALSE;
}
XDCOBJ dcoDst(hdc);
if (dcoDst.bValid())
{
//
// ICM must be on, non-device mode only
//
if (dcoDst.pdc->bIsHostICM())
{
BRUSHSELOBJ bro((HBRUSH) hbrush);
if (bro.bValid())
{
//
// must be a DIB brush
//
if (bro.flAttrs() & BR_IS_DIB)
{
//
// if brush was created with DIB_PAL_COLORS then
// ICM translation is not needed.
//
if ((iUsage = bro.iUsage()) == DIB_RGB_COLORS)
{
//
// see if translated DIB already exists
//
PBRUSH pbr = bro.pbrush();
if (pbr->hFindIcmDIB(dcoDst.pdc->hcmXform()) != NULL)
{
ICMMSG(("GreIcmQueryBrushBitmap() Find !\n"));
bAlreadyTran = TRUE;
}
else
{
ICMMSG(("GreIcmQueryBrushBitmap() Not Find, then create it!\n"));
bAlreadyTran = FALSE;
//
// Initialize BITMAPINFO header.
//
RtlZeroMemory(pbmiDIB,ulSizeInfo);
pbmiDIB->bmiHeader.biSize = sizeof(BITMAPINFO);
//
// get bits per pixel, could use this to determine if color table is needed
//
bRet = GreGetDIBitsInternal(hdc,
bro.hbmPattern(),
0,0,NULL,
pbmiDIB,
DIB_RGB_COLORS,
0,ulSizeInfo);
if (bRet)
{
ULONG cjBits = GreGetBitmapBitsSize(pbmiDIB);
if (cjBits == 0)
{
//
// Empty or overflow..
//
bRet = FALSE;
}
else if (pvBits == NULL)
{
//
// Caller want to know the size of bitmap.
//
*pulBits = cjBits;
bRet = TRUE;
}
else if (cjBits <= *pulBits)
{
//
// We have enough memory to get bitmap bits.
//
bRet = GreGetDIBitsInternal(hdc,
bro.hbmPattern(),
0,
ABS(pbmiDIB->bmiHeader.biHeight),
(LPBYTE) pvBits,
pbmiDIB,
DIB_RGB_COLORS,
cjBits,
ulSizeInfo);
//
// Put used size.
//
*pulBits = cjBits;
}
else
{
WARNING("GreIcmQueryBrushBitmap: the buffer is not enough\n");
}
}
else
{
WARNING("GreIcmQueryBrushBitmap: failed to GetDIBits\n");
}
}
}
else
{
ICMMSG(("GreIcmQueryBrushBitmap: brush is not DIB_RGB_COLORS\n"));
}
}
else
{
ICMMSG(("GreIcmQueryBrushBitmap: brush is not DIBPATTERN\n"));
}
}
else
{
WARNING("GreIcmQueryBrushBitmap: invalid brush\n");
}
}
dcoDst.vUnlockFast();
}
else
{
WARNING("GreIcmQueryBrushBitmap: invalid DC\n");
}
*piUsage = iUsage;
*pbAlreadyTran = bAlreadyTran;
return (bRet);
}
/******************************Public*Routine******************************\
* GreIcmSetBrushBitmap
*
* Arguments:
*
* Return Value:
*
* History:
*
* Rewrite it:
* 27-Jan-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
GreIcmSetBrushBitmap(
HDC hdc,
HBRUSH hbrush,
PBITMAPINFO pbmiDIB,
PVOID pvBits
)
{
BOOL bRet = FALSE;
ULONG ulSizeInfo = sizeof(BITMAPINFO) + ((MAX_COLORTABLE - 1) * sizeof(RGBQUAD));
ICMAPI(("GreIcmSetBrushBitmap\n"));
XDCOBJ dcoDst(hdc);
if (dcoDst.bValid())
{
//
// ICM must be on, non-device mode only
//
if (dcoDst.pdc->bIsHostICM())
{
BRUSHSELOBJ bro((HBRUSH) hbrush);
if (bro.bValid())
{
//
// must be a DIB brush
//
if (bro.flAttrs() & BR_IS_DIB)
{
//
// Create a new DIB for this brush based on
// the DC's hcmXform. The client must already
// have translated this DIB
//
PBRUSH pbr = bro.pbrush();
//
// try to create a new DIB
//
HBITMAP hDIB = GreCreateDIBitmapReal(
hdc,
CBM_INIT | CBM_CREATEDIB,
(PBYTE)pvBits,
pbmiDIB,
DIB_RGB_COLORS,
ulSizeInfo,
0x007fffff,
NULL,
0,
NULL,
CDBI_INTERNAL,
0,
NULL);
if (hDIB)
{
//
// Keep translate DIB in cache.
//
bRet = pbr->bAddIcmDIB(dcoDst.pdc->hcmXform(),hDIB);
}
}
else
{
ICMMSG(("GreIcmSetBrushBitmap: brush is not DIBPATTERN\n"));
}
}
else
{
WARNING("GreIcmSetBrushBitmap: invalid brush\n");
}
}
dcoDst.vUnlockFast();
}
else
{
WARNING("GreIcmSetBrushBitmap: invalid DC\n");
}
return(bRet);
}
/******************************Public*Routine******************************\
* NtGdiIcmBrushInfo
*
* Arguments:
*
* Return Value:
*
* History:
*
* Rewrite it:
* 27-Jan-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
NtGdiIcmBrushInfo(
HDC hdc,
HBRUSH hbrush,
PBITMAPINFO pbmiDIB,
PVOID pvBits,
ULONG *pulBits,
DWORD *piUsage,
BOOL *pbAlreadyTran,
ULONG Command
)
{
BOOL bRet = TRUE;
HANDLE hSecureHeader = NULL;
HANDLE hSecureBits = NULL;
ULONG cjHeader = (sizeof(BITMAPINFO) + ((MAX_COLORTABLE - 1) * sizeof(RGBQUAD)));
ULONG cjBits = 0;
switch (Command)
{
case IcmQueryBrush:
{
BOOL bAlreadyTran = FALSE;
DWORD iUsage = DIB_RGB_COLORS;
__try
{
//
// Capture user mode memories.
//
ProbeForWrite(pbmiDIB,cjHeader,sizeof(DWORD));
hSecureHeader = MmSecureVirtualMemory(pbmiDIB,cjHeader,PAGE_READWRITE);
if ((pvBits != NULL) && hSecureHeader)
{
//
// Caller needs bitmap bits
//
ProbeForRead(pulBits,sizeof(ULONG),sizeof(ULONG));
cjBits = *pulBits;
ProbeForWrite(pvBits,cjBits,sizeof(DWORD));
hSecureBits = MmSecureVirtualMemory(pvBits,cjBits,PAGE_READWRITE);
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("NtGdiIcmBrushInfo - IcmQueryBrush failed copy usermode parameter\n");
bRet = FALSE;
}
if (bRet && hSecureHeader && ((pvBits == NULL) || hSecureBits))
{
//
// Get DIB brush bits.
//
bRet = GreIcmQueryBrushBitmap(hdc,
hbrush,
pbmiDIB,
pvBits,
&cjBits,
&iUsage,
&bAlreadyTran);
}
if (bRet)
{
__try
{
ProbeForWrite(pulBits,sizeof(ULONG),sizeof(ULONG));
*pulBits = cjBits;
if (pbAlreadyTran)
{
ProbeForWrite(pbAlreadyTran,sizeof(BOOL), sizeof(BOOL));
*pbAlreadyTran = bAlreadyTran;
}
if (piUsage)
{
ProbeForWrite(piUsage,sizeof(DWORD), sizeof(DWORD));
*piUsage = iUsage;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("NtGdiIcmBrushInfo failed copy usermode parameter\n");
bRet = FALSE;
}
}
break;
}
case IcmSetBrush:
{
__try
{
//
// Lock down header memory.
//
ProbeForRead(pbmiDIB,cjHeader,sizeof(DWORD));
hSecureHeader = MmSecureVirtualMemory(pbmiDIB,cjHeader,PAGE_READWRITE);
ProbeForRead(pulBits,sizeof(ULONG),sizeof(ULONG));
cjBits = *pulBits;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("NtGdiIcmBrushInfo - IcmSetBrush failed copy usermode parameter\n");
bRet = FALSE;
}
if (bRet && hSecureHeader)
{
//
// Compute bitmap size.
//
ULONG cjBitsNeeded = GreGetBitmapBitsSize(pbmiDIB);
if ((cjBitsNeeded == 0) || (cjBitsNeeded > cjBits))
{
WARNING1("NtGdiIcmBrushInfo - IcmSetBrush bitmap size is wrong\n");
bRet = FALSE;
}
else
{
__try
{
//
// Lock Bits.
//
ProbeForRead(pvBits,cjBitsNeeded,sizeof(DWORD));
hSecureBits = MmSecureVirtualMemory(pvBits,cjBitsNeeded,PAGE_READWRITE);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
WARNING("NtGdiIcmBrushInfo - IcmSetBrush failed lock pvBits\n");
bRet = FALSE;
}
if (bRet && hSecureBits)
{
//
// Set brush DIB bits.
//
bRet = GreIcmSetBrushBitmap(hdc,
hbrush,
pbmiDIB,
pvBits);
}
}
}
break;
}
default:
WARNING("NtGdiIcmBrushInfo(): unknown command\n");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
bRet = FALSE;
}
//
// Unlock user mode memory if locked.
//
if (hSecureHeader)
{
MmUnsecureVirtualMemory(hSecureHeader);
}
if (hSecureBits)
{
MmUnsecureVirtualMemory(hSecureBits);
}
return (bRet);
}
/******************************Public*Routine******************************\
* bInitIcm
*
* Init ICM information
*
* Arguments:
*
* None
*
* Return Value:
*
* Status
*
* History:
*
* 9/25/1996 Mark Enstrom [marke]
*
\**************************************************************************/
extern "C" BOOL bInitICM()
{
ICMAPI(("bInitIcm\n"));
BOOL bRet = TRUE;
//
// Read ICM configuration.
//
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
NTSTATUS NtStatus;
ULONG iIcmControlFlag = 0;
//
// read icm global configuration.
//
QueryTable[0].QueryRoutine = NULL;
QueryTable[0].Flags = (RTL_QUERY_REGISTRY_DIRECT |
RTL_QUERY_REGISTRY_REQUIRED);
QueryTable[0].Name = (PWSTR)L"GdiIcmControl";
QueryTable[0].EntryContext = (PVOID) &iIcmControlFlag;
QueryTable[0].DefaultType = REG_NONE;
QueryTable[0].DefaultData = 0;
QueryTable[0].DefaultLength = 0;
QueryTable[1].QueryRoutine = NULL;
QueryTable[1].Flags = 0;
QueryTable[1].Name = (PWSTR)NULL;
NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
L"ICM",
QueryTable,
NULL,
NULL);
if(!NT_SUCCESS(NtStatus))
{
WARNING1("Error reading GdiIcmControl (Optional, Not Error)\n");
iIcmControlFlag = 0L;
}
//
// NOTE: After sRGB.icm become really default.
//
if (!(iIcmControlFlag & ICM_CONTROL_WIN95_COLORSPACE))
{
//
// Configure default colorspace to sRGB.
//
gcsStockColorSpace.lcsCSType = LCS_sRGB;
//
// Set sRGB color profile name.
//
wcscpy(gcsStockColorSpace.lcsFilename,sRGB_PROFILENAME);
}
//
// Next, try to read GammaRange
//
//
// Initialize with default value.
//
giIcmGammaRange = 0x80; // Plus/Minus 128 is allowable by default.
QueryTable[0].Name = (PWSTR)L"GdiIcmGammaRange";
QueryTable[0].EntryContext = (PVOID) &giIcmGammaRange;
NtStatus = RtlQueryRegistryValues(RTL_REGISTRY_WINDOWS_NT,
L"ICM",
QueryTable,
NULL,
NULL);
if(!NT_SUCCESS(NtStatus))
{
WARNING1("Error reading GdiIcmGammaRange (Optional, Not Error)\n");
giIcmGammaRange = 0x80; // Plus/Minus 128 is allowable by default.
}
//
// Validate the value
//
if (giIcmGammaRange > 256)
{
giIcmGammaRange = 256;
}
#if HIDEYUKN_DBG
DbgPrint("GDI:IcmControlFlag = %x\n",iIcmControlFlag);
DbgPrint("GDI:IcmGammaRange = %x\n",giIcmGammaRange);
#endif
//
// Create Logical Color Space StockObject.
//
LOGCOLORSPACEEXW LogColorSpaceExW;
LogColorSpaceExW.lcsColorSpace = gcsStockColorSpace;
LogColorSpaceExW.dwFlags = 0;
HCOLORSPACE hColorSpace = GreCreateColorSpace(&LogColorSpaceExW);
if (hColorSpace)
{
//
// Set Owner of color space.
//
HmgSetOwner((HOBJ)hColorSpace, OBJECT_OWNER_PUBLIC, ICMLCS_TYPE);
//
// Mark the object is undeletable
//
HmgMarkUndeletable((HOBJ)hColorSpace,ICMLCS_TYPE);
//
// Set this colorspace to stock object.
//
bSetStockObject(hColorSpace,PRIV_STOCK_COLORSPACE);
//
// Keep stcok object to global
//
ghStockColorSpace = (HCOLORSPACE)GreGetStockObject(PRIV_STOCK_COLORSPACE);
//
// Lock color space to increment ref. count. (never become zero !)
//
gpStockColorSpace = (PCOLORSPACE)HmgShareLock((HOBJ)ghStockColorSpace,ICMLCS_TYPE);
//
// Initialize default DC_ATTR and DCLEVEL.
//
DcAttrDefault.hColorSpace = ghStockColorSpace;
dclevelDefault.pColorSpace = gpStockColorSpace;
if (gpStockColorSpace == NULL)
{
bRet = FALSE;
}
}
else
{
bRet = FALSE;
}
return(bRet);
}