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.
 
 
 
 
 
 

11798 lines
363 KiB

/******************************Module*Header*******************************\
* Module Name: icm.c
*
* Created: 4-Jun-1996
* Author: Mark Enstrom [marke]
*
* Copyright (c) 1996-1999 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include "winuserk.h"
#if DBG_ICM
ULONG DbgIcm = 0x0;
#endif
//
// Instance of MSCMS.DLL
//
HINSTANCE ghICM;
//
// Color Profile Directory
//
WCHAR ColorDirectory[MAX_PATH];
DWORD ColorDirectorySize;
//
// Primary display DC color profile filename.
//
WCHAR PrimaryDisplayProfile[MAX_PATH];
//
// List of ICMINFO
//
LIST_ENTRY ListIcmInfo;
//
// Semaphore to protect ICMINFO list
//
RTL_CRITICAL_SECTION semListIcmInfo;
//
// Per process color space and color transform cache list
//
LIST_ENTRY ListCachedColorSpace;
LIST_ENTRY ListCachedColorTransform;
ULONG cCachedColorSpace = 0;
ULONG cCachedColorTransform = 0;
//
// Semaphore to protect Cache list
//
RTL_CRITICAL_SECTION semColorTransformCache;
RTL_CRITICAL_SECTION semColorSpaceCache;
BOOL gbICMEnabledOnceBefore = FALSE;
//
// ANSI version function in MSCMS.DLL will not called.
//
// FPOPENCOLORPROFILEA fpOpenColorProfileA;
// FPCREATECOLORTRANSFORMA fpCreateColorTransformA;
// FPREGISTERCMMA fpRegisterCMMA;
// FPUNREGISTERCMMA fpUnregisterCMMA;
// FPINSTALLCOLORPROFILEA fpInstallColorProfileA;
// FPUNINSTALLCOLORPROFILEA fpUninstallColorProfileA;
// FPGETSTANDARDCOLORSPACEPROFILEA fpGetStandardColorSpaceProfileA;
// FPENUMCOLORPROFILESA fpEnumColorProfilesA;
// FPGETCOLORDIRECTORYA fpGetColorDirectoryA;
//
// And Following function does not used from gdi32.dll
//
// FPISCOLORPROFILEVALID fpIsColorProfileValid;
// FPCREATEDEVICELINKPROFILE fpCreateDeviceLinkProfile;
// FPTRANSLATECOLORS fpTranslateColors;
// FPCHECKCOLORS fpCheckColors;
// FPGETCMMINFO fpGetCMMInfo;
// FPSELECTCMM fpSelectCMM;
//
FPOPENCOLORPROFILEW fpOpenColorProfileW;
FPCLOSECOLORPROFILE fpCloseColorProfile;
FPCREATECOLORTRANSFORMW fpCreateColorTransformW;
FPDELETECOLORTRANSFORM fpDeleteColorTransform;
FPTRANSLATEBITMAPBITS fpTranslateBitmapBits;
FPTRANSLATECOLORS fpTranslateColors;
FPCHECKBITMAPBITS fpCheckBitmapBits;
FPREGISTERCMMW fpRegisterCMMW;
FPUNREGISTERCMMW fpUnregisterCMMW;
FPINSTALLCOLORPROFILEW fpInstallColorProfileW;
FPUNINSTALLCOLORPROFILEW fpUninstallColorProfileW;
FPENUMCOLORPROFILESW fpEnumColorProfilesW;
FPGETSTANDARDCOLORSPACEPROFILEW fpGetStandardColorSpaceProfileW;
FPGETCOLORPROFILEHEADER fpGetColorProfileHeader;
FPGETCOLORDIRECTORYW fpGetColorDirectoryW;
FPCREATEPROFILEFROMLOGCOLORSPACEW fpCreateProfileFromLogColorSpaceW;
FPCREATEMULTIPROFILETRANSFORM fpCreateMultiProfileTransform;
FPINTERNALGETDEVICECONFIG fpInternalGetDeviceConfig;
//
// MS COLOR MATCH DLL name
//
#define MSCMS_DLL_NAME L"mscms.dll"
//
// Misc. macros
//
#define ALIGN_DWORD(nBytes) (((nBytes) + 3) & ~3)
//
// sRGB color profile name
//
#define sRGB_PROFILENAME L"sRGB Color Space Profile.icm"
//
// DWORD 0x12345678 ---> 0x78563412
//
#define IcmSwapBytes(x) ((((x) & 0xFF000000) >> 24) | (((x) & 0x00FF0000) >> 8) | \
(((x) & 0x0000FF00) << 8) | (((x) & 0x000000FF) << 24))
//
// Macro to check color DC or not.
//
// LATER: We can improve performance by caching this in client, since
// GetDeviceCaps() goes to kernel in most cases.
//
#define IsColorDeviceContext(hdcThis) \
(2 < (unsigned) GetDeviceCaps((hdcThis), NUMCOLORS))
//
// Macro to check the color space is GDI object dependent.
//
#define IsColorSpaceOwnedByGDIObject(pColorSpace,hGDIObj) \
((pColorSpace) ? \
(((pColorSpace)->hObj == (hGDIObj)) ? TRUE : FALSE) \
: FALSE)
//
// Macro to get current color tranform in DC.
//
#define GetColorTransformInDC(pdcattr) ((pdcattr)->hcmXform)
//
// if the color space has DEVICE_CALIBRATE_COLORSPACE flag, returns TRUE, otherwise FALSE.
//
#define bDeviceCalibrate(pColorSpace) \
((pColorSpace) ? \
(((pColorSpace)->flInfo & DEVICE_CALIBRATE_COLORSPACE) ? TRUE : FALSE) \
: FALSE)
//
// Increment reference count of colorpsace/colortransform.
//
#define IcmReferenceColorSpace(pColorSpace) \
if ((pColorSpace)) \
{ \
ENTERCRITICALSECTION(&semColorSpaceCache); \
(pColorSpace)->cRef++; \
LEAVECRITICALSECTION(&semColorSpaceCache); \
}
#define IcmReferenceColorTransform(pCXfrom) \
if ((pCXform)) \
{ \
ENTERCRITICALSECTION(&semColorTransformCache); \
(pCXform)->cRef++; \
LEAVECRITICALSECTION(&semColorTransformCache); \
}
//
// Invalid color space handle
//
#define INVALID_COLORSPACE ((HCOLORSPACE)-1)
//
// Maximum number of cached color transform in list.
//
#define MAX_COLORTRANSFORM_CACHE 10
//
// Maximum size of "on memory profile" which be able to cache.
//
#define MAX_SIZE_OF_COLORPROFILE_TO_CACHE (1024*3)
/******************************Public*Routine******************************\
* GDI initialization routine called from dll init
*
* Arguments:
*
* None
*
* Return Value:
*
* Status
*
* History:
*
* 3-Jul-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL
IcmInitialize()
{
BOOL bStatus = TRUE;
ICMAPI(("gdi32: IcmInitialize\n"));
ENTERCRITICALSECTION(&semLocal);
//
// load MCSCM.DLL and get function addresses
//
if (ghICM == NULL)
{
HANDLE hmscms = LoadLibraryW(MSCMS_DLL_NAME);
if (hmscms != NULL)
{
fpOpenColorProfileW =
(FPOPENCOLORPROFILEW)GetProcAddress(hmscms,"OpenColorProfileW");
fpCloseColorProfile =
(FPCLOSECOLORPROFILE)GetProcAddress(hmscms,"CloseColorProfile");
fpCreateColorTransformW =
(FPCREATECOLORTRANSFORMW)GetProcAddress(hmscms,"CreateColorTransformW");
fpDeleteColorTransform =
(FPDELETECOLORTRANSFORM)GetProcAddress(hmscms,"DeleteColorTransform");
fpTranslateBitmapBits =
(FPTRANSLATEBITMAPBITS)GetProcAddress(hmscms,"TranslateBitmapBits");
fpTranslateColors =
(FPTRANSLATECOLORS)GetProcAddress(hmscms,"TranslateColors");
fpCheckBitmapBits =
(FPCHECKBITMAPBITS)GetProcAddress(hmscms,"CheckBitmapBits");
fpRegisterCMMW =
(FPREGISTERCMMW)GetProcAddress(hmscms,"RegisterCMMW");
fpUnregisterCMMW =
(FPUNREGISTERCMMW)GetProcAddress(hmscms,"UnregisterCMMW");
fpInstallColorProfileW =
(FPINSTALLCOLORPROFILEW)GetProcAddress(hmscms,"InstallColorProfileW");
fpUninstallColorProfileW =
(FPUNINSTALLCOLORPROFILEW)GetProcAddress(hmscms,"UninstallColorProfileW");
fpEnumColorProfilesW =
(FPENUMCOLORPROFILESW)GetProcAddress(hmscms,"EnumColorProfilesW");
fpGetStandardColorSpaceProfileW =
(FPGETSTANDARDCOLORSPACEPROFILEW)GetProcAddress(hmscms,"GetStandardColorSpaceProfileW");
fpGetColorProfileHeader =
(FPGETCOLORPROFILEHEADER)GetProcAddress(hmscms,"GetColorProfileHeader");
fpGetColorDirectoryW =
(FPGETCOLORDIRECTORYW)GetProcAddress(hmscms,"GetColorDirectoryW");
fpCreateProfileFromLogColorSpaceW =
(FPCREATEPROFILEFROMLOGCOLORSPACEW)GetProcAddress(hmscms,"CreateProfileFromLogColorSpaceW");
fpCreateMultiProfileTransform =
(FPCREATEMULTIPROFILETRANSFORM)GetProcAddress(hmscms,"CreateMultiProfileTransform");
fpInternalGetDeviceConfig =
(FPINTERNALGETDEVICECONFIG)GetProcAddress(hmscms,"InternalGetDeviceConfig");
if ((fpOpenColorProfileW == NULL) ||
(fpCloseColorProfile == NULL) ||
(fpCreateColorTransformW == NULL) ||
(fpDeleteColorTransform == NULL) ||
(fpTranslateBitmapBits == NULL) ||
(fpTranslateColors == NULL) ||
(fpCheckBitmapBits == NULL) ||
(fpRegisterCMMW == NULL) ||
(fpUnregisterCMMW == NULL) ||
(fpInstallColorProfileW == NULL) ||
(fpUninstallColorProfileW == NULL) ||
(fpEnumColorProfilesW == NULL) ||
(fpGetStandardColorSpaceProfileW == NULL) ||
(fpGetColorProfileHeader == NULL) ||
(fpGetColorDirectoryW == NULL) ||
(fpCreateProfileFromLogColorSpaceW == NULL) ||
(fpCreateMultiProfileTransform == NULL) ||
(fpInternalGetDeviceConfig == NULL)
)
{
WARNING("LoadLibrary of mscms.dll failed to associate all proc addresses\n");
FreeLibrary(hmscms);
hmscms = NULL;
}
else
{
//
// Initialize Color Directory
//
ColorDirectorySize = sizeof(ColorDirectory) / sizeof(WCHAR);
bStatus = (*fpGetColorDirectoryW)(NULL,ColorDirectory,&ColorDirectorySize);
if (bStatus)
{
ColorDirectorySize = wcslen(ColorDirectory);
}
if (bStatus && ColorDirectorySize)
{
ICMMSG(("IcmInitialize():ColorDirectory = %ws\n",ColorDirectory));
//
// Counts null-terminated char.
//
ColorDirectorySize += 1;
//
// Initialize Primary display color profile.
//
PrimaryDisplayProfile[0] = UNICODE_NULL;
}
else
{
WARNING("LoadLibrary of mscms.dll failed to obtain color directory\n");
FreeLibrary(hmscms);
hmscms = NULL;
}
}
//
// Keep the handle to global veriable.
//
ghICM = hmscms;
}
}
LEAVECRITICALSECTION(&semLocal);
if (ghICM == NULL)
{
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
bStatus = FALSE;
}
return(bStatus);
}
/******************************Public*Routine******************************\
*
* SetIcmMode - turn ICM on or off in a DC
*
* Arguments:
*
* hdc - device context
* mode - ICM_ON,ICM_OFF,ICM_QUERY
*
* Return Value:
*
* status
*
* History:
*
* Rewrite it:
* 20-Jan-1997 -by- Hideyuki Nagase [hideyukn]
* Write it:
* 4-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
int META WINAPI
SetICMMode(
HDC hdc,
int mode
)
{
int iRet = (int)FALSE;
PDC_ATTR pdcattr;
ICMAPI(("gdi32: SetICMMode\n"));
FIXUP_HANDLE(hdc);
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
//
// metafile (only for ICM_ON and ICM_OFF)
//
if (IS_ALTDC_TYPE(hdc))
{
PLDC pldc;
//
// No ICM with Windows MetaFile.
//
if (IS_METADC16_TYPE(hdc))
return(iRet);
DC_PLDC(hdc,pldc,iRet)
#if DBG_ICM
ICMMSG(("SetICMMode():%s ICM for %s\n", \
((mode == ICM_ON) ? "Enable" : \
((mode == ICM_OFF) ? "Disable" : "Query")), \
((pldc->iType == LO_METADC) ? "Enhanced Metafile" : \
(!IsColorDeviceContext(hdc) ? "Monochrome Printer" : "Color Printer")) \
));
#endif
//
// If this is Enhanced Metafile, OR non-color printer device, don't enable ICM "really".
//
if (pldc->iType == LO_METADC || (!IsColorDeviceContext(hdc)))
{
switch (mode)
{
case ICM_ON:
case ICM_OFF:
case ICM_DONE_OUTSIDEDC:
//
// Record ICM ON/OFF only to metafile.
//
if (pldc->iType == LO_METADC)
{
if (!MF_SetD(hdc,(DWORD)mode,EMR_SETICMMODE))
{
return((int)FALSE);
}
}
//
// We don't "really" turn-on ICM for metafile, metafile
// should be device-independent, thus, non-ICMed color/images
// will be metafiled. But still need to keep its status for ICM_QUERY.
// And "real" image correction happen at play-back time.
//
if(pdcattr)
{
if (mode == ICM_ON)
{
pdcattr->lIcmMode |= DC_ICM_METAFILING_ON;
}
else if (mode == ICM_DONE_OUTSIDEDC)
{
pdcattr->lIcmMode |= (DC_ICM_METAFILING_ON |
CTX_ICM_METAFILING_OUTSIDEDC);
}
else // if ((mode == ICM_OFF)
{
pdcattr->lIcmMode &= ~(DC_ICM_METAFILING_ON |
CTX_ICM_METAFILING_OUTSIDEDC);
}
iRet = (int)TRUE;
}
break;
case ICM_QUERY:
if (pdcattr)
{
if (IS_ICM_METAFILING_ON(pdcattr->lIcmMode))
{
iRet = ((pdcattr->lIcmMode & CTX_ICM_METAFILING_OUTSIDEDC) ? \
ICM_DONE_OUTSIDEDC : ICM_ON);
}
else
{
iRet = ICM_OFF;
}
}
break;
default:
iRet = (int)FALSE;
break;
}
return (iRet);
}
}
if (pdcattr)
{
ULONG iPrevMode;
//
// Before change ICM mode, we need to flush batched gdi functions.
//
CHECK_AND_FLUSH(hdc,pdcattr);
//
// Get current mode.
//
iPrevMode = pdcattr->lIcmMode;
//
// validate input parameter
//
switch (ICM_MODE(mode))
{
case ICM_QUERY:
//
// return current mode
//
if (IS_ICM_INSIDEDC(iPrevMode))
{
iRet = ICM_ON;
}
else if (IS_ICM_OUTSIDEDC(iPrevMode))
{
iRet = ICM_DONE_OUTSIDEDC;
}
else
{
iRet = ICM_OFF;
}
break;
case ICM_ON:
if (!IS_ICM_INSIDEDC(iPrevMode))
{
//
// As default, ICM will be done on HOST.
//
ULONG lReqMode = REQ_ICM_HOST;
PGDI_ICMINFO pIcmInfo = INIT_ICMINFO(hdc,pdcattr);
//
// Initialize ICMINFO
//
if (pIcmInfo == NULL)
{
WARNING("gdi32: SetICMMode: Can't init icm info\n");
return((int)FALSE);
}
//
// Load external ICM dlls.
//
LOAD_ICMDLL((int)FALSE);
//
// ICM is not enabled,yet. Let's enable ICM.
//
ASSERTGDI(GetColorTransformInDC(pdcattr) == NULL,"SetIcmMode: hcmXform is not NULL\n");
if (IS_DEVICE_ICM_DEVMODE(iPrevMode))
{
ICMMSG(("SetIcmMode: Device ICM is requested\n"));
//
// if ICM on Device was requested by CreateDC(), let force do
// ICM on device, if possible.
//
lReqMode = REQ_ICM_DEVICE;
}
else
{
ICMMSG(("SetIcmMode: Host ICM is requested\n"));
}
//
// Turn ICM on for this DC.
//
if (!NtGdiSetIcmMode(hdc,ICM_SET_MODE,lReqMode))
{
//
// something wrong... we are fail to enable ICM.
//
iRet = (int)FALSE;
break;
}
//
// If we have cached transform and it is not dirty, we can use that.
//
if ((pIcmInfo->pCXform == NULL) || (pdcattr->ulDirty_ & DIRTY_COLORTRANSFORM))
{
if (IcmUpdateDCColorInfo(hdc,pdcattr))
{
//
// Mark this process has experience about ICM ON.
//
gbICMEnabledOnceBefore = TRUE;
iRet = (int)TRUE;
}
else
{
WARNING("SetIcmMode():IcmUpdateDCInfo failed\n");
//
// Fail to create new transform
//
NtGdiSetIcmMode(hdc,ICM_SET_MODE,REQ_ICM_OFF);
iRet = (int)FALSE;
}
}
else
{
ICMMSG(("SetIcmMode: Use cached Color Transform\n"));
//
// Use cached transform, because since last time when we disabled ICM,
// NO profile(s) and logical color space has been changed.
//
if (IcmSelectColorTransform(
hdc,pdcattr,pIcmInfo->pCXform,
bDeviceCalibrate(pIcmInfo->pCXform->DestinationColorSpace)))
{
//
// Translate all DC objects to ICM colors. Must
// force brush/pens to be re-realized when used next
//
IcmTranslateColorObjects(hdc,pdcattr,TRUE);
iRet = (int)TRUE;
}
else
{
//
// Fail to select cached transform to the DC.
//
NtGdiSetIcmMode(hdc,ICM_SET_MODE,REQ_ICM_OFF);
iRet = (int)FALSE;
}
}
}
else
{
ICMMSG(("SetIcmMode: ICM has been enabled already\n"));
iRet = (int)TRUE;
}
break;
case ICM_DONE_OUTSIDEDC:
if (!IS_ICM_OUTSIDEDC(iPrevMode))
{
//
// if inside-DC ICM is enabled, turned off it.
//
if (IS_ICM_INSIDEDC(iPrevMode))
{
//
// Invalidate current color tansform (but the cache in ICMINFO is still valid).
//
IcmSelectColorTransform(hdc,pdcattr,NULL,FALSE);
//
// Restore color data for ICM disable.
//
IcmTranslateColorObjects(hdc,pdcattr,FALSE);
}
//
// Tell the kernel to disable color adjustment during halftone.
//
NtGdiSetIcmMode(hdc,ICM_SET_MODE,REQ_ICM_OUTSIDEDC);
}
else
{
ICMMSG(("SetIcmMode: OutsideDC ICM has been enabled already\n"));
}
iRet = (int)TRUE;
break;
case ICM_OFF:
//
// Is there any kind of ICM is enabled ?
//
if (IS_ICM_ON(iPrevMode))
{
if (IS_ICM_INSIDEDC(iPrevMode))
{
//
// Invalidate current color tansform (but the cache in ICMINFO is still valid).
//
IcmSelectColorTransform(hdc,pdcattr,NULL,TRUE);
//
// Restore color data for ICM disable.
//
IcmTranslateColorObjects(hdc,pdcattr,FALSE);
}
//
// Tell the kernel to disable ICM.
//
NtGdiSetIcmMode(hdc,ICM_SET_MODE,REQ_ICM_OFF);
}
else
{
ICMMSG(("SetIcmMode: ICM has been disabled already\n"));
}
iRet = (int)TRUE;
break;
default:
GdiSetLastError(ERROR_INVALID_PARAMETER);
iRet = (int)FALSE;
break;
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
iRet = (int)FALSE;
}
return((int)iRet);
}
/******************************Public*Routine******************************\
* CreateColorSpaceA
*
* Arguments:
*
* lpLogColorSpace - apps log color space
*
* Return Value:
*
* handle of color space or NULL
*
* History:
*
* 4-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
HCOLORSPACE WINAPI
CreateColorSpaceA(
LPLOGCOLORSPACEA lpLogColorSpace
)
{
HCOLORSPACE hRet;
LOGCOLORSPACEW LogColorSpaceW;
ICMAPI(("gdi32: CreateColorSpaceA\n"));
if (lpLogColorSpace == NULL)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return(NULL);
}
//
// convert ascii to long character version
//
if ((lpLogColorSpace->lcsSignature != LCS_SIGNATURE) ||
(lpLogColorSpace->lcsVersion != 0x400) ||
(lpLogColorSpace->lcsSize != sizeof(LOGCOLORSPACEA)))
{
ICMWRN(("CreateColorSpaceA: Incorrect signature,version or size \n"));
GdiSetLastError(ERROR_INVALID_COLORSPACE);
return(NULL);
}
RtlZeroMemory(&LogColorSpaceW,sizeof(LOGCOLORSPACEW));
LogColorSpaceW.lcsSignature = lpLogColorSpace->lcsSignature;
LogColorSpaceW.lcsVersion = lpLogColorSpace->lcsVersion;
LogColorSpaceW.lcsCSType = lpLogColorSpace->lcsCSType;
LogColorSpaceW.lcsIntent = lpLogColorSpace->lcsIntent;
LogColorSpaceW.lcsEndpoints = lpLogColorSpace->lcsEndpoints;
LogColorSpaceW.lcsGammaRed = lpLogColorSpace->lcsGammaRed;
LogColorSpaceW.lcsGammaGreen = lpLogColorSpace->lcsGammaGreen;
LogColorSpaceW.lcsGammaBlue = lpLogColorSpace->lcsGammaBlue;
LogColorSpaceW.lcsSize = sizeof(LOGCOLORSPACEW);
vToUnicodeN(
LogColorSpaceW.lcsFilename,MAX_PATH,
lpLogColorSpace->lcsFilename,strlen(lpLogColorSpace->lcsFilename)+1
);
hRet = CreateColorSpaceInternalW(&LogColorSpaceW,LCSEX_ANSICREATED);
return(hRet);
}
/******************************Public*Routine******************************\
* CreateColorSpaceW
*
* ColorSpace is a KERNEL mode object
*
* Arguments:
*
* lpLogColorSpace - apps log color space
*
* Return Value:
*
* Handle of color space or NULL
*
* History:
*
* 18-Apr-1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
HCOLORSPACE WINAPI
CreateColorSpaceW(
LPLOGCOLORSPACEW lpLogColorSpace
)
{
return (CreateColorSpaceInternalW(lpLogColorSpace,0));
}
HCOLORSPACE WINAPI
CreateColorSpaceInternalW(
LPLOGCOLORSPACEW lpLogColorSpace,
DWORD dwCreateFlags
)
{
HCOLORSPACE hRet = NULL;
LOGCOLORSPACEEXW LogColorSpaceExOnStack;
ICMAPI(("gdi32: CreateColorSpaceW\n"));
if (lpLogColorSpace == NULL)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return(NULL);
}
//
// validate color space
//
if ((lpLogColorSpace->lcsSignature != LCS_SIGNATURE) ||
(lpLogColorSpace->lcsVersion != 0x400) ||
(lpLogColorSpace->lcsSize != sizeof(LOGCOLORSPACEW)))
{
goto InvalidColorSpaceW;
}
//
// validate lcsIntent
//
if ((lpLogColorSpace->lcsIntent != LCS_GM_BUSINESS) &&
(lpLogColorSpace->lcsIntent != LCS_GM_GRAPHICS) &&
(lpLogColorSpace->lcsIntent != LCS_GM_IMAGES) &&
(lpLogColorSpace->lcsIntent != LCS_GM_ABS_COLORIMETRIC))
{
goto InvalidColorSpaceW;
}
//
// We can not modify apps LOGCOLORSPACEW, so that make a copy on stack.
//
LogColorSpaceExOnStack.lcsColorSpace = *lpLogColorSpace;
LogColorSpaceExOnStack.dwFlags = dwCreateFlags;
//
// validate lcsCSTYPE
//
if ((lpLogColorSpace->lcsCSType == LCS_CALIBRATED_RGB) ||
(lpLogColorSpace->lcsCSType == PROFILE_LINKED))
{
//
// Replace CSType in case PROFILE_LINKED.
//
LogColorSpaceExOnStack.lcsColorSpace.lcsCSType = LCS_CALIBRATED_RGB;
if (lpLogColorSpace->lcsFilename[0] != L'\0')
{
HANDLE hFile;
//
// Normalize profile filename. but we will not over-write app's
// path with our normalized path.
//
BuildIcmProfilePath(lpLogColorSpace->lcsFilename,
LogColorSpaceExOnStack.lcsColorSpace.lcsFilename,
MAX_PATH);
//
// profile name given, verify it exists
//
hFile = CreateFileW(
LogColorSpaceExOnStack.lcsColorSpace.lcsFilename,
GENERIC_READ,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
//
// Yes, file is really exits.
//
CloseHandle(hFile);
}
else
{
ICMWRN(("CreateColorSpaceW: Couldn't open file specified by lcsFilename\n"));
GdiSetLastError(ERROR_PROFILE_NOT_FOUND);
return(NULL);
}
}
}
else // any other CSType
{
ULONG ulSize = MAX_PATH;
//
// Load external ICM dlls.
//
LOAD_ICMDLL(NULL);
//
// if CSType is not LCS_CALIBRATED_RGB, we should go to MSCMS.DLL to get color profile
// for corresponding LCSType, then any given profile name from application is IGNORED.
//
if (!(*fpGetStandardColorSpaceProfileW)(
NULL, lpLogColorSpace->lcsCSType,
LogColorSpaceExOnStack.lcsColorSpace.lcsFilename, &ulSize))
{
ICMWRN(("CreateColorSpaceW:Error CSType = %x\n",lpLogColorSpace->lcsCSType));
goto InvalidColorSpaceW;
}
}
//
// Call kernel to create this colorspace.
//
hRet = NtGdiCreateColorSpace(&LogColorSpaceExOnStack);
return(hRet);
InvalidColorSpaceW:
ICMWRN(("CreateColorSpaceW: Incorrect ColorSpace parameter\n"));
GdiSetLastError(ERROR_INVALID_COLORSPACE);
return(NULL);
}
/******************************Public*Routine******************************\
* DeleteColorSpace - delete user object
*
* Arguments:
*
* hColorSpace - color space handle
*
* Return Value:
*
* status
*
* History:
*
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL WINAPI
DeleteColorSpace(
HCOLORSPACE hColorSpace
)
{
ICMAPI(("gdi32: DeleteColorSpace\n"));
FIXUP_HANDLE(hColorSpace);
//
// validate handle, delete
//
return (NtGdiDeleteColorSpace(hColorSpace));
}
/******************************Public*Routine******************************\
* SetColorSpace - set logical color space into DC, force new xform to be
* created and all objects re-realized
*
* Arguments:
*
* hdc - dc handle
* hColorSpace - logical color space handle
*
* Return Value:
*
* Status
*
* History:
*
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
HCOLORSPACE META WINAPI
SetColorSpace(
HDC hdc,
HCOLORSPACE hColorSpace
)
{
HANDLE hRet = NULL;
ICMAPI(("gdi32: SetColorSpace\n"));
FIXUP_HANDLE(hdc);
FIXUP_HANDLE(hColorSpace);
if (IS_ALTDC_TYPE(hdc))
{
PLDC pldc;
if (IS_METADC16_TYPE(hdc))
return(hRet);
DC_PLDC(hdc,pldc,hRet);
if (pldc->iType == LO_METADC)
{
if (!MF_SelectAnyObject(hdc,(HANDLE)hColorSpace,EMR_SETCOLORSPACE))
return(hRet);
}
}
//
// Update source color space
//
hRet = IcmSetSourceColorSpace(hdc,hColorSpace,NULL,0);
return(hRet);
}
/******************************Public*Routine******************************\
* GetColorSpace - return color space from DC
*
* Arguments:
*
* hdc
*
* Return Value:
*
* hColorSpace or NULL
*
* History:
*
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
HCOLORSPACE WINAPI
GetColorSpace(
HDC hdc
)
{
HANDLE hRet = NULL;
PDC_ATTR pdcattr;
ICMAPI(("gdi32: GetColorSpace\n"));
FIXUP_HANDLE(hdc);
//
// validate and access hdc
//
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (pdcattr)
{
//
// get hColorSpace
//
hRet = (HANDLE)pdcattr->hColorSpace;
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
return(hRet);
}
/******************************Public*Routine******************************\
* GetLogColorSpaceA - get colorspace and convert to ASCII
*
* typedef struct tagLOGCOLORSPACEW {
* DWORD lcsSignature;
* DWORD lcsVersion;
* DWORD lcsSize;
* LCSCSTYPE lcsCSType;
* LCSGAMUTMATCH lcsIntent;
* CIEXYZTRIPLE lcsEndpoints;
* DWORD lcsGammaRed;
* DWORD lcsGammaGreen;
* DWORD lcsGammaBlue;
* WCHAR lcsFilename[MAX_PATH];
* } LOGCOLORSPACEW, *LPLOGCOLORSPACEW;
*
* Arguments:
*
* hColorSpace - handle to color space
* lpBuffer - buffer to hold logcolorspace
* nSize - buffer size
*
* Return Value:
*
* status
*
* History:
*
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL WINAPI
GetLogColorSpaceA(
HCOLORSPACE hColorSpace,
LPLOGCOLORSPACEA lpBuffer,
DWORD nSize
)
{
BOOL bRet = FALSE;
LOGCOLORSPACEW LogColorSpaceW;
ICMAPI(("gdi32: GetLogColorSpaceA\n"));
if ((lpBuffer != NULL) && (nSize >= sizeof(LOGCOLORSPACEA)))
{
//
// get info using W version
//
bRet = GetLogColorSpaceW(hColorSpace,&LogColorSpaceW,sizeof(LOGCOLORSPACEW));
if (bRet)
{
//
// copy to user buffer
//
lpBuffer->lcsSignature = LogColorSpaceW.lcsSignature;
lpBuffer->lcsVersion = LogColorSpaceW.lcsVersion;
lpBuffer->lcsSize = sizeof(LOGCOLORSPACEA);
lpBuffer->lcsCSType = LogColorSpaceW.lcsCSType;
lpBuffer->lcsIntent = LogColorSpaceW.lcsIntent;
lpBuffer->lcsEndpoints = LogColorSpaceW.lcsEndpoints;
lpBuffer->lcsGammaRed = LogColorSpaceW.lcsGammaRed;
lpBuffer->lcsGammaGreen = LogColorSpaceW.lcsGammaGreen;
lpBuffer->lcsGammaBlue = LogColorSpaceW.lcsGammaBlue;
//
// convert W to A
//
bRet = bToASCII_N(lpBuffer->lcsFilename,
MAX_PATH,
LogColorSpaceW.lcsFilename,
wcslen(LogColorSpaceW.lcsFilename)+1);
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
}
else
{
GdiSetLastError(ERROR_INSUFFICIENT_BUFFER);
}
return(bRet);
}
/******************************Public*Routine******************************\
* GetLogColorSpaceW - return logical color space info.
*
* Arguments:
*
* hColorSpace - handle to color space
* lpBuffer - buffer to hold logcolorspace
* nSize - buffer size
*
* Return Value:
*
* status
*
* History:
*
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL WINAPI
GetLogColorSpaceW(
HCOLORSPACE hColorSpace,
LPLOGCOLORSPACEW lpBuffer,
DWORD nSize
)
{
BOOL bRet = FALSE;
ICMAPI(("gdi32: GetLogColorSpaceW\n"));
if ((lpBuffer != NULL) && (nSize >= sizeof(LOGCOLORSPACEW)))
{
FIXUP_HANDLE(hColorSpace);
//
// Call kernel to get contents
//
if (NtGdiExtGetObjectW(hColorSpace,sizeof(LOGCOLORSPACEW),lpBuffer)
== sizeof(LOGCOLORSPACEW))
{
//
// Only for stock color space object.
//
if ((hColorSpace == GetStockObject(PRIV_STOCK_COLORSPACE)) &&
(lpBuffer->lcsCSType != LCS_CALIBRATED_RGB))
{
ULONG ulSize = MAX_PATH;
//
// Load ICM DLL.
//
LOAD_ICMDLL(FALSE);
//
// Get corresponding profile name from CSType.
//
if (!(*fpGetStandardColorSpaceProfileW)(
NULL,
lpBuffer->lcsCSType,
lpBuffer->lcsFilename,
&ulSize))
{
ICMMSG(("GetLogColorSpaceW():Fail to SCS(%x), leave it as is\n",
lpBuffer->lcsCSType));
}
}
bRet = TRUE;
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
}
else
{
GdiSetLastError(ERROR_INSUFFICIENT_BUFFER);
}
return(bRet);
}
/******************************Public*Routine******************************\
* CheckColorsInGamut
*
* Arguments:
*
* hdc - DC
* lpRGBQuad - Buffer of colors to check
* dlpBuffer - result buffer
* nCount - number of colors
*
* Return Value:
*
* status
*
* History:
*
* Rewrite it:
* 26-Jan-1997 -by- Hideyuki Nagase [hideyukn]
* Write it:
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL WINAPI
CheckColorsInGamut(
HDC hdc,
LPVOID lpRGBTriple,
LPVOID dlpBuffer,
DWORD nCount
)
{
BOOL bRet = FALSE;
PDC_ATTR pdcattr;
ICMAPI(("gdi32: CheckColorsInGamut\n"));
FIXUP_HANDLE(hdc);
//
// Check parameter
//
if ((lpRGBTriple == NULL) || (dlpBuffer == NULL) || (nCount == 0))
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// validate and access hdc
//
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (pdcattr)
{
if (IS_ICM_HOST(pdcattr->lIcmMode) ||
IS_ICM_DEVICE(pdcattr->lIcmMode))
{
ASSERTGDI(ghICM,"CheckColorsInGamut(): mscms.dll is not loaded\n");
if (GetColorTransformInDC(pdcattr))
{
//
// The input buffer may not be DWORD-aligned, And it buffer size
// might be exactly nCount * sizeof(RGBTRIPLE).
// So that, allocate DWORD-aligned buffer here.
//
PVOID pvBuf = LOCALALLOC(ALIGN_DWORD(nCount*sizeof(RGBTRIPLE)));
if (!pvBuf)
{
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return (FALSE);
}
//
// Make a copy, here
//
RtlZeroMemory(pvBuf,ALIGN_DWORD(nCount*sizeof(RGBTRIPLE)));
RtlCopyMemory(pvBuf,lpRGBTriple,nCount*sizeof(RGBTRIPLE));
if (IS_ICM_HOST(pdcattr->lIcmMode))
{
//
// we handle RGBTRIPLE array as nCount x 1 pixel bitmap.
//
bRet = (*fpCheckBitmapBits)(
(HANDLE)GetColorTransformInDC(pdcattr),
pvBuf,
BM_RGBTRIPLETS,
nCount,1,
ALIGN_DWORD(nCount*sizeof(RGBTRIPLE)),
dlpBuffer,
NULL,0);
}
else // if (IS_ICM_DEVICE(pdcattr->lIcmMode))
{
//
// Call device driver via kernel.
//
bRet = NtGdiCheckBitmapBits(
hdc,
(HANDLE)GetColorTransformInDC(pdcattr),
(PVOID)lpRGBTriple,
(ULONG)BM_RGBTRIPLETS,
nCount,1,
ALIGN_DWORD(nCount*sizeof(RGBTRIPLE)),
dlpBuffer);
}
LOCALFREE(pvBuf);
}
else
{
//
// There is no valid color transform,
// so it is assume ident. color transform,
// then that every color in the gamut.
//
RtlZeroMemory(dlpBuffer,nCount);
bRet = TRUE;
}
}
else
{
WARNING("CheckColorsInGamut():ICM mode is invalid\n");
GdiSetLastError(ERROR_ICM_NOT_ENABLED);
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
return(bRet);
}
/******************************Public*Routine******************************\
* ColorMatchToTarget
*
* Arguments:
*
* hdc,
* hdcTarget
* uiAction
*
* Return Value:
*
* status
*
* History:
*
* Rewrite it:
* 26-Jan-1997 -by- Hideyuki Nagase [hideyukn]
* Write it:
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL META WINAPI
ColorMatchToTarget(
HDC hdc,
HDC hdcTarget,
DWORD uiAction
)
{
BOOL bRet = FALSE;
PDC_ATTR pdcattrTarget;
ICMAPI(("gdi32: ColorMatchToTarget\n"));
FIXUP_HANDLE(hdcTarget);
//
// Verify Target DC. No ICM with Windows MetaFile.
//
if (IS_METADC16_TYPE(hdcTarget))
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return(bRet);
}
PSHARED_GET_VALIDATE(pdcattrTarget,hdcTarget,DC_TYPE);
if (pdcattrTarget != NULL)
{
PCACHED_COLORSPACE pTargetColorSpace = NULL;
PLDC pldcTarget = (PLDC)(pdcattrTarget->pvLDC);
if (!IS_ICM_INSIDEDC(pdcattrTarget->lIcmMode))
{
GdiSetLastError(ERROR_ICM_NOT_ENABLED);
return (FALSE);
}
//
// No Enhanced metafile DC as target DC.
//
if (pldcTarget && pldcTarget->iType == LO_METADC)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return(bRet);
}
//
// ICMINFO should be exist.
//
if (!BEXIST_ICMINFO(pdcattrTarget))
{
GdiSetLastError(ERROR_ICM_NOT_ENABLED);
return(bRet);
}
if (uiAction == CS_ENABLE)
{
//
// Hold critical section for color space to make sure pTargetColorSpace won't be deleted
//
ENTERCRITICALSECTION(&semColorSpaceCache);
//
// Target DC has LDC and ICMINFO, pick up colorspace data from there.
//
pTargetColorSpace = ((PGDI_ICMINFO)(pdcattrTarget->pvICM))->pDestColorSpace;
//
// Select it to target. the ref count of pTargetColorSpace will be incremented
// if we suceed to select.
//
bRet = ColorMatchToTargetInternal(hdc,pTargetColorSpace,uiAction);
LEAVECRITICALSECTION(&semColorSpaceCache);
}
else
{
bRet = ColorMatchToTargetInternal(hdc,NULL,uiAction);
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
return (bRet);
}
BOOL WINAPI
ColorMatchToTargetInternal(
HDC hdc,
PCACHED_COLORSPACE pTargetColorSpace,
DWORD uiAction
)
{
BOOL bRet = FALSE;
BOOL bEhnMetafile = FALSE;
PDC_ATTR pdcattr;
FIXUP_HANDLE(hdc);
//
// Verify destination DC. No ICM with Windows MetaFile.
//
if (IS_METADC16_TYPE(hdc))
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return(FALSE);
}
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (pdcattr != NULL)
{
PLDC pldc = (PLDC)(pdcattr->pvLDC);
//
// Check ICM is enabled on hdc properly.
//
if (pldc && (pldc->iType == LO_METADC))
{
//
// ICM should be turned on "fakely" on metafile hdc
//
if (!IS_ICM_METAFILING_ON(pdcattr->lIcmMode))
{
GdiSetLastError(ERROR_ICM_NOT_ENABLED);
return (FALSE);
}
//
// Mark we are recording into Enhanced metafile.
//
bEhnMetafile = TRUE;
}
else
{
if (!IS_ICM_INSIDEDC(pdcattr->lIcmMode))
{
GdiSetLastError(ERROR_ICM_NOT_ENABLED);
return (FALSE);
}
}
switch (uiAction)
{
case CS_ENABLE:
//
// Fail, if we are in proofing mode, already.
//
if (!IS_ICM_PROOFING(pdcattr->lIcmMode))
{
if (pTargetColorSpace)
{
if (bEhnMetafile)
{
//
// Set the data to metafile.
//
bRet = MF_ColorMatchToTarget(
hdc, uiAction,
(PVOID) pTargetColorSpace,
EMR_COLORMATCHTOTARGETW);
}
else
{
//
// Set Target color space.
//
// (this increments ref count of pTargetColorSpace)
//
bRet = IcmSetTargetColorSpace(hdc,pTargetColorSpace,uiAction);
}
}
}
else
{
WARNING("ColorMatchToTargetInternal(): DC is proofing mode already\n");
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
break;
case CS_DISABLE:
case CS_DELETE_TRANSFORM:
if (IS_ICM_PROOFING(pdcattr->lIcmMode))
{
if (bEhnMetafile)
{
//
// Set the data to metafile.
//
bRet = MF_ColorMatchToTarget(
hdc, uiAction, NULL,
EMR_COLORMATCHTOTARGETW);
}
else
{
//
// Reset Target color space
//
bRet = IcmSetTargetColorSpace(hdc,NULL,uiAction);
}
}
else
{
//
// we are not in proofing mode, never called with CS_ENABLE before.
//
WARNING("ColorMatchToTarget: DC is not proofing mode\n");
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
break;
default:
WARNING("ColorMatchToTarget: uiAction is invalid\n");
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
WARNING("ColorMatchToTarget: invalid DC\n");
}
return(bRet);
}
/******************************Public*Routine******************************\
* GetICMProfileA - get current profile from DC
*
* Arguments:
*
* hdc - DC
* szBuffer - size of buffer
* pBuffer - user buffer
*
* Return Value:
*
* status
*
* History:
*
* Rewrite it:
* 05-Feb-1996 -by- Hideyuki Nagase [hideyukn]
* Write it:
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL WINAPI
GetICMProfileA(
HDC hdc,
LPDWORD pBufSize,
LPSTR pszFilename
)
{
BOOL bRet = FALSE;
WCHAR wchProfile[MAX_PATH];
DWORD BufSizeW = MAX_PATH;
ICMAPI(("gdi32: GetICMProfileA\n"));
if (pBufSize == NULL)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return(FALSE);
}
//
// Call W version.
//
if (GetICMProfileW(hdc,&BufSizeW,wchProfile))
{
CHAR chProfile[MAX_PATH];
DWORD BufSizeA = MAX_PATH;
if (BufSizeW)
{
//
// Unicode to Ansi convertion
//
BufSizeA = WideCharToMultiByte(CP_ACP,0,
wchProfile,BufSizeW,
chProfile,BufSizeA,
NULL,NULL);
if ((pszFilename == NULL) || (*pBufSize < BufSizeA))
{
//
// if the buffer is not given or not enough, return nessesary buffer size and error.
//
*pBufSize = BufSizeA;
GdiSetLastError(ERROR_INSUFFICIENT_BUFFER);
}
else
{
//
// copy converted string to buffer.
//
lstrcpyA(pszFilename,chProfile);
*pBufSize = BufSizeA;
bRet = TRUE;
}
}
}
return(bRet);
}
/******************************Public*Routine******************************\
* GetICMProfileW - read icm profile from DC
*
* Arguments:
*
* hdc - DC
* szBuffer - size of user buffer
* pszFilename - user W buffer
*
* Return Value:
*
* Boolean
*
* History:
*
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL WINAPI
GetICMProfileW(
HDC hdc,
LPDWORD pBufSize,
LPWSTR pszFilename
)
{
PDC_ATTR pdcattr;
ICMAPI(("gdi32: GetICMProfileW\n"));
FIXUP_HANDLE(hdc);
if (pBufSize == NULL)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return(FALSE);
}
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (pdcattr)
{
PGDI_ICMINFO pIcmInfo;
PWSZ pwszProfile = NULL;
ULONG ulSize = 0;
//
// Initialize ICMINFO
//
if ((pIcmInfo = INIT_ICMINFO(hdc,pdcattr)) == NULL)
{
WARNING("gdi32: GetICMProfileW: Can't init icm info\n");
return(FALSE);
}
if (IsColorDeviceContext(hdc))
{
//
// Load external ICM dll
//
LOAD_ICMDLL(FALSE);
//
// if there is no destination profile for the DC, then load
// the defualt
//
IcmUpdateLocalDCColorSpace(hdc,pdcattr);
if (pIcmInfo->pDestColorSpace)
{
//
// Get profile name in destination colorspace.
//
pwszProfile = pIcmInfo->pDestColorSpace->LogColorSpace.lcsFilename;
}
}
else
{
ICMMSG(("GetICMProfile(): for Mono-device\n"));
//
// There is no destination profile AS default,
// *BUT* if Apps set it by calling SetICMProfile(), return it.
//
if (pIcmInfo->flInfo & ICM_VALID_CURRENT_PROFILE)
{
pwszProfile = pIcmInfo->DefaultDstProfile;
}
}
if (pwszProfile)
{
ulSize = lstrlenW(pwszProfile) + 1; // + 1 for null-terminated
}
if (ulSize <= 1)
{
//
// No profile, Or only NULL character.
//
GdiSetLastError(ERROR_PROFILE_NOT_FOUND);
return(FALSE);
}
else if (*pBufSize >= ulSize)
{
//
// There is enough buffer, copy filename.
//
lstrcpyW(pszFilename,pwszProfile);
*pBufSize = ulSize;
return (TRUE);
}
else
{
//
// if buffer is not presented or it's too small,
// returns the nessesary buffer size.
//
GdiSetLastError(ERROR_INSUFFICIENT_BUFFER);
*pBufSize = ulSize;
return (FALSE);
}
}
//
// something error.
//
GdiSetLastError(ERROR_INVALID_PARAMETER);
return(FALSE);
}
/******************************Public*Routine******************************\
* SetICMProfileA - convert the profile string to WCHAR and save in DC
*
* Arguments:
*
* hdc - DC
* pszFileName - Profile name
*
* Return Value:
*
* status
*
* History:
*
* Rewrite it:
* 23-Jan-1996 -by- Hideyuki Nagase [hideyukn]
* Write it:
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL META WINAPI
SetICMProfileA(
HDC hdc,
LPSTR pszFileName
)
{
ICMAPI(("gdi32: SetICMProfileA\n"));
return (SetICMProfileInternalA(hdc,pszFileName,NULL,0));
}
BOOL
SetICMProfileInternalA(
HDC hdc,
LPSTR pszFileName,
PCACHED_COLORSPACE pColorSpace,
DWORD dwFlags
)
{
BOOL bRet = FALSE;
//
// Check parameter either pColorSpace or pszFilename should be given.
//
if (pColorSpace)
{
ICMAPI(("gdi32: SetICMProfileA by ColorSpace (%ws):dwFlags - %d\n",
pColorSpace->LogColorSpace.lcsFilename,dwFlags));
}
else if (pszFileName)
{
ICMAPI(("gdi32: SetICMProfileA by profile name (%s):dwFlags - %x\n",
pszFileName,dwFlags));
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
if (IS_ALTDC_TYPE(hdc))
{
PLDC pldc;
if (IS_METADC16_TYPE(hdc))
return(bRet);
DC_PLDC(hdc,pldc,bRet)
if (pldc->iType == LO_METADC)
{
if (!MF_SetICMProfile(hdc,
(LPBYTE)pszFileName,
(PVOID)pColorSpace,
EMR_SETICMPROFILEA))
{
return((int)FALSE);
}
}
}
if (pColorSpace)
{
//
// Select the given profile into DC.
//
// (this increments ref count of pColorSpace)
//
bRet = IcmSetDestinationColorSpace(hdc,NULL,pColorSpace,dwFlags);
}
else if (pszFileName)
{
ULONG ulSize = lstrlenA(pszFileName);
if (ulSize && (ulSize < MAX_PATH))
{
WCHAR pwszCapt[MAX_PATH];
//
// let me count null-terminate char.
//
ulSize += 1;
//
// Convert to Unicode.
//
vToUnicodeN(pwszCapt,MAX_PATH,pszFileName,ulSize);
//
// Select the given profile into DC.
//
bRet = IcmSetDestinationColorSpace(hdc,pwszCapt,NULL,dwFlags);
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
}
return(bRet);
}
/******************************Public*Routine******************************\
* SetICMProfileW - set profile name into DC
*
* Arguments:
*
* Return Value:
*
* History:
*
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL META WINAPI
SetICMProfileW(
HDC hdc,
LPWSTR pwszFileName
)
{
ICMAPI(("gdi32: SetICMProfileW\n"));
return (SetICMProfileInternalW(hdc,pwszFileName,NULL,0));
}
BOOL
SetICMProfileInternalW(
HDC hdc,
LPWSTR pwszFileName,
PCACHED_COLORSPACE pColorSpace,
DWORD dwFlags
)
{
BOOL bRet = FALSE;
//
// Check parameter either pColorSpace or pszFilename should be given.
//
if (pColorSpace)
{
ICMAPI(("gdi32: SetICMProfileW by ColorSpace (%ws):dwFlags - %x\n",
pColorSpace->LogColorSpace.lcsFilename,dwFlags));
}
else if (pwszFileName)
{
ICMAPI(("gdi32: SetICMProfileW by profile name (%ws):dwFlags - %d\n",
pwszFileName,dwFlags));
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
FIXUP_HANDLE(hdc);
if (IS_ALTDC_TYPE(hdc))
{
PLDC pldc;
if (IS_METADC16_TYPE(hdc))
return(bRet);
DC_PLDC(hdc,pldc,bRet)
if (pldc->iType == LO_METADC)
{
if (!MF_SetICMProfile(hdc,
(LPBYTE)pwszFileName,
(PVOID)pColorSpace,
EMR_SETICMPROFILEW))
{
return((int)FALSE);
}
}
}
//
// Select the given profile into DC.
//
// (this increments ref count of pColorSpace)
//
bRet = IcmSetDestinationColorSpace(hdc,pwszFileName,pColorSpace,dwFlags);
return (bRet);
}
/******************************Public*Routine******************************\
* EnumICMProfilesA
*
* Arguments:
*
* hdc
* lpEnumGamutMatchProc
* lParam
*
* Return Value:
*
* History:
*
* Write it:
* 13-Feb-1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
int WINAPI
EnumICMProfilesA(
HDC hdc,
ICMENUMPROCA lpEnumGamutMatchProc,
LPARAM lParam
)
{
int iRet = -1;
BOOL bRet;
ICMAPI(("gdi32: EnumICMProfileA\n"));
FIXUP_HANDLE(hdc);
VALIDATE_HANDLE(bRet,hdc,DC_TYPE);
if (bRet && (lpEnumGamutMatchProc != NULL))
{
iRet = IcmEnumColorProfile(hdc,lpEnumGamutMatchProc,lParam,TRUE,NULL,NULL);
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
return(iRet);
}
/******************************Public*Routine******************************\
* EnumICMProfilesW
*
* Arguments:
*
* hdc
* lpEnumGamutMatchProc
* lParam
*
* Return Value:
*
* History:
*
* Write it:
* 13-Feb-1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
int WINAPI
EnumICMProfilesW(
HDC hdc,
ICMENUMPROCW lpEnumGamutMatchProc,
LPARAM lParam
)
{
int iRet = -1;
BOOL bRet;
ICMAPI(("gdi32: EnumICMProfileW\n"));
FIXUP_HANDLE(hdc);
VALIDATE_HANDLE(bRet,hdc,DC_TYPE);
if (bRet && (lpEnumGamutMatchProc != NULL))
{
iRet = IcmEnumColorProfile(hdc,lpEnumGamutMatchProc,lParam,FALSE,NULL,NULL);
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
return(iRet);
}
/******************************Public*Routine******************************\
* UpdateICMRegKeyW()
*
* History:
* 8-Jan-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL WINAPI
UpdateICMRegKeyW(
DWORD Reserved,
PWSTR pwszICMMatcher,
PWSTR pwszFileName,
UINT Command
)
{
BOOL bRet = FALSE;
int iRet;
ICMAPI(("gdi32: UpdateICMRegKeyW\n"));
if (Reserved != 0)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return(FALSE);
}
//
// Load external ICM dlls
//
LOAD_ICMDLL(FALSE);
switch (Command)
{
case ICM_ADDPROFILE:
if (pwszFileName)
{
//
// Call InstallColorProfileA() in mscms.dll
//
bRet = (*fpInstallColorProfileW)(NULL, pwszFileName);
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
break;
case ICM_DELETEPROFILE:
if (pwszFileName)
{
//
// Call UninstallColorProfileW() in mscms.dll
//
bRet = (*fpUninstallColorProfileW)(NULL, pwszFileName, FALSE);
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
break;
case ICM_QUERYPROFILE:
if (pwszFileName)
{
PROFILECALLBACK_DATA QueryProfile;
QueryProfile.pwszFileName = GetFileNameFromPath(pwszFileName);
QueryProfile.bFound = FALSE;
if (QueryProfile.pwszFileName != NULL)
{
//
// Enumrate all registered profile to find this profile.
//
IcmEnumColorProfile(NULL,IcmQueryProfileCallBack,(LPARAM)(&QueryProfile),FALSE,NULL,NULL);
//
// Is that found ?
//
bRet = QueryProfile.bFound;
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
break;
case ICM_SETDEFAULTPROFILE:
//
// Not supported.
//
GdiSetLastError(ERROR_CALL_NOT_IMPLEMENTED);
break;
case ICM_REGISTERICMATCHER:
if (pwszICMMatcher && pwszFileName)
{
DWORD dwCMM = *((DWORD *)pwszICMMatcher);
//
// Call RegisterCMMW() in mscms.dll
//
bRet = (*fpRegisterCMMW)(NULL, IcmSwapBytes(dwCMM), pwszFileName);
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
break;
case ICM_UNREGISTERICMATCHER:
if (pwszICMMatcher)
{
DWORD dwCMM = *((DWORD *)pwszICMMatcher);
//
// Call UnregisterCMMW() in mscms.dll
//
bRet = (*fpUnregisterCMMW)(NULL, IcmSwapBytes(dwCMM));
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
break;
case ICM_QUERYMATCH:
if (pwszFileName)
{
//
// Find match profile.
//
iRet = IcmEnumColorProfile(NULL,NULL,0,FALSE,(PDEVMODEW)pwszFileName,NULL);
//
// Adjust return value, because IcmEnumColorProfile returns -1 if not found.
// and 0 for error (since no callback function)
//
if (iRet > 0)
{
bRet = TRUE;
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
break;
default:
WARNING("gdi32!UpdateICMRegKeyW():Invalid Command\n");
GdiSetLastError(ERROR_INVALID_PARAMETER);
break;
}
return bRet;
}
/******************************Public*Routine******************************\
* UpdateICMRegKeyA
*
* Arguments:
*
* Reserved
* szICMMatcher
* szFileName
* Command
*
* Return Value:
*
* Status
*
* History:
*
* 8-Jan-1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
BOOL WINAPI
UpdateICMRegKeyA(
DWORD Reserved,
PSTR szICMMatcher,
PSTR szFileName,
UINT Command
)
{
BOOL bRet = FALSE;
BOOL bError = FALSE;
PWSTR pwszFileName = NULL;
//
// szICMMatcher points to 4 bytes CMM ID, actually it is not "string".
// Ansi to Unicode conversion is not needed.
//
PWSTR pwszICMMatcher = (PWSTR) szICMMatcher;
ULONG cjSize;
ICMAPI(("gdi32: UpdateICMRegKeyA\n"));
if (Reserved != 0)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return(FALSE);
}
switch (Command)
{
case ICM_ADDPROFILE:
case ICM_DELETEPROFILE:
case ICM_QUERYPROFILE:
case ICM_REGISTERICMATCHER:
//
// szFileName should be presented.
//
if (szFileName)
{
//
// szFileName points to ansi string, just convert to Unicode.
//
cjSize = lstrlenA(szFileName)+1;
pwszFileName = LOCALALLOC((cjSize)*sizeof(WCHAR));
if (pwszFileName == NULL)
{
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return (bRet);
}
vToUnicodeN(pwszFileName,cjSize,szFileName,cjSize);
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
bError = TRUE;
}
break;
case ICM_QUERYMATCH:
//
// szFileName should be presented.
//
if (szFileName)
{
//
// szFileName points to DEVMODEA structure, convert it to DEVMODEW
//
pwszFileName = (PWSTR) GdiConvertToDevmodeW((DEVMODEA *)szFileName);
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
bError = TRUE;
}
break;
case ICM_SETDEFAULTPROFILE:
GdiSetLastError(ERROR_CALL_NOT_IMPLEMENTED);
bError = TRUE;
break;
case ICM_UNREGISTERICMATCHER:
//
// Nothing to convert to Unicode.
//
ASSERTGDI(szFileName==NULL,"UpdateICMRegKeyA():szFileName is not null\n");
break;
default:
WARNING("GDI:UpdateICMRegKeyA():Command is invalid\n");
GdiSetLastError(ERROR_INVALID_PARAMETER);
bError = TRUE;
break;
}
if (!bError)
{
//
// Call W version.
//
bRet = UpdateICMRegKeyW(Reserved,pwszICMMatcher,pwszFileName,Command);
}
if (pwszFileName)
{
LOCALFREE(pwszFileName);
}
return(bRet);
}
/******************************Public*Routine******************************\
* GetDeviceGammaRamp
*
* Arguments:
*
* hdc
* lpGammaRamp
*
* Return Value:
*
* Status
*
* History:
*
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL WINAPI
GetDeviceGammaRamp(
HDC hdc,
LPVOID lpGammaRamp
)
{
BOOL bRet = FALSE;
ICMAPI(("gdi32: GetDeviceGammaRamp\n"));
if (lpGammaRamp == NULL)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
else
{
//
// Call kernel to get current Gamma ramp array for this DC.
//
bRet = NtGdiGetDeviceGammaRamp(hdc,lpGammaRamp);
}
return(bRet);
}
/******************************Public*Routine******************************\
* SetDeviceGammaRamp
*
* Arguments:
*
* hdc
* lpGammaRamp
*
* Return Value:
*
* Status
*
* History:
*
* 5-Jun-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL WINAPI
SetDeviceGammaRamp(
HDC hdc,
LPVOID lpGammaRamp
)
{
BOOL bRet = FALSE;
ICMAPI(("gdi32: SetDeviceGammaRamp\n"));
if (lpGammaRamp == NULL)
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
else
{
//
// Call kernel to set new Gamma ramp array for this DC.
//
bRet = NtGdiSetDeviceGammaRamp(hdc,lpGammaRamp);
}
return(bRet);
}
/******************************Public*Routine******************************\
* ColorCorrectPalette
*
* If this is not the default palette and ICM is turned on in the DC
* then translate the specified palette entries according to the color
* transform in the DC
*
* Arguments:
*
* hdc - DC handle
* hpal - PALETTE handle
* FirsrEntry - first entry in palette to translate
* NumberOfEntries - number of entries to translate
*
* Return Value:
*
* Status
*
* History:
*
* Write it:
* 13-Feb-1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
BOOL META WINAPI
ColorCorrectPalette(
HDC hdc,
HPALETTE hpal,
ULONG FirstEntry,
ULONG NumberOfEntries
)
{
BOOL bStatus = FALSE;
PDC_ATTR pdcattr = NULL;
ICMAPI(("gdi32: ColorCorrectPalette\n"));
//
// Parameter check (max entry of log palette is 0x65536)
//
if ((hdc == NULL) || (hpal == NULL) ||
(NumberOfEntries == 0) || (NumberOfEntries > 65536) ||
(FirstEntry >= 65536) || (65536 - NumberOfEntries < FirstEntry))
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
return (FALSE);
}
//
// default palette could not be changed...
//
if (hpal != (HPALETTE)GetStockObject(DEFAULT_PALETTE))
{
//
// metafile call
//
if (IS_ALTDC_TYPE(hdc))
{
PLDC pldc;
if (IS_METADC16_TYPE(hdc))
return(bStatus);
DC_PLDC(hdc,pldc,bStatus);
if (pldc->iType == LO_METADC)
{
if (!MF_ColorCorrectPalette(hdc,hpal,FirstEntry,NumberOfEntries))
{
return(FALSE);
}
}
}
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (pdcattr)
{
//
// Load external ICM dlls
//
LOAD_ICMDLL(FALSE);
if (IS_ICM_HOST(pdcattr->lIcmMode))
{
if (bNeedTranslateColor(pdcattr))
{
PPALETTEENTRY ppalEntrySrc = NULL;
PPALETTEENTRY ppalEntryDst = NULL;
ULONG NumEntriesRetrieved = 0;
//
// Make sure palette can be color corrected, get requested entries
//
ULONG Index;
ppalEntrySrc = LOCALALLOC((NumberOfEntries * sizeof(PALETTEENTRY)) * 2);
if (ppalEntrySrc == NULL)
{
WARNING("ColorCorrectPalette: ppalEntry = NULL\n");
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
return(bStatus);
}
NumEntriesRetrieved = NtGdiColorCorrectPalette(hdc,
hpal,
FirstEntry,
NumberOfEntries,
ppalEntrySrc,
ColorPaletteQuery);
if (NumEntriesRetrieved > 0)
{
ppalEntryDst = ppalEntrySrc + NumberOfEntries;
//
// Translate palette entry colors
//
IcmTranslatePaletteEntry(hdc,pdcattr,ppalEntrySrc,ppalEntryDst,NumEntriesRetrieved);
//
// set new palette entries
//
NumEntriesRetrieved = NtGdiColorCorrectPalette(hdc,
hpal,
FirstEntry,
NumEntriesRetrieved,
ppalEntryDst,
ColorPaletteSet);
if (NumEntriesRetrieved > 0)
{
bStatus = TRUE;
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
LOCALFREE(ppalEntrySrc);
}
else
{
//
// Don't need to translate color.
//
bStatus = TRUE;
}
}
else if (IS_ICM_DEVICE(pdcattr->lIcmMode))
{
//
// for device ICM, don't need to do anything.
//
bStatus = TRUE;
}
else
{
WARNING("ColorCorrectPalette():ICM mode is not enabled\n");
GdiSetLastError(ERROR_ICM_NOT_ENABLED);
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
return bStatus;
}
/******************************Public*Routine******************************\
* IcmTranslateColorObjects - called when there is a change in ICM color transfrom
* state
*
* Arguments:
*
* hdc - input DC
* pdcattr - DC's attrs
*
* Return Value:
*
* status
*
* History:
*
* Rewrite it:
* 13-Feb-1997 -by- Hideyuki Nagase [hideyukn]
* Write it:
* 9-Jul-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL
IcmTranslateColorObjects(
HDC hdc,
PDC_ATTR pdcattr,
BOOL bICMEnable
)
{
BOOL bStatus = TRUE;
COLORREF OldColor;
COLORREF NewColor;
ICMAPI(("gdi32: IcmTranslateColorObjects\n"));
//
// Invalidate IcmPenColor/IcmBrushColor
//
pdcattr->ulDirty_ &= ~(ICM_PEN_TRANSLATED | ICM_BRUSH_TRANSLATED);
if (bICMEnable)
{
if(bNeedTranslateColor(pdcattr))
{
if (GetColorTransformInDC(pdcattr) == NULL)
{
WARNING("Error in IcmTranslateColorObjects: called when hcmXform == NULL");
return FALSE;
}
//
// translate Foreground to new icm mode if not paletteindex
//
if (!(pdcattr->ulForegroundClr & 0x01000000))
{
OldColor = pdcattr->ulForegroundClr;
bStatus = IcmTranslateCOLORREF(hdc,
pdcattr,
OldColor,
&NewColor,
ICM_FORWARD);
if (bStatus)
{
pdcattr->crForegroundClr = NewColor;
}
else
{
pdcattr->crForegroundClr = OldColor;
}
}
//
// translate Background to new icm mode if not paletteindex
//
if (!(pdcattr->ulBackgroundClr & 0x01000000))
{
OldColor = pdcattr->ulBackgroundClr;
bStatus = IcmTranslateCOLORREF(hdc,
pdcattr,
OldColor,
&NewColor,
ICM_FORWARD);
if (bStatus)
{
pdcattr->crBackgroundClr = NewColor;
}
else
{
pdcattr->crBackgroundClr = OldColor;
}
}
//
// translate DCBrush to new icm mode if not paletteindex
//
if (!(pdcattr->ulDCBrushClr & 0x01000000))
{
OldColor = pdcattr->ulDCBrushClr;
bStatus = IcmTranslateCOLORREF(hdc,
pdcattr,
OldColor,
&NewColor,
ICM_FORWARD);
if (bStatus)
{
pdcattr->crDCBrushClr = NewColor;
}
else
{
pdcattr->crDCBrushClr = OldColor;
}
}
//
// translate DCPen to new icm mode if not paletteindex
//
if (!(pdcattr->ulDCPenClr & 0x01000000))
{
OldColor = pdcattr->ulDCPenClr;
bStatus = IcmTranslateCOLORREF(hdc,
pdcattr,
OldColor,
&NewColor,
ICM_FORWARD);
if (bStatus)
{
pdcattr->crDCPenClr = NewColor;
}
else
{
pdcattr->crDCPenClr = OldColor;
}
}
//
// set icm color of selected logical brush
//
IcmTranslateBrushColor(hdc,pdcattr,(HANDLE)pdcattr->hbrush);
//
// set icm color of selected logical pen/extpen
//
if (LO_TYPE(pdcattr->hpen) == LO_EXTPEN_TYPE)
{
IcmTranslateExtPenColor(hdc,pdcattr,(HANDLE)pdcattr->hpen);
}
else
{
IcmTranslatePenColor(hdc,pdcattr,(HANDLE)pdcattr->hpen);
}
}
}
else
{
PBRUSHATTR pbrushattr;
//
// ICM is off, restore colors (non device icm only)
//
pdcattr->crForegroundClr = pdcattr->ulForegroundClr & 0x13ffffff;
pdcattr->crBackgroundClr = pdcattr->ulBackgroundClr & 0x13ffffff;
pdcattr->crDCBrushClr = pdcattr->ulDCBrushClr & 0x13ffffff;
pdcattr->crDCPenClr = pdcattr->ulDCPenClr & 0x13ffffff;
//
// set icm color of selected logical brush
//
PSHARED_GET_VALIDATE(pbrushattr,pdcattr->hbrush,BRUSH_TYPE);
if (pbrushattr)
{
pdcattr->IcmBrushColor = pbrushattr->lbColor;
}
//
// set icm color of selected logical pen
//
PSHARED_GET_VALIDATE(pbrushattr,pdcattr->hpen,BRUSH_TYPE);
if (pbrushattr)
{
pdcattr->IcmPenColor = pbrushattr->lbColor;
}
}
//
// set DC dirty flags to force re-realization of color objects
//
pdcattr->ulDirty_ |= (DIRTY_BRUSHES|DC_BRUSH_DIRTY|DC_PEN_DIRTY);
return(bStatus);
}
/******************************Public*Routine******************************\
* IcmCreateTemporaryColorProfile()
*
* History:
*
* Wrote it:
* 7.May.1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmCreateTemporaryColorProfile(
LPWSTR TemporaryColorProfile,
LPBYTE ProfileData,
DWORD ProfileDataSize
)
{
BOOL bRet = FALSE;
WCHAR TempPath[MAX_PATH];
WCHAR TempFile[MAX_PATH];
//
// make temp file for profile, include name in lcspw
//
if (GetTempPathW(MAX_PATH,(LPWSTR)TempPath))
{
BOOL bPathOK = TRUE;
if (TemporaryColorProfile[0] != UNICODE_NULL)
{
wcscpy(TempFile,TempPath);
wcscat(TempFile,TemporaryColorProfile);
}
else
{
bPathOK = GetTempFileNameW((LPWSTR)TempPath,L"ICM",0,(LPWSTR)TempFile);
}
if (bPathOK)
{
if (ProfileDataSize == 0)
{
//
// Nothing needs to save, just return with created filename
//
lstrcpyW(TemporaryColorProfile,TempFile);
bRet = TRUE;
}
else
{
HANDLE hFile = CreateFileW((LPWSTR)TempFile,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hFile != INVALID_HANDLE_VALUE)
{
ULONG ulWritten;
if (WriteFile(hFile,ProfileData,ProfileDataSize,&ulWritten,NULL))
{
//
// Put the created file name into LOGCOLORSPACE
//
lstrcpyW(TemporaryColorProfile,TempFile);
//
// Close file handle
//
CloseHandle(hFile);
//
// Everything O.K.
//
bRet = TRUE;
}
else
{
ICMWRN(("IcmCreateTemporaryColorProfile(): Failed WriteFile\n"));
//
// Failed, close handle and delete it.
//
CloseHandle(hFile);
DeleteFileW(TempFile);
}
}
else
{
ICMWRN(("IcmCreateTemporaryColorProfile(): Failed CreateFile\n"));
}
}
}
else
{
ICMWRN(("IcmCreateTemporaryColorProfile(): Failed CreateTempFileName\n"));
}
}
else
{
ICMWRN(("IcmCreateTemporayColorProfile(): Failed GetTempPath\n"));
}
return (bRet);
}
/******************************Public*Routine******************************\
* IcmGetBitmapColorSpace()
*
* History:
*
* Wrote it:
* 13.March.1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmGetBitmapColorSpace(
LPBITMAPINFO pbmi,
LPLOGCOLORSPACEW plcspw,
PPROFILE pColorProfile,
PDWORD pdwFlags
)
{
BOOL bBitmapColorSpace = FALSE;
ICMAPI(("gdi32: IcmGetBitmapColorSpace\n"));
//
// Init output buffers with zero.
//
*pdwFlags = 0;
ZeroMemory(plcspw,sizeof(LOGCOLORSPACE));
ZeroMemory(pColorProfile,sizeof(PROFILE));
//
// check for BITMAPV4 OR BITMAPV5
//
if (pbmi->bmiHeader.biSize == sizeof(BITMAPV4HEADER))
{
PBITMAPV4HEADER pbmih4 = (PBITMAPV4HEADER)&pbmi->bmiHeader;
ICMMSG(("IcmGetBitmapColorSpace: BITMAPV4HEADER\n"));
//
// if CIEXYZ endpoints are given, create a new color transform
// to use.
//
plcspw->lcsSignature = LCS_SIGNATURE;
plcspw->lcsVersion = 0x400;
plcspw->lcsSize = sizeof(LOGCOLORSPACEW);
plcspw->lcsCSType = pbmih4->bV4CSType;
plcspw->lcsIntent = LCS_GM_IMAGES;
plcspw->lcsEndpoints = pbmih4->bV4Endpoints;
plcspw->lcsGammaRed = pbmih4->bV4GammaRed;
plcspw->lcsGammaGreen = pbmih4->bV4GammaGreen;
plcspw->lcsGammaBlue = pbmih4->bV4GammaBlue;
if (pbmih4->bV4CSType == LCS_CALIBRATED_RGB)
{
ICMMSG(("IcmGetBitmapColorSpace: BITMAPv4 CALIBRATED RGB\n"));
ICMMSG((" lcspw.lcsCSType = %x\n",pbmih4->bV4CSType));
ICMMSG((" lcspw.lcsIntent = %d\n",LCS_GM_IMAGES));
ICMMSG((" lcspw.lcsGammaRed = %d\n",pbmih4->bV4GammaRed));
ICMMSG((" lcspw.lcsGammaGreen = %d\n",pbmih4->bV4GammaGreen));
//
// There is no profile specified.
//
plcspw->lcsFilename[0] = UNICODE_NULL;
bBitmapColorSpace = TRUE;
}
else // any other CSType
{
DWORD dwSize = MAX_PATH;
ICMMSG(("IcmGetBitmapColorSpace: BITMAPv4 lcsType = %x\n",pbmih4->bV4CSType));
//
// Load external ICM dlls.
//
LOAD_ICMDLL((int)FALSE);
//
// Get corresponding colorspace profile.
//
bBitmapColorSpace =
(*fpGetStandardColorSpaceProfileW)(NULL,
pbmih4->bV4CSType,
plcspw->lcsFilename,
&dwSize);
}
}
else if (pbmi->bmiHeader.biSize == sizeof(BITMAPV5HEADER))
{
PBITMAPV5HEADER pbmih5 = (PBITMAPV5HEADER)&pbmi->bmiHeader;
ICMMSG(("IcmGetBitmapColorSpace: BITMAPV5HEADER\n"));
ICMMSG((" lcspw.lcsCSType = %x\n",pbmih5->bV5CSType));
ICMMSG((" lcspw.lcsIntent = %d\n",pbmih5->bV5Intent));
//
// fill in common logcolorspace info
//
plcspw->lcsSignature = LCS_SIGNATURE;
plcspw->lcsVersion = 0x400;
plcspw->lcsSize = sizeof(LOGCOLORSPACEW);
plcspw->lcsCSType = pbmih5->bV5CSType;
plcspw->lcsIntent = pbmih5->bV5Intent;
plcspw->lcsEndpoints = pbmih5->bV5Endpoints;
plcspw->lcsGammaRed = pbmih5->bV5GammaRed;
plcspw->lcsGammaGreen = pbmih5->bV5GammaGreen;
plcspw->lcsGammaBlue = pbmih5->bV5GammaBlue;
//
// validate Intent
//
if ((plcspw->lcsIntent != LCS_GM_BUSINESS) &&
(plcspw->lcsIntent != LCS_GM_GRAPHICS) &&
(plcspw->lcsIntent != LCS_GM_IMAGES) &&
(plcspw->lcsIntent != LCS_GM_ABS_COLORIMETRIC))
{
//
// Intent is invalid, just use LCS_GM_IMAGES
//
plcspw->lcsIntent = LCS_GM_IMAGES;
}
//
// If a profile is linked or embedded then use it.
// otherwise:
// If CIEXYZ endpoints are given, create a new color transform
// to use.
//
if (pbmih5->bV5CSType == PROFILE_EMBEDDED)
{
PVOID pProfileEmbedded = NULL;
ICMMSG(("IcmGetBitmapColorSpace: Embedded profile\n"));
//
// Update CSType to Calibrated_RGB from Profile_Embedded
//
plcspw->lcsCSType = LCS_CALIBRATED_RGB;
//
// Get pointer to embeded profile.
//
pProfileEmbedded = (PVOID)((PBYTE)pbmi + pbmih5->bV5ProfileData);
if (pProfileEmbedded)
{
//
// Fill up PROFILE structure for "on memory" profile.
//
pColorProfile->dwType = PROFILE_MEMBUFFER;
pColorProfile->pProfileData = pProfileEmbedded;
pColorProfile->cbDataSize = pbmih5->bV5ProfileSize;
//
// Mark as on memory profile.
//
*pdwFlags |= ON_MEMORY_PROFILE;
}
else
{
//
// This bitmap marked as "Embedded", but no profile there, just go with LOGCOLORSPACE.
//
ICMWRN(("IcmGetBitmapColorSpace(): Embedded profile, but no profile embedded\n"));
}
bBitmapColorSpace = TRUE;
}
else if (pbmih5->bV5CSType == PROFILE_LINKED)
{
WCHAR LinkedProfile[MAX_PATH];
ICMMSG(("IcmGetBitmapColorSpace(): linked profile\n"));
//
// Update CSType to Calibrated_RGB from Profile_Linked
//
plcspw->lcsCSType = LCS_CALIBRATED_RGB;
//
// Convert profile name to Unicode.
//
vToUnicodeN(
LinkedProfile, MAX_PATH,
(CONST CHAR *)((PBYTE)pbmih5 + pbmih5->bV5ProfileData),
strlen((CONST CHAR *)((PBYTE)pbmih5 + pbmih5->bV5ProfileData))+1
);
//
// Normalize profile path.
//
BuildIcmProfilePath(LinkedProfile,plcspw->lcsFilename,MAX_PATH);
ICMMSG(("lcspw.lcsFilename = %ws\n",plcspw->lcsFilename));
bBitmapColorSpace = TRUE;
}
else if (pbmih5->bV5CSType == LCS_CALIBRATED_RGB)
{
ICMMSG(("IcmGetBitmapColorSpace(): calibrated RGB\n"));
ICMMSG((" lcspw.lcsGammaRed = %d\n",pbmih5->bV5GammaRed));
ICMMSG((" lcspw.lcsGammaGreen = %d\n",pbmih5->bV5GammaGreen));
ICMMSG((" lcspw.lcsGammaBlue = %d\n",pbmih5->bV5GammaBlue));
//
// There is profile specified.
//
plcspw->lcsFilename[0] = UNICODE_NULL;
bBitmapColorSpace = TRUE;
}
else // any other CSType
{
DWORD dwSize = MAX_PATH;
ICMMSG(("IcmGetBitmapColorSpace: BITMAPv5 lcsType = %x\n",pbmih5->bV5CSType));
//
// Load external ICM dlls.
//
LOAD_ICMDLL((int)FALSE);
//
// Get corresponding colorspace profile.
//
bBitmapColorSpace =
(*fpGetStandardColorSpaceProfileW)(NULL,
pbmih5->bV5CSType,
plcspw->lcsFilename,
&dwSize);
}
}
else
{
ICMMSG(("IcmGetBitmapColorSpace(): no color space specified\n"));
}
return (bBitmapColorSpace);
}
/******************************Public*Routine******************************\
* IcmGetTranslateInfo()
*
* History:
*
* Wrote it:
* 13.March.1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmGetTranslateInfo(
PDC_ATTR pdcattr,
LPBITMAPINFO pbmi,
PVOID pvBits,
ULONG cjBits,
DWORD dwNumScan,
PDIB_TRANSLATE_INFO pdti,
DWORD dwFlags
)
{
BMFORMAT ColorType;
PVOID pOutput;
ULONG nColors;
ULONG cjTranslateBits;
PBITMAPINFO pbmiNew = NULL;
BOOL bCMYKColor = IS_CMYK_COLOR(pdcattr->lIcmMode);
ICMAPI(("gdi32: IcmGetTranslateInfo\n"));
ICMAPI(("-----: CMYK Color = %s\n",(bCMYKColor ? "Yes" : "No")));
ICMAPI(("-----: Backward = %s\n",((dwFlags & ICM_BACKWARD) ? "Yes" : "No")));
UNREFERENCED_PARAMETER(dwFlags);
if (dwNumScan == (DWORD)-1)
{
dwNumScan = ABS(pbmi->bmiHeader.biHeight);
}
//
// determine whether this is a palettized DIB
//
if (pbmi->bmiHeader.biCompression == BI_RGB)
{
if (pbmi->bmiHeader.biBitCount > 8)
{
//
// we will translate bitmap, pvBits should be presented.
//
if (pvBits == NULL)
{
return (FALSE);
}
//
// must translate DIB, standard 16,24,32 format
//
if (pbmi->bmiHeader.biBitCount == 16)
{
ICMMSG(("IcmGetTranslateInfo():BI_RGB 16 bpp\n"));
ColorType = BM_x555RGB;
}
else if (pbmi->bmiHeader.biBitCount == 24)
{
ICMMSG(("IcmGetTranslateInfo():BI_RGB 24 bpp\n"));
ColorType = BM_RGBTRIPLETS;
}
else if (pbmi->bmiHeader.biBitCount == 32)
{
ICMMSG(("IcmGetTranslateInfo():BI_RGB 32 bpp\n"));
ColorType = BM_xRGBQUADS;
}
else
{
ICMMSG(("IcmGetTranslateInfo():BI_RGB Invalid bpp\n"));
return (FALSE);
}
//
// Fill up source bitmap information.
//
pdti->SourceWidth = pbmi->bmiHeader.biWidth;
pdti->SourceHeight = dwNumScan;
pdti->SourceBitCount = pbmi->bmiHeader.biBitCount;
pdti->SourceColorType = ColorType;
pdti->pvSourceBits = pvBits;
pdti->cjSourceBits = cjBits;
//
// CMYK Color ?
//
if (bCMYKColor)
{
pdti->TranslateType = (TRANSLATE_BITMAP|TRANSLATE_HEADER);
//
// CMYK bitmap color bitmap is 32 BPP (4 bytes per pixel).
//
cjTranslateBits = (pdti->SourceWidth * 4) * pdti->SourceHeight;
//
// We need new bitmap info header for CMYK.
//
pbmiNew = LOCALALLOC(pbmi->bmiHeader.biSize);
if (!pbmiNew)
{
WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n");
return (FALSE);
}
//
// Make a copy of source, first.
//
RtlCopyMemory(pbmiNew,pbmi,pbmi->bmiHeader.biSize);
//
// Update header for CMYK color.
//
pbmiNew->bmiHeader.biBitCount = 32;
pbmiNew->bmiHeader.biCompression = BI_CMYK;
pbmiNew->bmiHeader.biSizeImage = cjTranslateBits;
pbmiNew->bmiHeader.biClrUsed = 0;
pbmiNew->bmiHeader.biClrImportant = 0;
//
// We have new BITMAPINFO header
//
pdti->TranslateBitmapInfo = pbmiNew;
pdti->TranslateBitmapInfoSize = pbmi->bmiHeader.biSize;
//
// Translate bitmap color type is CMYK.
//
pdti->TranslateColorType = BM_KYMCQUADS;
}
else
{
pdti->TranslateType = TRANSLATE_BITMAP;
//
// Translate bitmap size is same as source.
//
cjTranslateBits = cjBits;
//
// Translate bitmap color type is same source.
//
pdti->TranslateColorType = ColorType;
pdti->TranslateBitmapInfo = NULL;
pdti->TranslateBitmapInfoSize = 0;
}
//
// Allocate translate buffer
//
pOutput = LOCALALLOC(cjTranslateBits);
if (!pOutput)
{
if (pbmiNew)
{
LOCALFREE(pbmiNew);
}
WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n");
return (FALSE);
}
//
// Setup translation buffer.
//
pdti->pvTranslateBits = pOutput;
pdti->cjTranslateBits = cjTranslateBits;
}
else if (
((pbmi->bmiHeader.biBitCount == 8) ||
(pbmi->bmiHeader.biBitCount == 4) ||
(pbmi->bmiHeader.biBitCount == 1))
)
{
ULONG nMaxColors = (1 << pbmi->bmiHeader.biBitCount);
ICMMSG(("IcmGetTranslateInfo():BI_RGB 8/4/1 bpp\n"));
//
// validate number of colors
//
nColors = pbmi->bmiHeader.biClrUsed;
if ((nColors == 0) || (nColors > nMaxColors))
{
nColors = nMaxColors;
}
//
// Allocate new bitmap info header and color table.
//
pbmiNew = LOCALALLOC(pbmi->bmiHeader.biSize + (nColors * sizeof(RGBQUAD)));
if (!pbmiNew)
{
WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n");
return (FALSE);
}
//
// Copy source BITMAPINFO to new
//
RtlCopyMemory(pbmiNew,pbmi,pbmi->bmiHeader.biSize);
pdti->TranslateType = TRANSLATE_HEADER;
pdti->SourceColorType = BM_xRGBQUADS;
pdti->SourceWidth = nColors;
pdti->SourceHeight = 1;
pdti->SourceBitCount = sizeof(RGBQUAD);
pdti->TranslateBitmapInfo = pbmiNew;
pdti->TranslateBitmapInfoSize = 0; // size will not change from original
pdti->pvSourceBits = (PBYTE)pbmi + pbmi->bmiHeader.biSize;
pdti->cjSourceBits = nColors;
pdti->pvTranslateBits = (PBYTE)pbmiNew + pbmiNew->bmiHeader.biSize;
pdti->cjTranslateBits = nColors * sizeof(RGBQUAD);
if (bCMYKColor)
{
pdti->TranslateColorType = BM_KYMCQUADS;
//
// Update header for CMYK color.
//
pbmiNew->bmiHeader.biCompression = BI_CMYK;
}
else
{
pdti->TranslateColorType = BM_xRGBQUADS;
}
}
else
{
ICMWRN(("IcmGetTranslateInfo: Illegal biBitCount\n"));
return (FALSE);
}
}
else if (
(pbmi->bmiHeader.biCompression == BI_BITFIELDS) &&
(
(pbmi->bmiHeader.biBitCount == 16) ||
(pbmi->bmiHeader.biBitCount == 32)
)
)
{
PULONG pulColors = (PULONG)pbmi->bmiColors;
ICMMSG(("IcmGetTranslateInfo():BI_BITFIELDS 16/32 bpp\n"));
//
// we will translate bitmap, pvBits should be presented.
//
if (pvBits == NULL)
{
return (FALSE);
}
if (pbmi->bmiHeader.biBitCount == 32)
{
if ((pulColors[0] == 0x0000ff) && /* Red */
(pulColors[1] == 0x00ff00) && /* Green */
(pulColors[2] == 0xff0000)) /* Blue */
{
ColorType = BM_xBGRQUADS;
}
else if ((pulColors[0] == 0xff0000) && /* Red */
(pulColors[1] == 0x00ff00) && /* Green */
(pulColors[2] == 0x0000ff)) /* Blue */
{
ColorType = BM_xRGBQUADS;
}
else
{
ICMWRN(("IcmGetTranslateInfo: Illegal Bitfields fields for 32 bpp\n"));
return (FALSE);
}
}
else
{
if ((pulColors[0] == 0x007c00) &&
(pulColors[1] == 0x0003e0) &&
(pulColors[2] == 0x00001f))
{
ColorType = BM_x555RGB;
}
else if ((pulColors[0] == 0x00f800) &&
(pulColors[1] == 0x0007e0) &&
(pulColors[2] == 0x00001f))
{
ColorType = BM_565RGB;
}
else
{
ICMWRN(("IcmGetTranslateInfo: Illegal Bitfields fields for 16 bpp\n"));
return (FALSE);
}
}
//
// Fill up source bitmap information.
//
pdti->SourceWidth = pbmi->bmiHeader.biWidth;
pdti->SourceHeight = dwNumScan;
pdti->SourceBitCount = pbmi->bmiHeader.biBitCount;
pdti->SourceColorType = ColorType;
pdti->pvSourceBits = pvBits;
pdti->cjSourceBits = cjBits;
//
// CMYK Color ?
//
if (bCMYKColor)
{
pdti->TranslateType = (TRANSLATE_BITMAP|TRANSLATE_HEADER);
//
// CMYK bitmap color bitmap is 32 BPP (4 bytes per pixel).
//
cjTranslateBits = (pdti->SourceWidth * 4) * pdti->SourceHeight;
//
// We need new bitmap info header for CMYK.
//
pbmiNew = LOCALALLOC(pbmi->bmiHeader.biSize);
if (!pbmiNew)
{
WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n");
return (FALSE);
}
//
// Make a copy of source, first.
//
RtlCopyMemory(pbmiNew,pbmi,pbmi->bmiHeader.biSize);
//
// Update header for CMYK color.
//
pbmiNew->bmiHeader.biBitCount = 32;
pbmiNew->bmiHeader.biCompression = BI_CMYK;
pbmiNew->bmiHeader.biSizeImage = cjTranslateBits;
pbmiNew->bmiHeader.biClrUsed = 0;
pbmiNew->bmiHeader.biClrImportant = 0;
//
// We have new BITMAPINFO header
//
pdti->TranslateBitmapInfo = pbmiNew;
pdti->TranslateBitmapInfoSize = pbmi->bmiHeader.biSize;
//
// Translate bitmap color type is CMYK.
//
pdti->TranslateColorType = BM_KYMCQUADS;
}
else
{
pdti->TranslateType = TRANSLATE_BITMAP;
//
// Translate bitmap size is same as source.
//
cjTranslateBits = cjBits;
//
// Translate bitmap color type is same source.
//
pdti->TranslateColorType = ColorType;
pdti->TranslateBitmapInfo = NULL;
pdti->TranslateBitmapInfoSize = 0;
}
//
// Allocate translate buffer
//
pOutput = LOCALALLOC(cjTranslateBits);
if (!pOutput)
{
if (pbmiNew)
{
LOCALFREE(pbmiNew);
}
WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n");
return (FALSE);
}
//
// Setup translation buffer.
//
pdti->pvTranslateBits = pOutput;
pdti->cjTranslateBits = cjTranslateBits;
}
else if (
(pbmi->bmiHeader.biCompression == BI_RLE8) ||
(pbmi->bmiHeader.biCompression == BI_RLE4)
)
{
//
// translate 256 for RLE8, 16 for RLE4 entry color palette
//
ULONG nMaxColors;
if (pbmi->bmiHeader.biCompression == BI_RLE8)
{
ICMMSG(("IcmGetTranslateInfo():BI_RLE 8\n"));
nMaxColors = 256;
}
else
{
ICMMSG(("IcmGetTranslateInfo():BI_RLE 4\n"));
nMaxColors = 16;
}
//
// validate number of colors
//
nColors = pbmi->bmiHeader.biClrUsed;
if ((nColors == 0) || (nColors > nMaxColors))
{
nColors = nMaxColors;
}
//
// Allocate new bitmap info header and color table.
//
pbmiNew = LOCALALLOC(pbmi->bmiHeader.biSize + (nColors * sizeof(RGBQUAD)));
if (!pbmiNew)
{
WARNING("IcmGetTranslateInfo():LOCALALLOC() failed\n");
return (FALSE);
}
//
// Copy source BITMAPINFO to new
//
RtlCopyMemory(pbmiNew,pbmi,pbmi->bmiHeader.biSize);
pdti->TranslateType = TRANSLATE_HEADER;
pdti->SourceColorType = BM_xRGBQUADS;
pdti->SourceWidth = nColors;
pdti->SourceHeight = 1;
pdti->SourceBitCount = sizeof(RGBQUAD);
pdti->TranslateBitmapInfo = pbmiNew;
pdti->TranslateBitmapInfoSize = 0; // size will not change from original
pdti->pvSourceBits = (PBYTE)pbmi + pbmi->bmiHeader.biSize;
pdti->cjSourceBits = nColors;
pdti->pvTranslateBits = (PBYTE)pbmiNew + pbmiNew->bmiHeader.biSize;
pdti->cjTranslateBits = nColors * sizeof(RGBQUAD);
if (bCMYKColor)
{
pdti->TranslateColorType = BM_KYMCQUADS;
//
// Update header for CMYK color.
//
if (pbmi->bmiHeader.biCompression == BI_RLE8)
{
ICMMSG(("IcmGetTranslateInfo():BI_CMYKRLE 8\n"));
pbmiNew->bmiHeader.biCompression = BI_CMYKRLE8;
}
else
{
ICMMSG(("IcmGetTranslateInfo():BI_CMYKRLE 4\n"));
pbmiNew->bmiHeader.biCompression = BI_CMYKRLE4;
}
}
else
{
pdti->TranslateColorType = BM_xRGBQUADS;
}
}
else
{
WARNING("IcmGetTranslateInfo():Illegal bitmap format\n");
return (FALSE);
}
return (TRUE);
}
/******************************Public*Routine******************************\
* IcmTranslateDIB
*
* History:
*
* Rewrote it for CMYK color support:
* 13-Mar-1997 -by- Hideyuki Nagase [hideyukn]
* Wrote it:
* 3-Jul-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL
IcmTranslateDIB(
HDC hdc,
PDC_ATTR pdcattr,
ULONG cjBits,
PVOID pBitsIn,
PVOID *ppBitsOut,
PBITMAPINFO pbmi,
PBITMAPINFO *ppbmiNew,
DWORD *pcjbmiNew,
DWORD dwNumScan,
UINT iUsage,
DWORD dwFlags,
PCACHED_COLORSPACE *ppColorSpace, // used only for device ICM case.
PCACHED_COLORTRANSFORM *ppCXform // used only for device ICM case.
)
{
//
// translate DIB or color table
//
BOOL bStatus = TRUE;
DWORD dwColorSpaceFlags = 0;
PCACHED_COLORSPACE pBitmapColorSpace = NULL;
LOGCOLORSPACEW LogColorSpace;
PROFILE ColorProfile;
DIB_TRANSLATE_INFO TranslateInfo;
PCACHED_COLORTRANSFORM pCXform;
PGDI_ICMINFO pIcmInfo;
UNREFERENCED_PARAMETER(iUsage);
ICMAPI(("gdi32: IcmTranslateDIB\n"));
//
// Parameter check
//
if (pbmi == NULL)
{
WARNING("gdi32: IcmTranslateDIB(): pbmi is NULL\n");
return FALSE;
}
//
// Load external ICM dlls.
//
LOAD_ICMDLL(FALSE);
//
// Initialize ICMINFO
//
if ((pIcmInfo = GET_ICMINFO(pdcattr)) == NULL)
{
WARNING("gdi32: IcmTranslateDIB: Can't init icm info\n");
return FALSE;
}
//
// Initialized returned info.
//
if (ppColorSpace)
*ppColorSpace = NULL;
if (ppCXform)
*ppCXform = NULL;
//
// Get LOGCOLORSPACE from bitmap if specified.
//
if (IcmGetBitmapColorSpace(pbmi,&LogColorSpace,&ColorProfile,&dwColorSpaceFlags))
{
//
// Find ColorSpace from cache.
//
pBitmapColorSpace = IcmGetColorSpaceByColorSpace(
(HGDIOBJ)hdc,
&LogColorSpace,
&ColorProfile,
dwColorSpaceFlags);
if (pBitmapColorSpace == NULL)
{
//
// Create new cache.
//
pBitmapColorSpace = IcmCreateColorSpaceByColorSpace(
(HGDIOBJ)hdc,
&LogColorSpace,
&ColorProfile,
dwColorSpaceFlags);
}
}
//
// Create Color Transform, if nessesary.
//
if (IS_ICM_DEVICE(pdcattr->lIcmMode))
{
//
// just create a new hcmXform for use with BITMAPV4 AND BITMAPV5s.
//
if (pBitmapColorSpace)
{
ICMMSG(("IcmTranslateDIB():Bitmap color space used for DEVICE ICM\n"));
if ((ppCXform != NULL) && (ppColorSpace != NULL))
{
//
// for DEVICE managed ICM, call device driver to create a temp xform
//
pCXform = IcmCreateColorTransform(hdc,pdcattr,pBitmapColorSpace,dwFlags);
if (pCXform == NULL)
{
WARNING("IcmTranslateDIB():Fail to create temporay Xfrom with V4V5 Bitmap\n");
//
// Failed to create color transfrom, release bitmap color space,
// and null-color transform.
//
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
bStatus = FALSE;
}
else
{
if (pCXform == IDENT_COLORTRANSFORM)
{
//
// Source and destination color space are same, so no color transform is
// required, and of course we don't need to keep bitmap color space.
//
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
}
else
{
//
// Return to the color transform to callee...
// (these should be deleted by callee)
//
*ppCXform = pCXform;
*ppColorSpace = pBitmapColorSpace;
}
bStatus = TRUE;
}
}
else
{
WARNING("IcmTranslateDIB():No device ICM will happen for this V4V5 Bitmap\n");
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
bStatus = TRUE;
}
return (bStatus);
}
else
{
ICMMSG(("IcmTranslateDIB():DC color space used for DEVICE ICM\n"));
//
// We don't need to create new transform, just use the transform in DC.
//
return (TRUE);
}
}
else if (IS_ICM_HOST(pdcattr->lIcmMode))
{
HANDLE hcmXform = NULL;
if (pBitmapColorSpace)
{
ICMMSG(("IcmTranslateDIB():Bitmap color space used for HOST ICM\n"));
pCXform = IcmCreateColorTransform(hdc,pdcattr,pBitmapColorSpace,dwFlags);
if ((pCXform == IDENT_COLORTRANSFORM) || (pCXform == NULL))
{
//
// unable or not nessesary to translate DIB
//
ICMWRN(("Bitmap V4 or V5: CreateColorTransform failed or ident.\n"));
goto TranslateDIB_Cleanup;
}
else
{
hcmXform = pCXform->ColorTransform;
}
}
else
{
ICMMSG(("IcmTranslateDIB():DC color space used for HOST ICM\n"));
if (dwFlags & ICM_BACKWARD)
{
ICMMSG(("IcmTranslateDIB():Backward Color transform\n"));
//
// If there is cached handle, use that.
//
if (pIcmInfo->pBackCXform)
{
ICMMSG(("IcmTranslateDIB():Use cached transform for Backward Color transform\n"));
hcmXform = pIcmInfo->pBackCXform->ColorTransform;
}
else
{
PCACHED_COLORTRANSFORM pCXform;
ICMMSG(("IcmTranslateDIB():Create cached transform for Backward Color transform\n"));
//
// Create backward color transform.
//
pCXform = IcmCreateColorTransform(hdc,
pdcattr,
NULL,
ICM_BACKWARD);
if ((pCXform == NULL) || (pCXform == IDENT_COLORTRANSFORM))
{
ICMWRN(("IcmTranslateDIB():ColorTransform is NULL or ident.\n"));
goto TranslateDIB_Cleanup;
}
//
// Cache created color transform.
//
pIcmInfo->pBackCXform = pCXform;
//
// We will delete this cached transform, when we don't need this anymore.
//
hcmXform = pCXform->ColorTransform;
}
}
else
{
//
// Use DC's colortransform
//
hcmXform = pdcattr->hcmXform;
}
}
if (hcmXform == NULL)
{
//
// if we don't have any colortransform, we will not translate anything.
// just fail and let use original image.
//
ICMWRN(("IcmTranslateDIB():No colortransform, might be ident.\n"));
goto TranslateDIB_Cleanup;
}
//
// Get bitmap translate information.
//
bStatus = IcmGetTranslateInfo(pdcattr,pbmi,pBitsIn,cjBits,dwNumScan,&TranslateInfo,dwFlags);
if (bStatus)
{
LONG nLineBytes = ((TranslateInfo.SourceWidth *
TranslateInfo.SourceBitCount) + 7) / 8;
bStatus = (*fpTranslateBitmapBits)(
hcmXform,
TranslateInfo.pvSourceBits,
TranslateInfo.SourceColorType,
TranslateInfo.SourceWidth,
TranslateInfo.SourceHeight,
ALIGN_DWORD(nLineBytes),
TranslateInfo.pvTranslateBits,
TranslateInfo.TranslateColorType,
//
0, // We need pass 0 here, to let Kodak CMM works
//
NULL,0);
if (bStatus)
{
//
// Pass new bitmap and/or header to caller.
//
if (TranslateInfo.TranslateType & TRANSLATE_BITMAP)
{
if (ppBitsOut)
{
*ppBitsOut = TranslateInfo.pvTranslateBits;
}
else
{
//
// Overwrite original (when input color and output color type is same)
//
if (TranslateInfo.SourceColorType == TranslateInfo.TranslateColorType)
{
RtlCopyMemory(TranslateInfo.pvSourceBits,
TranslateInfo.pvTranslateBits,
TranslateInfo.cjTranslateBits);
}
else
{
WARNING("IcmTranslateDIB():Input color != Output color\n");
}
LOCALFREE(TranslateInfo.pvTranslateBits);
}
}
if (TranslateInfo.TranslateType & TRANSLATE_HEADER)
{
if (ppbmiNew)
{
*ppbmiNew = TranslateInfo.TranslateBitmapInfo;
}
else
{
//
// Overwrite original (when input color and output color type is same)
//
if (TranslateInfo.SourceColorType == TranslateInfo.TranslateColorType)
{
RtlCopyMemory(TranslateInfo.pvSourceBits,
TranslateInfo.pvTranslateBits,
TranslateInfo.cjTranslateBits);
}
else
{
WARNING("IcmTranslateDIB():Input color != Output color\n");
}
LOCALFREE(TranslateInfo.TranslateBitmapInfo);
}
if (pcjbmiNew)
{
*pcjbmiNew = TranslateInfo.TranslateBitmapInfoSize;
}
}
}
else
{
WARNING("IcmTranslateDIB():Fail TranslateBitmapBits\n");
//
// Free memory which allocated inside IcmGetTranslateInfo().
//
if (TranslateInfo.TranslateType & TRANSLATE_BITMAP)
{
LOCALFREE(TranslateInfo.pvTranslateBits);
}
if (TranslateInfo.TranslateType & TRANSLATE_HEADER)
{
LOCALFREE(TranslateInfo.TranslateBitmapInfo);
}
}
}
TranslateDIB_Cleanup:
//
// Free temp transform and temp file
//
// Only delete hcmXform when it based on bitmap colorspace.
//
if (pBitmapColorSpace)
{
if (hcmXform)
{
IcmDeleteColorTransform(pCXform,FALSE);
}
IcmReleaseColorSpace(NULL,pBitmapColorSpace,FALSE);
}
}
return(bStatus);
}
/******************************Public*Routine******************************\
* IcmGetFirstNonUsedColorTransform()
*
* History:
*
* Write it:
* 12-Mar-1998 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
PCACHED_COLORTRANSFORM
IcmGetFirstNonUsedColorTransform(
VOID
)
{
PCACHED_COLORTRANSFORM pCXform = NULL;
PLIST_ENTRY p;
ICMAPI(("gdi32: IcmGetFirstNonUsedColorTransform\n"));
ENTERCRITICALSECTION(&semColorTransformCache);
p = ListCachedColorTransform.Flink;
while(p != &ListCachedColorTransform)
{
pCXform = CONTAINING_RECORD(p,CACHED_COLORTRANSFORM,ListEntry);
if (pCXform->cRef == 0)
{
ICMMSG(("IcmGetFirstNonUsedColorTransform():Find non-used color transform in cache !\n"));
//
// No one use this color transform at this moment.
//
break;
}
p = p->Flink;
pCXform = NULL;
}
LEAVECRITICALSECTION(&semColorTransformCache);
return (pCXform);
}
/******************************Public*Routine******************************\
* IcmGetColorTransform()
*
* History:
*
* Write it:
* 21-Apr-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
PCACHED_COLORTRANSFORM
IcmGetColorTransform(
HDC hdcRequest,
PCACHED_COLORSPACE pSource,
PCACHED_COLORSPACE pDestination,
PCACHED_COLORSPACE pTarget,
BOOL bNeedDeviceXform
)
{
PCACHED_COLORTRANSFORM pCXform = NULL;
PLIST_ENTRY p;
ICMAPI(("gdi32: IcmGetColorTransform\n"));
ENTERCRITICALSECTION(&semColorTransformCache);
p = ListCachedColorTransform.Flink;
while(p != &ListCachedColorTransform)
{
pCXform = CONTAINING_RECORD(p,CACHED_COLORTRANSFORM,ListEntry);
if (IcmSameColorSpace(pSource,pCXform->SourceColorSpace) &&
IcmSameColorSpace(pDestination,pCXform->DestinationColorSpace) &&
IcmSameColorSpace(pTarget,pCXform->TargetColorSpace))
{
//
// If callee needs device color tansform,
// of course, we should return device color transform.
//
if ((bNeedDeviceXform ? 1 : 0) ==
((pCXform->flInfo & DEVICE_COLORTRANSFORM) ? 1 : 0))
{
//
// if Cached color transform depends on specific DC, check it.
//
if ((pCXform->hdc == NULL) || (pCXform->hdc == hdcRequest))
{
ICMMSG(("IcmGetColorTransform():Find in cache !\n"));
//
// Match !, use this color transform, increment ref. count
//
pCXform->cRef++;
break;
}
}
}
p = p->Flink;
pCXform = NULL;
}
LEAVECRITICALSECTION(&semColorTransformCache);
return (pCXform);
}
/******************************Public*Routine******************************\
* IcmCreateColorTransform
*
* Decide whether to call the device driver or mscms.dll to delete a
* color transform.
*
* Arguments:
*
* hdc
* pdcattr
* pLogColorSpaceW
*
* Return Value:
*
* handle of new transform
*
* History:
*
* Write it:
* 24-Jan-1996 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
PCACHED_COLORTRANSFORM
IcmCreateColorTransform(
HDC hdc,
PDC_ATTR pdcattr,
PCACHED_COLORSPACE pInputColorSpace,
DWORD dwFlags
)
{
PCACHED_COLORTRANSFORM pCXform = NULL;
PCACHED_COLORSPACE pSourceColorSpace = NULL;
BOOL bDCSourceColorSpace = (pInputColorSpace == NULL ? TRUE : FALSE);
BOOL bAnyNewColorSpace = FALSE;
PGDI_ICMINFO pIcmInfo;
ICMAPI(("gdi32: IcmCreateColorTransform\n"));
ASSERTGDI(pdcattr != NULL,"IcmCreateColorTransform: pdcattr == NULL\n");
//
// If this is Lazy color correction case, the destination surface
// will have image in source color space, so the color transform
// is identical.
//
if (IS_ICM_LAZY_CORRECTION(pdcattr->lIcmMode))
{
return (IDENT_COLORTRANSFORM);
}
//
// Load external ICM dlls.
//
LOAD_ICMDLL(NULL);
//
// Initialize ICMINFO
//
if ((pIcmInfo = GET_ICMINFO(pdcattr)) == NULL)
{
WARNING("gdi32: IcmCreateColorTransform: Can't init icm info\n");
return(NULL);
}
if (bDCSourceColorSpace && (pIcmInfo->pSourceColorSpace == NULL))
{
//
// If we haven't gotton DC source color space, get it there.
//
LOGCOLORSPACEW LogColorSpaceW;
ICMMSG(("IcmCreateColorTransform(): Call getobject to get source color space in DC\n"));
//
// Filled with zero.
//
RtlZeroMemory(&LogColorSpaceW,sizeof(LOGCOLORSPACEW));
//
// Find ColorSpace from cache.
//
pSourceColorSpace = IcmGetColorSpaceByHandle(
(HGDIOBJ)hdc,
(HANDLE)pdcattr->hColorSpace,
&LogColorSpaceW,0);
//
// If we can not find from cache, but succeeded to obtain
// valid logcolorspace from handle, create new one.
//
if ((pSourceColorSpace == NULL) &&
(LogColorSpaceW.lcsSignature == LCS_SIGNATURE))
{
//
// Create new cache.
//
pSourceColorSpace = IcmCreateColorSpaceByColorSpace(
(HGDIOBJ)hdc,
&LogColorSpaceW,
NULL, 0);
//
// we are using new color space
//
bAnyNewColorSpace = TRUE;
}
//
// And this is DC's color space, keep it for cache.
//
pIcmInfo->pSourceColorSpace = pSourceColorSpace;
}
else if (bDCSourceColorSpace)
{
ICMMSG(("IcmCreateColorTransform(): Use cached source color space in DC\n"));
//
// Get this from client cache !
//
pSourceColorSpace = pIcmInfo->pSourceColorSpace;
}
else
{
ICMMSG(("IcmCreateColorTransform(): Use given source color space\n"));
//
// Just use given color space.
//
pSourceColorSpace = pInputColorSpace;
}
if (pSourceColorSpace)
{
HANDLE hColorTransform = NULL;
PCACHED_COLORSPACE pDestColorSpace = pIcmInfo->pDestColorSpace;
PCACHED_COLORSPACE pTargetColorSpace = NULL;
//
// if we are in proofing mode, consider target profile.
//
if (IS_ICM_PROOFING(pdcattr->lIcmMode))
{
pTargetColorSpace = pIcmInfo->pTargetColorSpace;
}
#if DBG_ICM
//
// Dump current color space for the DC.
//
if ((pSourceColorSpace->LogColorSpace.lcsFilename[0]) != UNICODE_NULL)
{
ICMMSG(("IcmCreateColorTransform(): Source Profile = %ws\n",
pSourceColorSpace->LogColorSpace.lcsFilename));
}
if ((pDestColorSpace) &&
((pDestColorSpace->LogColorSpace.lcsFilename[0]) != UNICODE_NULL))
{
ICMMSG(("IcmCreateColorTransform(): Destination Profile = %ws\n",
pDestColorSpace->LogColorSpace.lcsFilename));
}
if ((pTargetColorSpace) &&
((pTargetColorSpace->LogColorSpace.lcsFilename[0]) != UNICODE_NULL))
{
ICMMSG(("IcmCreateColorTransform(): Target Profile = %ws\n",
pTargetColorSpace->LogColorSpace.lcsFilename));
}
ICMMSG(("IcmCreateColorTransform(): Intent = %d\n",
pSourceColorSpace->ColorIntent));
#endif // DBG
//
// At this moment, we have any source colorspace.
//
if (IcmSameColorSpace(pSourceColorSpace,pDestColorSpace))
{
if (pTargetColorSpace)
{
if (IcmSameColorSpace(pSourceColorSpace,pTargetColorSpace))
{
ICMMSG(("IcmCreateColorTransform(): Src == Dest == Trg colorspace\n"));
//
// Source ColorSpace == Destination ColorSpace == Target ColorSpace
// No color transform needed.
//
return (IDENT_COLORTRANSFORM);
}
}
else
{
ICMMSG(("IcmCreateColorTransform(): Src == Dest colorspace\n"));
//
// Source ColorSpace == Destination ColorSpace,
// and there is no target profile.
// That means we don't need translate color
//
return (IDENT_COLORTRANSFORM);
}
}
//
// We need to have proper colortransform to adjust color between each colorspace.
//
if (dwFlags & ICM_BACKWARD)
{
//
// This is backward transform. (swap source and destination)
//
PCACHED_COLORSPACE pSwapColorSpace;
pSwapColorSpace = pSourceColorSpace;
pSourceColorSpace = pDestColorSpace;
pDestColorSpace = pSwapColorSpace;
}
//
// At this moment, at least, we should have Source and Destination color space.
// And target color space is optional.
//
if (pDestColorSpace)
{
if (!bAnyNewColorSpace)
{
//
// Find colortransform from cache
//
// if this is device ICM, hdc also should matched.
//
pCXform = IcmGetColorTransform(
hdc,
pSourceColorSpace,
pDestColorSpace,
pTargetColorSpace,
(IS_ICM_DEVICE(pdcattr->lIcmMode)));
if (pCXform)
{
return (pCXform);
}
}
//
// Allocate CACHED_COLORTRANSFORM
//
pCXform = LOCALALLOC(sizeof(CACHED_COLORTRANSFORM));
if (pCXform)
{
ENTERCRITICALSECTION(&semColorSpaceCache);
//
// Make sure all color space has been realized
//
if (IcmRealizeColorProfile(pSourceColorSpace,TRUE) &&
IcmRealizeColorProfile(pDestColorSpace,TRUE) &&
IcmRealizeColorProfile(pTargetColorSpace,TRUE))
{
//
// call ICM dll or device driver to create a color transform
//
if (IS_ICM_HOST(pdcattr->lIcmMode))
{
DWORD ahIntents[3];
HPROFILE ahProfiles[3];
DWORD chProfiles = 0;
ICMMSG(("Creating Host ICM Transform...\n"));
//
// Put source profile in first entry.
//
ahIntents[chProfiles] = INTENT_RELATIVE_COLORIMETRIC;
ahProfiles[chProfiles] = pSourceColorSpace->hProfile;
chProfiles++;
ahIntents[chProfiles] = pSourceColorSpace->ColorIntent;
//
// If target profile (proofing) is used, insert it
// between source and destination.
//
if (pTargetColorSpace)
{
ahProfiles[chProfiles] = pTargetColorSpace->hProfile;
chProfiles++;
ahIntents[chProfiles] = INTENT_ABSOLUTE_COLORIMETRIC;
}
//
// Finally, set destination profile.
//
ahProfiles[chProfiles] = pDestColorSpace->hProfile;
chProfiles++;
//
// Call MSCMS to create color transform.
//
hColorTransform = (*fpCreateMultiProfileTransform)(
ahProfiles, chProfiles,
ahIntents, chProfiles,
NORMAL_MODE | ENABLE_GAMUT_CHECKING,
INDEX_DONT_CARE);
}
else if (IS_ICM_DEVICE(pdcattr->lIcmMode))
{
CLIENT_SIDE_FILEVIEW fvwSrcProfile;
CLIENT_SIDE_FILEVIEW fvwDstProfile;
CLIENT_SIDE_FILEVIEW fvwTrgProfile;
ICMMSG(("Creating Device ICM Transform...\n"));
//
// Invalidate FILEVIEW.
//
RtlZeroMemory(&fvwSrcProfile,sizeof(CLIENT_SIDE_FILEVIEW));
RtlZeroMemory(&fvwDstProfile,sizeof(CLIENT_SIDE_FILEVIEW));
RtlZeroMemory(&fvwTrgProfile,sizeof(CLIENT_SIDE_FILEVIEW));
//
// Map color profile(s) into memory.
//
if (pSourceColorSpace->ColorProfile.dwType == PROFILE_FILENAME)
{
if (!bMapFileUNICODEClideSide(
(PWSTR)(pSourceColorSpace->ColorProfile.pProfileData),
&fvwSrcProfile,FALSE))
{
WARNING("IcmCreateColorTransform(): Fail to map source profile\n");
goto IcmCreateColorTransform_Cleanup;
}
}
else if (pSourceColorSpace->ColorProfile.dwType == PROFILE_MEMBUFFER)
{
ICMMSG(("Source Profile is memory buffer\n"));
fvwSrcProfile.pvView = pSourceColorSpace->ColorProfile.pProfileData;
fvwSrcProfile.cjView = pSourceColorSpace->ColorProfile.cbDataSize;
}
else
{
WARNING("IcmCreateColorTransform():src profile type is not supported\n");
goto IcmCreateColorTransform_Cleanup;
}
if (pDestColorSpace->ColorProfile.dwType == PROFILE_FILENAME)
{
if (!bMapFileUNICODEClideSide(
(PWSTR)(pDestColorSpace->ColorProfile.pProfileData),
&fvwDstProfile,FALSE))
{
WARNING("IcmCreateColorTransform(): Fail to map destination profile\n");
goto IcmCreateColorTransform_Cleanup;
}
}
else if (pDestColorSpace->ColorProfile.dwType == PROFILE_MEMBUFFER)
{
ICMMSG(("Destination Profile is memory buffer\n"));
fvwDstProfile.pvView = pDestColorSpace->ColorProfile.pProfileData;
fvwDstProfile.cjView = pDestColorSpace->ColorProfile.cbDataSize;
}
else
{
WARNING("IcmCreateColorTransform():dst profile type is not supported\n");
goto IcmCreateColorTransform_Cleanup;
}
//
// Target color space is optional
//
if (pTargetColorSpace)
{
if (pTargetColorSpace->ColorProfile.dwType == PROFILE_FILENAME)
{
if (!bMapFileUNICODEClideSide(
(PWSTR)(pTargetColorSpace->ColorProfile.pProfileData),
&fvwTrgProfile,FALSE))
{
WARNING("IcmCreateColorTransform(): Fail to map target profile\n");
goto IcmCreateColorTransform_Cleanup;
}
}
else if (pTargetColorSpace->ColorProfile.dwType == PROFILE_MEMBUFFER)
{
ICMMSG(("Target Profile is memory buffer\n"));
fvwTrgProfile.pvView = pTargetColorSpace->ColorProfile.pProfileData;
fvwTrgProfile.cjView = pTargetColorSpace->ColorProfile.cbDataSize;
}
else
{
WARNING("IcmCreateColorTransform():trg profile type is not supported\n");
goto IcmCreateColorTransform_Cleanup;
}
}
//
// Call kernel.
//
hColorTransform = NtGdiCreateColorTransform(hdc,
&(pSourceColorSpace->LogColorSpace),
fvwSrcProfile.pvView, // Source Profile memory mapped file.
fvwSrcProfile.cjView,
fvwDstProfile.pvView, // Destination Profile memory mapped file.
fvwDstProfile.cjView,
fvwTrgProfile.pvView, // Target Profile memory mapped file.
fvwTrgProfile.cjView);
IcmCreateColorTransform_Cleanup:
//
// if we mapped file, unmap here.
//
if (fvwSrcProfile.hSection)
{
vUnmapFileClideSide(&fvwSrcProfile);
}
if (fvwDstProfile.hSection)
{
vUnmapFileClideSide(&fvwDstProfile);
}
if (fvwTrgProfile.hSection)
{
vUnmapFileClideSide(&fvwTrgProfile);
}
}
}
//
// Once after create tranform, we don't need realized color space,
// so just unrealize it.
//
IcmUnrealizeColorProfile(pSourceColorSpace);
IcmUnrealizeColorProfile(pDestColorSpace);
IcmUnrealizeColorProfile(pTargetColorSpace);
LEAVECRITICALSECTION(&semColorSpaceCache);
if (hColorTransform)
{
BOOL bCacheable = TRUE;
//
// Initialize CACHED_COLORTRANSFORM with zero
//
RtlZeroMemory(pCXform,sizeof(CACHED_COLORTRANSFORM));
//
// Fill up CACHED_COLORTRANSFORM
//
pCXform->ColorTransform = hColorTransform;
pCXform->SourceColorSpace = pSourceColorSpace;
pCXform->DestinationColorSpace = pDestColorSpace;
pCXform->TargetColorSpace = pTargetColorSpace;
if (IS_ICM_DEVICE(pdcattr->lIcmMode))
{
//
// if this is device colortransform, mark it and
// put DC in CACHED_COLORTRANSFORM strcuture
//
pCXform->flInfo |= DEVICE_COLORTRANSFORM;
//
// And device color transform is not cacheable.
//
bCacheable = FALSE;
}
ENTERCRITICALSECTION(&semColorSpaceCache);
//
// Increment transform ref. count in each color space.
//
if (pSourceColorSpace)
{
pSourceColorSpace->cRef++;
if (bCacheable)
{
//
// Check this color space is cacheable.
//
bCacheable &= IcmIsCacheable(pSourceColorSpace);
}
}
if (pDestColorSpace)
{
pDestColorSpace->cRef++;
if (bCacheable)
{
//
// Check this color space is cacheable.
//
bCacheable &= IcmIsCacheable(pDestColorSpace);
}
}
if (pTargetColorSpace)
{
pTargetColorSpace->cRef++;
if (bCacheable)
{
//
// Check this color space is cacheable.
//
bCacheable &= IcmIsCacheable(pTargetColorSpace);
}
}
LEAVECRITICALSECTION(&semColorSpaceCache);
//
// Initialize ref. counter.
//
pCXform->cRef = 1;
//
// Set cache-able bit, if possible.
//
if (bCacheable)
{
ICMMSG(("IcmCreateColorTransform(): ColorTransform is cacheable\n"));
pCXform->flInfo |= CACHEABLE_COLORTRANSFORM;
}
else
{
ICMMSG(("IcmCreateColorTransform(): ColorTransform is *NOT* cacheable\n"));
//
// If this is not cacheable, make sure this get deleted when DC gone.
//
pCXform->hdc = hdc;
}
//
// Insert new CACHED_COLORTRANSFORM to list
//
ENTERCRITICALSECTION(&semColorTransformCache);
InsertTailList(&ListCachedColorTransform,&(pCXform->ListEntry));
cCachedColorTransform++;
LEAVECRITICALSECTION(&semColorTransformCache);
}
else
{
ICMWRN(("IcmCreateColorTransform(): Fail to create color transform\n"));
//
// Fail to get transform handle
//
LOCALFREE(pCXform);
pCXform = NULL;
}
}
else
{
WARNING("IcmCreateColorTransform(): LOCALALLOC() failed\n");
}
}
else
{
WARNING("IcmCreateColorTransform(): Dest color space is required\n");
}
}
else
{
WARNING("IcmCreateColorTransform(): Fail to get source colorspace\n");
}
return(pCXform);
}
/******************************Public*Routine******************************\
* IcmTranslateCOLORREF
*
* Arguments:
*
* hdc
* pdcattr
* ColorIn
* *ColorOut
*
* Return Value:
*
* Status
*
* History:
*
* Write it:
* 13-Feb-1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
BOOL
IcmTranslateCOLORREF(
HDC hdc,
PDC_ATTR pdcattr,
COLORREF ColorIn,
COLORREF *ColorOut,
DWORD Flags
)
{
COLORREF OldColor = ColorIn;
COLORREF NewColor;
BOOL bStatus = TRUE;
ICMAPI(("gdi32: IcmTranslateCOLORREF\n"));
ASSERTGDI(ColorOut != NULL,"IcmTranslateCOLORREF(): ColorOut == NULL\n");
if (bNeedTranslateColor(pdcattr))
{
PGDI_ICMINFO pIcmInfo;
LOAD_ICMDLL(FALSE);
if ((pIcmInfo = GET_ICMINFO(pdcattr)) == NULL)
{
WARNING("gdi32: IcmTranslateCOLORREF: Can't init icm info\n");
return((int)FALSE);
}
else
{
ULONG SrcColorFormat;
ULONG DstColorFormat;
HANDLE hcmXform = NULL;
if (Flags & ICM_BACKWARD)
{
ICMMSG(("IcmTranslateCOLORREF():Backward Color transform\n"));
//
// AnyColorFormat ----> COLORREF (0x00bbggrr)
//
// Setup src & dest color type.
//
SrcColorFormat = pIcmInfo->pDestColorSpace->ColorFormat;
DstColorFormat = BM_xBGRQUADS;
//
// If there is cached handle, use that.
//
if (pIcmInfo->pBackCXform)
{
ICMMSG(("IcmTranslateCOLORREF():Use cached transform for Backward Color transform\n"));
hcmXform = pIcmInfo->pBackCXform->ColorTransform;
}
else
{
PCACHED_COLORTRANSFORM pCXform;
ICMMSG(("IcmTranslateCOLORREF():Create cached transform for Backward Color transform\n"));
//
// Create backward color transform.
//
pCXform = IcmCreateColorTransform(hdc,
pdcattr,
NULL,
ICM_BACKWARD);
if ((pCXform == NULL) || (pCXform == IDENT_COLORTRANSFORM))
{
return (FALSE);
}
//
// Cache created color transform.
//
pIcmInfo->pBackCXform = pCXform;
//
// We will delete this cached transform, when we don't need this anymore.
//
hcmXform = pCXform->ColorTransform;
}
}
else
{
//
// COLORREF (0x00bbggrr) ----> AnyColorFormat
//
// Setup src & dest color type.
//
SrcColorFormat = BM_xBGRQUADS;
DstColorFormat = pIcmInfo->pDestColorSpace->ColorFormat;
//
// Use foaward color transform.
//
hcmXform = GetColorTransformInDC(pdcattr);
//
// Source is COLORREF. then, Mask off gdi internal infomation.
//
// COLORREF = 0x00bbggrr;
//
OldColor &= 0x00ffffff;
}
if (hcmXform)
{
//
// We handle COLORREF as 1x1 pixel bitmap data.
//
bStatus = (*fpTranslateBitmapBits)(hcmXform,
(PVOID)&OldColor,
SrcColorFormat,
1,1,
ALIGN_DWORD(sizeof(COLORREF)),
(PVOID)&NewColor,
DstColorFormat,
//
0, // We need pass 0 here, to let Kodak CMM works
//
NULL,0);
}
else
{
//
// It seems hcmXform is invalid
//
ICMWRN(("IcmTranslateCOLORREF():hcmXform is invalid\n"));
bStatus = FALSE;
}
if (bStatus)
{
if (Flags & ICM_BACKWARD)
{
//
// OldColor: AnyColorFormat
// NewColor: COLORREF (0x00bbggrr)
//
// [NOTE:]
// We could not restore flags.
//
*ColorOut = NewColor;
}
else
{
//
// OldColor: COLORREF (0x00bbggrr)
// NewColor: AnyColorFormat
//
if (!(IS_32BITS_COLOR(pdcattr->lIcmMode)))
{
//
// The distination is not 32Bits Color, Restore assign and preserve flags.
//
*ColorOut = (NewColor & 0x00ffffff) | (ColorIn & 0xff000000);
}
else
{
//
// The distination is 32bits color.
//
// [NOTE:]
// We will lost flags here.
//
*ColorOut = NewColor;
ICMMSG(("IcmTranslateCOLORREF(): 32 bits color !\n"));
}
}
}
else
{
WARNING("IcmTranslateCOLORREF():Fail TranslateBitmapBits()\n");
}
}
}
else
{
//
// Just return original color
//
*ColorOut = ColorIn;
bStatus = TRUE;
}
return(bStatus);
}
/******************************Public*Routine******************************\
* IcmTranslateTRIVERTEX
*
* Translate TRIVERTEX in place. No need for a general routine with
* separate input and output pointers
*
* Arguments:
*
* hdc - hdc
* pdcattr - verified dcattr
* pVertex - input and output pointer
*
* Return Value:
*
* Status
*
* History:
*
* Write it:
* 13-Feb-1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
BOOL
IcmTranslateTRIVERTEX(
HDC hdc,
PDC_ATTR pdcattr,
PTRIVERTEX pVertex,
ULONG nVertex
)
{
BOOL bStatus = TRUE;
ICMAPI(("gdi32: IcmTranslateTRIVERTEX\n"));
ASSERTGDI(pVertex != NULL,"IcmTranslateTrivertex(): pVertex == NULL\n");
if (bNeedTranslateColor(pdcattr))
{
PGDI_ICMINFO pIcmInfo;
LOAD_ICMDLL(FALSE);
if ((pIcmInfo = GET_ICMINFO(pdcattr)) == NULL)
{
WARNING("gdi32: IcmTranslateTRIVERTEX: Can't init icm info\n");
return((int)FALSE);
}
else
{
//
// Use foaward color transform.
//
if (GetColorTransformInDC(pdcattr))
{
//
// use 16 bit per channel COLOR_RGB to translate trivertex
//
while (nVertex--)
{
COLOR Color;
Color.rgb.red = pVertex->Red;
Color.rgb.green = pVertex->Green;
Color.rgb.blue = pVertex->Blue;
bStatus = (*fpTranslateColors)(
(HANDLE)GetColorTransformInDC(pdcattr),
&Color,
1,
COLOR_RGB,
&Color,
COLOR_RGB);
if (bStatus)
{
//
// assign output
//
pVertex->Red = Color.rgb.red;
pVertex->Green = Color.rgb.green;
pVertex->Blue = Color.rgb.blue;
}
else
{
WARNING("IcmTranslateTRIVERTEX():Fail TranslateColors()\n");
break;
}
pVertex++;
}
}
else
{
//
// It seems hcmXform is invalid
//
ICMWRN(("IcmTranslateTRIVERTEX():hcmXform is invalid\n"));
bStatus = FALSE;
}
}
}
else
{
bStatus = TRUE;
}
return(bStatus);
}
/******************************Public*Routine******************************\
* IcmTranslatePaletteEntry
*
* Arguments:
*
* hdc
* pdcattr
* ColorIn
* pColorOut
*
* Return Value:
*
* Status
*
* History:
*
* Rewrite it:
* 21-Jan-1997 -by- Hideyuki Nagase [hideyukn]
* Write it:
* 5-Aug-1996 -by- Mark Enstrom [marke]
*
\**************************************************************************/
BOOL
IcmTranslatePaletteEntry(
HDC hdc,
PDC_ATTR pdcattr,
PALETTEENTRY *pColorIn,
PALETTEENTRY *pColorOut,
UINT NumberOfEntries
)
{
BOOL bStatus = FALSE;
ICMAPI(("gdi32: IcmTranslatePaletteEntry\n"));
if (bNeedTranslateColor(pdcattr))
{
PGDI_ICMINFO pIcmInfo = GET_ICMINFO(pdcattr);
if (pIcmInfo)
{
LOAD_ICMDLL(FALSE);
//
// We handle PALETTEENTRYs as NumberOfEntries x 1 pixels bitmap data.
//
bStatus = (*fpTranslateBitmapBits)((HANDLE)GetColorTransformInDC(pdcattr),
(PVOID)pColorIn,
//
BM_xBGRQUADS, // PALETTEENTRY is 0x00bbggrr format
//
NumberOfEntries,1,
ALIGN_DWORD(NumberOfEntries*sizeof(COLORREF)),
(PVOID)pColorOut,
//
pIcmInfo->pDestColorSpace->ColorFormat, // BM_xBGRQUADS or BM_KYMCQUADS
//
//
0, // We need pass 0 here, to let Kodak CMM works
//
NULL,0);
if (!bStatus)
{
WARNING("IcmTranslatePaletteEntry():Fail TranslateBitmapBits()\n");
}
}
}
else
{
//
// Just return original color.
//
RtlCopyMemory(pColorIn,pColorOut,sizeof(PALETTEENTRY) * NumberOfEntries);
bStatus = TRUE;
}
return(bStatus);
}
/******************************Public*Routine******************************\
* IcmDeleteColorTransform
*
* Decide whether to call the device driver or mscms.dll to delete a
* color transform.
*
* Arguments:
*
* Return Value:
*
* History:
*
* Mar.12.1998 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
BOOL
IcmDeleteColorTransform(
PCACHED_COLORTRANSFORM pCXform,
BOOL bForceDelete
)
{
BOOL bStatus = TRUE;
ICMAPI(("gdi32: IcmDeleteColorTransform\n"));
if (pCXform)
{
ENTERCRITICALSECTION(&semColorTransformCache);
//
// Decrement ref. counter.
//
pCXform->cRef--;
if ((pCXform->cRef == 0) || bForceDelete)
{
PCACHED_COLORTRANSFORM pCXformVictim = NULL;
if ((pCXform->flInfo & CACHEABLE_COLORTRANSFORM) && !bForceDelete)
{
if (cCachedColorTransform < MAX_COLORTRANSFORM_CACHE)
{
ICMMSG(("IcmDeleteColorTransform(): colortransform can be cached !\n"));
//
// The color transform can be cached. so just keep it in list.
// And don't need to delete anything here.
//
pCXformVictim = NULL;
}
else
{
//
// Find any cache can delete from list.
//
if ((pCXformVictim = IcmGetFirstNonUsedColorTransform()) == NULL)
{
ICMMSG(("IcmDeleteColorTransform(): colortransform cache is full, delete myself\n"));
//
// Nothing can be deleted from list, so delete myself.
//
pCXformVictim = pCXform;
}
else
{
ICMMSG(("IcmDeleteColorTransform(): colortransform cache is full, delete victim\n"));
}
}
}
else
{
//
// The colortransform can not be kept, or force delete, so just delete this.
//
pCXformVictim = pCXform;
}
if (pCXformVictim)
{
//
// Unref color space count.
//
if (pCXformVictim->SourceColorSpace)
{
IcmReleaseColorSpace(NULL,pCXformVictim->SourceColorSpace,FALSE);
}
if (pCXformVictim->DestinationColorSpace)
{
IcmReleaseColorSpace(NULL,pCXformVictim->DestinationColorSpace,FALSE);
}
if (pCXformVictim->TargetColorSpace)
{
IcmReleaseColorSpace(NULL,pCXformVictim->TargetColorSpace,FALSE);
}
//
// Delete color transform
//
if (pCXformVictim->flInfo & DEVICE_COLORTRANSFORM)
{
//
// call device driver to delete transform.
//
bStatus = NtGdiDeleteColorTransform(pCXformVictim->hdc,pCXformVictim->ColorTransform);
}
else
{
//
// call color match dll to delete transform.
//
bStatus = (*fpDeleteColorTransform)(pCXformVictim->ColorTransform);
}
//
// Remove from list
//
RemoveEntryList(&(pCXformVictim->ListEntry));
cCachedColorTransform--;
//
// free CACHED_COLORTRANSFORM
//
LOCALFREE(pCXformVictim);
}
}
LEAVECRITICALSECTION(&semColorTransformCache);
}
return(bStatus);
}
/******************************Public*Routine******************************\
* IcmDeleteDCColorTransforms
*
* Arguments:
*
* Return Value:
*
* History:
*
* Feb.17.1997 Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL IcmDeleteDCColorTransforms(
PGDI_ICMINFO pIcmInfo
)
{
ICMAPI(("gdi32: IcmDeleteDCColorTransforms\n"));
ASSERTGDI(pIcmInfo != NULL,"IcmDeleteDCColorTransform():pIcmInfo == NULL\n");
//
// Delete transform selected in DC.
//
if (pIcmInfo->pCXform)
{
IcmDeleteColorTransform(pIcmInfo->pCXform,FALSE);
}
if (pIcmInfo->pBackCXform)
{
IcmDeleteColorTransform(pIcmInfo->pBackCXform,FALSE);
}
if (pIcmInfo->pProofCXform)
{
IcmDeleteColorTransform(pIcmInfo->pProofCXform,FALSE);
}
//
// Invalidate colortransforms
//
pIcmInfo->pCXform = pIcmInfo->pBackCXform = pIcmInfo->pProofCXform = NULL;
return (TRUE);
}
/******************************Public*Routine******************************\
* IcmDeleteCachedColorTransforms
*
* Arguments:
*
* Return Value:
*
* History:
*
* May.06.1997 Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmDeleteCachedColorTransforms(
HDC hdc
)
{
PCACHED_COLORTRANSFORM pCXform = NULL;
PLIST_ENTRY p;
ICMAPI(("gdi32: IcmDeleteCachedColorTransforms\n"));
ENTERCRITICALSECTION(&semColorTransformCache);
p = ListCachedColorTransform.Flink;
while(p != &ListCachedColorTransform)
{
//
// Get cached color transform
//
pCXform = CONTAINING_RECORD(p,CACHED_COLORTRANSFORM,ListEntry);
//
// Let 'p' points next cell. (this prefer to be done BEFORE un-chain this cell)
//
p = p->Flink;
//
// Is this color transform is specific to this DC ?
//
if (pCXform->hdc == hdc)
{
ICMMSG(("IcmDeleteCachedColorTransform():Delete colortransform in cache !\n"));
//
// Delete color transform (this call will un-chain this cell)
//
IcmDeleteColorTransform(pCXform,TRUE);
}
}
LEAVECRITICALSECTION(&semColorTransformCache);
return (TRUE);
}
/******************************Public*Routine******************************\
* IcmIsCacheable
*
* Arguments:
*
* Return Value:
*
* History:
*
* Mar.12.1998 Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmIsCacheable(
PCACHED_COLORSPACE pColorSpace
)
{
//
// If this color space can not be cached, don't cache it.
//
if (pColorSpace->flInfo & NOT_CACHEABLE_COLORSPACE)
{
return (FALSE);
}
//
// If this is any GDI object specific color space, also can not cache.
//
if (pColorSpace->hObj)
{
return (FALSE);
}
return (TRUE);
}
/******************************Public*Routine******************************\
* IcmReleaseCachedColorSpace
*
* Arguments:
*
* Return Value:
*
* History:
*
* May.06.1997 Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmReleaseCachedColorSpace(
HGDIOBJ hObj
)
{
PCACHED_COLORSPACE pColorSpace = NULL;
PLIST_ENTRY p;
ICMAPI(("gdi32: IcmReleaseCachedColorSpace\n"));
ENTERCRITICALSECTION(&semColorSpaceCache);
p = ListCachedColorSpace.Flink;
while(p != &ListCachedColorSpace)
{
//
// Get cached color space
//
pColorSpace = CONTAINING_RECORD(p,CACHED_COLORSPACE,ListEntry);
//
// Let 'p' points next cell. (this prefer to be done BEFORE un-chain this cell)
//
p = p->Flink;
//
// Is this color transform is related to this DC ?
//
if (pColorSpace->hObj == hObj)
{
ICMMSG(("IcmReleaseCachedColorSpace():Delete colorspace in cache !\n"));
//
// Delete color space (this call will un-chain this cell)
//
IcmReleaseColorSpace(hObj,pColorSpace,TRUE);
}
}
LEAVECRITICALSECTION(&semColorSpaceCache);
return (TRUE);
}
/******************************Public*Routine******************************\
* IcmReleaseColorSpace
*
* Arguments:
*
* Return Value:
*
* History:
*
* Feb.17.1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
VOID IcmReleaseColorSpace(
HGDIOBJ hObj, /* Must be given if bForceDelete is TRUE */
PCACHED_COLORSPACE pColorSpace,
BOOL bForceDelete
)
{
ICMAPI(("gdi32: IcmReleaseColorSpace\n"));
if (pColorSpace)
{
ENTERCRITICALSECTION(&semColorSpaceCache);
//
// Decrement ref. counter.
//
pColorSpace->cRef--;
//
// If this profile associated with other GDI objects (driver, metafile or bitmap)
// we won't delete until the object is deleted
//
if (
(pColorSpace->flInfo & HGDIOBJ_SPECIFIC_COLORSPACE)
&&
(bForceDelete == FALSE)
)
{
ICMWRN(("IcmReleaseColorSpace: Delay Delete for Metafile/Driver/Bitmap profile - %ws\n",\
(pColorSpace->LogColorSpace.lcsFilename[0] ? \
pColorSpace->LogColorSpace.lcsFilename : L"no profile")));
}
else
{
if ((pColorSpace->cRef == 0) // No one uses this profile.
|| // OR
(bForceDelete && IsColorSpaceOwnedByGDIObject(pColorSpace,hObj))
// DC or Owner GDI object is going to delete and
// colorspace is designed for this GDI object.
)
{
ICMMSG(("IcmReleaseColorSpace: Delete - %ws\n", \
(pColorSpace->LogColorSpace.lcsFilename[0] ? \
pColorSpace->LogColorSpace.lcsFilename : L"no profile")));
if (pColorSpace->hProfile)
{
IcmUnrealizeColorProfile(pColorSpace);
}
if (pColorSpace->flInfo & NEED_TO_FREE_PROFILE)
{
ICMMSG(("IcmReleaseColorSpace: Free on memory profile\n"));
GlobalFree(pColorSpace->ColorProfile.pProfileData);
}
if (pColorSpace->flInfo & NEED_TO_DEL_PROFILE)
{
ICMMSG(("IcmReleaseColorSpace: Delete TempFile - %ws\n",
pColorSpace->LogColorSpace.lcsFilename));
DeleteFileW(pColorSpace->LogColorSpace.lcsFilename);
}
//
// Remove from list
//
RemoveEntryList(&(pColorSpace->ListEntry));
cCachedColorSpace--;
//
// Free colorspace.
//
LOCALFREE(pColorSpace);
}
else
{
ICMWRN(("IcmReleaseColorSpace: Still in USE - %ws\n", \
(pColorSpace->LogColorSpace.lcsFilename[0] ? \
pColorSpace->LogColorSpace.lcsFilename : L"no profile")));
}
}
LEAVECRITICALSECTION(&semColorSpaceCache);
}
}
/******************************Public*Routine******************************\
* IcmReleaseDCColorSpace
*
* Arguments:
*
* Return Value:
*
* History:
*
* Feb.17.1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
VOID IcmReleaseDCColorSpace(
PGDI_ICMINFO pIcmInfo,
BOOL bReleaseDC
)
{
INT i = 0;
HDC hdc = pIcmInfo->hdc;
PCACHED_COLORSPACE DeleteColorSpaces[4];
ICMAPI(("gdi32: IcmReleaseDCColorSpace\n"));
ASSERTGDI(pIcmInfo != NULL,"IcmReleaseDCColorSpace pIcmInfo == NULL\n");
//
// Fill up the table to delete color color spaces.
//
DeleteColorSpaces[i++] = pIcmInfo->pSourceColorSpace;
if (bReleaseDC)
{
ICMMSG(("IcmReleaseDCColorSpace: Force Delete\n"));
//
// If we are in "force deletion" mode, don't delete twice.
// since if the color space owned by this HDC, and this DC is going to be
// deleted, we will delete the color space forcely.
//
if (IsColorSpaceOwnedByGDIObject(pIcmInfo->pDestColorSpace,hdc) &&
IcmSameColorSpace(pIcmInfo->pSourceColorSpace,pIcmInfo->pDestColorSpace))
{
ICMMSG(("IcmReleaseDCColorSpace: Force Delete - skip destination (same as source)\n"));
}
else
{
DeleteColorSpaces[i++] = pIcmInfo->pDestColorSpace;
}
if (IsColorSpaceOwnedByGDIObject(pIcmInfo->pTargetColorSpace,hdc) &&
(IcmSameColorSpace(pIcmInfo->pSourceColorSpace,pIcmInfo->pTargetColorSpace) ||
IcmSameColorSpace(pIcmInfo->pDestColorSpace,pIcmInfo->pTargetColorSpace)))
{
ICMMSG(("IcmReleaseDCColorSpace: Force Delete - skip target (same as source/dest)\n"));
}
else
{
DeleteColorSpaces[i++] = pIcmInfo->pTargetColorSpace;
}
}
else
{
DeleteColorSpaces[i++] = pIcmInfo->pDestColorSpace;
DeleteColorSpaces[i++] = pIcmInfo->pTargetColorSpace;
}
DeleteColorSpaces[i] = NULL;
for (i = 0; DeleteColorSpaces[i] != NULL; i++)
{
IcmReleaseColorSpace((HGDIOBJ)hdc,DeleteColorSpaces[i],bReleaseDC);
}
pIcmInfo->pSourceColorSpace = NULL;
pIcmInfo->pDestColorSpace = NULL;
pIcmInfo->pTargetColorSpace = NULL;
}
/******************************Public*Routine******************************\
* IcmInitIcmInfo()
*
* Arguments:
*
* Return Value:
*
* History:
*
* Jan.31,1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
PGDI_ICMINFO
IcmInitIcmInfo(
HDC hdc,
PDC_ATTR pdcattr
)
{
ICMAPI(("gdi32: IcmInitIcmInfo\n"));
if (pdcattr == NULL)
{
WARNING("IcmInitIcmInfo():pdcattr is NULL\n");
return (NULL);
}
if (pdcattr->pvICM == NULL)
{
PGDI_ICMINFO pIcmInfo = NULL;
PLDC pldc = (PLDC) pdcattr->pvLDC;
BOOL bDisplay = ((pldc && pldc->hSpooler) ? FALSE : TRUE);
BOOL bInsertList = bDisplay;
ENTERCRITICALSECTION(&semListIcmInfo);
//
// First try to get ICMINFO from list. if not nothing can be re-used,
// allocate new one.
//
if (bDisplay)
{
if ((pIcmInfo = IcmGetUnusedIcmInfo(hdc)) != NULL)
{
LIST_ENTRY ListEntry;
//
// Save ListEntry.
//
ListEntry = pIcmInfo->ListEntry;
//
// Init with zero.
//
RtlZeroMemory(pIcmInfo,sizeof(GDI_ICMINFO));
//
// Restore ListEntry
//
pIcmInfo->ListEntry = ListEntry;
//
// This ICMInfo already on list, don't need to insert.
//
bInsertList = FALSE;
//
// Mark this cell in on ListIcmInfo.
//
pIcmInfo->flInfo = ICM_ON_ICMINFO_LIST;
ICMMSG(("IcmInitIcmInfo():Get unused ICMINFO structure = %p\n",pIcmInfo));
}
}
if (pIcmInfo == NULL)
{
//
// ICMINFO is not allocated, yet. then allocate it.
//
pIcmInfo = (PGDI_ICMINFO) LOCALALLOC(sizeof(GDI_ICMINFO));
//
// Init with zero.
//
if (pIcmInfo != NULL) {
RtlZeroMemory(pIcmInfo,sizeof(GDI_ICMINFO));
}
ICMMSG(("IcmInitIcmInfo():Allocate new ICMINFO structure = %p\n",pIcmInfo));
}
if (pIcmInfo)
{
PDEVMODEW pDevModeW = NULL;
//
// Set owner information (hdc and pdcattr).
//
pIcmInfo->hdc = hdc;
pIcmInfo->pvdcattr = (PVOID) pdcattr;
//
// initialize LIST_ENTRY for saved icm info.
//
InitializeListHead(&(pIcmInfo->SavedIcmInfo));
//
// Default is LCS_DEFAULT_INTENT (aka LCS_GM_IMAGES)
//
pIcmInfo->dwDefaultIntent = LCS_DEFAULT_INTENT;
//
// If this is printer, set default Intent from devmode.
//
if (pldc && pldc->hSpooler)
{
PVOID pvFree = NULL;
if (pldc->pDevMode)
{
pDevModeW = pldc->pDevMode;
}
else
{
pDevModeW = pdmwGetDefaultDevMode(pldc->hSpooler,NULL,&pvFree);
}
if (pDevModeW && (pDevModeW->dmFields & DM_ICMINTENT))
{
DWORD dwIntent = pDevModeW->dmICMIntent;
ICMMSG(("IcmInitIcmInfo():Intent in devmode = %d\n",dwIntent));
//
// Convert intent for devmode to intent for LOGCOLORSPACE.
//
switch (dwIntent)
{
case DMICM_SATURATE:
pIcmInfo->dwDefaultIntent = LCS_GM_BUSINESS;
break;
case DMICM_COLORIMETRIC:
pIcmInfo->dwDefaultIntent = LCS_GM_GRAPHICS;
break;
case DMICM_ABS_COLORIMETRIC:
pIcmInfo->dwDefaultIntent = LCS_GM_ABS_COLORIMETRIC;
break;
case DMICM_CONTRAST:
default:
pIcmInfo->dwDefaultIntent = LCS_DEFAULT_INTENT;
break;
}
}
ICMMSG(("IcmInitIcmInfo():Default Intent = %d\n",pIcmInfo->dwDefaultIntent));
//
// Free devmode buffer.
//
if (pvFree)
{
LOCALFREE(pvFree);
}
}
//
// Only ICMINFO for Display ICM put on to the list.
//
if (bInsertList)
{
//
// This ICMINFO is newly allocated, so put this on list.
//
InsertTailList(&ListIcmInfo,&(pIcmInfo->ListEntry));
//
// Mark this cell in on ListIcmInfo.
//
pIcmInfo->flInfo |= ICM_ON_ICMINFO_LIST;
}
}
//
// Store pointer to ICMINFO to DC_ATTR.
//
pdcattr->pvICM = (PVOID) pIcmInfo;
LEAVECRITICALSECTION(&semListIcmInfo);
}
return ((PGDI_ICMINFO)(pdcattr->pvICM));
}
/******************************Public*Routine******************************\
* IcmGetUnusedIcmInfo()
*
* ATTENTION: semListIcmInfo should be held by caller
*
* History:
* 17-Feb-1999 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
PGDI_ICMINFO
IcmGetUnusedIcmInfo(
HDC hdcNew
)
{
PLIST_ENTRY p;
PGDI_ICMINFO pInvalidIcmInfo = NULL;
ICMAPI(("gdi32: IcmGetUnusedIcmInfo\n"));
p = ListIcmInfo.Flink;
//
// First Loop - Find ICMINFO which has same hdc.
//
while(p != &ListIcmInfo)
{
pInvalidIcmInfo = CONTAINING_RECORD(p,GDI_ICMINFO,ListEntry);
if (pInvalidIcmInfo->flInfo & ICM_IN_USE)
{
//
// Skip this one, since it's under initializing.
//
}
else
{
//
// If this is same hdc, break.
//
if (pInvalidIcmInfo->hdc == hdcNew)
{
ICMMSG(("IcmGetUnusedIcmInfo(): ICMINFO at %p is invalid (same hdc)\n",
pInvalidIcmInfo));
//
// break loop.
//
break;
}
}
//
// Move on next.
//
p = p->Flink;
pInvalidIcmInfo = NULL;
}
//
// If not find in first loop, go to second loop.
//
if (pInvalidIcmInfo == NULL)
{
p = ListIcmInfo.Flink;
//
// Second Loop - Find unused ICMINFO.
//
while(p != &ListIcmInfo)
{
pInvalidIcmInfo = CONTAINING_RECORD(p,GDI_ICMINFO,ListEntry);
if (pInvalidIcmInfo->flInfo & ICM_IN_USE)
{
//
// Skip this one, since it's under initializing.
//
}
else
{
PDC_ATTR pdcattr;
//
// Make sure this ICMINFO and hdc is stil effective.
//
//
// Check below by calling PSHARED_GET_VALIDATE.
//
// 1) Is this DC handle ?
// 2) Is this DC handle belonging to this process ?
// 3) Does this DC has valid user mode DC_ATTR ?
//
PSHARED_GET_VALIDATE(pdcattr,pInvalidIcmInfo->hdc,DC_TYPE);
if (pdcattr == NULL)
{
ICMMSG(("IcmGetUnusedIcmInfo(): ICMINFO at %p is invalid (no pdcattr)\n",
pInvalidIcmInfo));
//
// break loop.
//
break;
}
else
{
//
// Make sure the pointer points each other.
//
if ((pdcattr->pvICM != pInvalidIcmInfo ) ||
(pdcattr != pInvalidIcmInfo->pvdcattr))
{
ICMMSG(("IcmGetUnusedIcmInfo(): ICMINFO at %p is invalid (pointer mismatch)\n",
pInvalidIcmInfo));
//
// break loop.
//
break;
}
}
}
//
// Move on next.
//
p = p->Flink;
pInvalidIcmInfo = NULL;
}
}
if (pInvalidIcmInfo)
{
//
// This ICMINFO is invalid, clean up this ICMINFO.
//
IcmCleanupIcmInfo(NULL,pInvalidIcmInfo);
}
else
{
ICMMSG(("IcmGetUnusedIcmInfo(): Unused ICMINFO is not in list\n"));
}
return (pInvalidIcmInfo);
}
/******************************Public*Routine******************************\
* IcmInitDC()
*
* Arguments:
*
* Return Value:
*
* History:
*
* Jan.31.1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
BOOL
IcmInitLocalDC(
HDC hdc,
HANDLE hPrinter,
CONST DEVMODEW *pdm,
BOOL bReset
)
{
BOOL bRet = TRUE;
PDC_ATTR pdcattr;
PLDC pldc;
ICMAPI(("gdi32: IcmInitLocalDC\n"));
//
// all these stuff is for only Printer.
//
if (hPrinter == NULL)
{
return (TRUE);
}
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (!pdcattr)
{
WARNING("IcmInitDC(): pdcattr is NULL\n");
return (FALSE);
}
if (bReset)
{
//
// Release existing ICMINFO
//
if (ghICM || BEXIST_ICMINFO(pdcattr))
{
//
// Delete ICM stuff in this DC.
//
IcmDeleteLocalDC(hdc,pdcattr,NULL);
}
}
if (!pdm)
{
//
// DEVMODE are not presented.
//
ICMMSG(("IcmInitLocalDC():DEVMODE is not presented\n"));
return (TRUE);
}
//
// Check pointer to DEVMODE is valid or not. Check validation until
// DEVMODE.dmSize first, then check whole devmode size specified in dmSize.
//
if (IsBadReadPtr((CONST VOID *)pdm, offsetof(DEVMODEW,dmDriverExtra)) ||
IsBadReadPtr((CONST VOID *)pdm, pdm->dmSize))
{
WARNING("IcmInitLocalDC(): Invalid pointer given as PDEVMODEW\n");
return (FALSE);
}
//
// Check color or mono mode.
//
if ((pdm->dmFields & DM_COLOR) && (pdm->dmColor == DMCOLOR_MONOCHROME))
{
//
// This is monochrome mode, don't enable ICM as default.
// And NEVER enable ICM.
//
ICMMSG(("IcmInitLocalDC():DEVMODE says MONOCHROME mode\n"));
return (TRUE);
}
//
// ATTENTION: AFTER HERE, WE HAVE A DEVMODE WHICH POSSIBLE TO ENABLE ICM LATER OR NOW.
//
//
// Check DM fields
//
if (!(pdm->dmFields & DM_ICMMETHOD))
{
//
// DEVMODE does not have ICMMETHOD.
//
ICMMSG(("IcmInitLocalDC():DEVMODE does not have ICMMETHOD\n"));
return (TRUE);
}
//
// NOTE:
//
// DEVMODEW structure.
//
// ... [omitted]
// DWORD dmDisplayFrequency;
// #if(WINVER >= 0x0400)
// DWORD dmICMMethod; // Windows 95 only / Windows NT 5.0
// DWORD dmICMIntent; // Windows 95 only / Windows NT 5.0
// DWORD dmMediaType; // Windows 95 only / Windows NT 5.0
// ....
//
// Then DEVMODE structure should be larger than offset of dmMediaType
// to access ICM stuff.
//
if (pdm->dmSize < offsetof(DEVMODEW,dmMediaType))
{
//
// DEVMODE version might not matched.
//
WARNING("IcmInitLocalDC():DEVMODE is small\n");
return (TRUE);
}
//
// Check requested ICM mode.
//
switch (pdm->dmICMMethod)
{
case DMICMMETHOD_NONE:
ICMMSG(("IcmInitDC(): ICM is disabled by default\n"));
//
// ICM is not enabled at this time.
//
// no more process is needed, just return here...
//
return (TRUE);
case DMICMMETHOD_SYSTEM:
ICMMSG(("IcmInitDC(): HOST ICM is requested\n"));
//
// ICM on Host, is requested.
//
SET_HOST_ICM_DEVMODE(pdcattr->lIcmMode);
break;
case DMICMMETHOD_DRIVER:
case DMICMMETHOD_DEVICE:
ICMMSG(("IcmInitDC(): DEVICE ICM is requested\n"));
//
// ICM on device, is requested.
//
SET_DEVICE_ICM_DEVMODE(pdcattr->lIcmMode);
break;
default:
//
// And we treat as Device ICM greater DMICMMETHOD_USER also.
//
if (pdm->dmICMMethod >= DMICMMETHOD_USER)
{
ICMMSG(("IcmInitDC(): DEVICE ICM (USER) is requested\n"));
//
// ICM on device (user defined), is requested.
//
SET_DEVICE_ICM_DEVMODE(pdcattr->lIcmMode);
}
else
{
ICMMSG(("IcmInitDC(): Unknown ICM mode\n"));
//
// return with error.
//
return (FALSE);
}
break;
}
//
// Finally, enabled ICM.
//
bRet = SetICMMode(hdc,ICM_ON);
if (!bRet)
{
ICMWRN(("InitLocalDC():FAILED to turn on ICM\n"));
}
return (bRet);
}
/******************************Public*Routine******************************\
* IcmUpdateDCColorInfo()
*
* Arguments:
*
* Return Value:
*
* History:
*
* May.28.1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
BOOL
IcmUpdateDCColorInfo(
HDC hdc,
PDC_ATTR pdcattr
)
{
BOOL bRet = TRUE;
PGDI_ICMINFO pIcmInfo;
ICMAPI(("gdi32: IcmUpdateDCColorInfo\n"));
pIcmInfo = GET_ICMINFO(pdcattr);
ASSERTGDI(pIcmInfo != NULL,"IcmUpdateDCColorInfo(): pIcmInfo == NULL\n");
//
// Get the ColorSpace for this DC.
//
if (!IcmUpdateLocalDCColorSpace(hdc,pdcattr))
{
return (FALSE);
}
if ((pIcmInfo->pCXform == NULL) || (pdcattr->ulDirty_ & DIRTY_COLORTRANSFORM))
{
//
// if TRUE in above, new color space (or no) has been selected,
// then updates color transforms.
//
PCACHED_COLORTRANSFORM pCXform;
//
// At this momernt, we should have destination color space.
// if this is null, we may fail to update color space in
// IcmUpdateLocalDCColorSpace()
//
if (pIcmInfo->pDestColorSpace)
{
//
// Create the color transform.
//
pCXform = IcmCreateColorTransform(hdc,pdcattr,NULL,ICM_FORWARD);
if (pCXform)
{
if (pCXform == IDENT_COLORTRANSFORM)
{
ICMMSG(("IcmUpdateDCInfo():Input & Output colorspace is same\n"));
//
// Input and Output colorspace is same, could be optimize.
//
//
// Set new color transform to DC.
//
IcmSelectColorTransform(hdc,pdcattr,NULL,
bDeviceCalibrate(pIcmInfo->pDestColorSpace));
//
// Delete cached dirty color transform, if we have.
//
IcmDeleteDCColorTransforms(pIcmInfo);
//
// Set new color transform to ICMINFO.
//
pIcmInfo->pCXform = NULL;
}
else
{
//
// Select the color transform to DC.
//
IcmSelectColorTransform(hdc,pdcattr,pCXform,
bDeviceCalibrate(pCXform->DestinationColorSpace));
//
// Delete cached dirty color transform, if we have.
//
IcmDeleteDCColorTransforms(pIcmInfo);
//
// Set new color transform to ICMINFO.
//
pIcmInfo->pCXform = pCXform;
//
// Translate all DC objects to ICM colors. Must
// force brush/pens to be re-realized when used next
//
IcmTranslateColorObjects(hdc,pdcattr,TRUE);
}
}
else
{
WARNING("IcmUpdateDCInfo():CreateColorTransform failed\n");
//
// Fail to create new transform, keep as is.
//
bRet = FALSE;
}
}
else
{
WARNING("IcmUpdateDCInfo():No destination color space\n");
bRet = FALSE;
}
}
else
{
ICMMSG(("IcmUpdateDCColorInfo(): Color space does not change or not found\n"));
}
return (bRet);
}
/******************************Public*Routine******************************\
* IcmUpdateLocalDCColorSpace
*
* Arguments:
*
* Return Value:
*
* History:
*
* 26.Feb.1997 -by- Hideyuki Nagase [hideyukn]
*
\**************************************************************************/
BOOL
IcmUpdateLocalDCColorSpace(
HDC hdc,
PDC_ATTR pdcattr
)
{
BOOL bRet = FALSE;
BOOL bDirtyXform = FALSE;
PLDC pldc;
PGDI_ICMINFO pIcmInfo;
WCHAR ProfileName[MAX_PATH];
DWORD dwColorSpaceFlag;
PCACHED_COLORSPACE pNewColorSpace = NULL;
ICMAPI(("gdi32: IcmUpdateLocalDCColorSpace\n"));
ASSERTGDI(pdcattr != NULL,"IcmUpdateLocalDCColorSpace(): pdcattr == NULL\n");
pldc = pdcattr->pvLDC;
pIcmInfo = GET_ICMINFO(pdcattr);
ASSERTGDI(pIcmInfo != NULL,"IcmUpdateLocalDCColorSpace(): pIcmInfo == NULL\n");
//
// if the DC already has a destination colorspace, then return TRUE
//
if ((pIcmInfo->pDestColorSpace == NULL) || (pdcattr->ulDirty_ & DIRTY_COLORSPACE))
{
HCOLORSPACE hDIBColorSpace;
//
// Invalidate profilename.
//
ProfileName[0] = UNICODE_NULL;
dwColorSpaceFlag = 0;
hDIBColorSpace = NULL;
//
// if the target DC has DIBSection. it will be DIBsection's color space
// OR sRGB color space.
//
if (bDIBSectionSelected(pdcattr))
{
ENTERCRITICALSECTION(&semColorSpaceCache);
if (pdcattr->dwDIBColorSpace)
{
ICMMSG(("IcmUpdateLocalDCColorSpace(): DIB section in DC (V4/V5)\n"));
//
// The DIB currently selected, has thier own color space.
// This case happens when CreateDIBSection called with
// BITMAPV4/V5 header.
//
pNewColorSpace = (PCACHED_COLORSPACE) pdcattr->dwDIBColorSpace;
//
// Inc. ref. count.
//
pNewColorSpace->cRef++;
}
else
{
ICMMSG(("IcmUpdateLocalDCColorSpace(): DIB section in DC (no color space)\n"));
// [This is Win98 compatible behave]
//
// If the DIBitmap does not have any specific color space,
// keep same color space as current DC.
//
}
LEAVECRITICALSECTION(&semColorSpaceCache);
}
else if ((pdcattr->ulDirty_ & DC_PRIMARY_DISPLAY) &&
(PrimaryDisplayProfile[0] != UNICODE_NULL))
{
//
// Use cached color profile.
//
lstrcpyW(ProfileName,PrimaryDisplayProfile);
}
else if (pIcmInfo->flInfo & ICM_VALID_DEFAULT_PROFILE)
{
//
// Use cached color profile.
//
lstrcpyW(ProfileName,pIcmInfo->DefaultDstProfile);
}
else
{
int iRet;
//
// Still couldn't find yet ??. Ask MSCMS to find out profile. (go slow way)
//
iRet = IcmEnumColorProfile(hdc,IcmFindProfileCallBack,
(LPARAM)ProfileName,FALSE,NULL,&dwColorSpaceFlag);
//
// if you could not find any profile for this DC, just use sRGB.
//
if ((iRet == -1) || (ProfileName[0] == UNICODE_NULL))
{
ULONG ulSize = MAX_PATH;
if (!(*fpGetStandardColorSpaceProfileW)(NULL,LCS_sRGB,ProfileName,&ulSize))
{
ICMMSG(("IcmUpdateLocalDCColorSpace():Fail to SCS(sRGB), use hardcode\n"));
//
// If error, use hardcoded profile name.
//
wcscpy(ProfileName,sRGB_PROFILENAME);
}
}
//
// Create cache for next usage
//
if ((pdcattr->ulDirty_ & DC_PRIMARY_DISPLAY) &&
(PrimaryDisplayProfile[0] == UNICODE_NULL))
{
lstrcpyW(PrimaryDisplayProfile,ProfileName);
}
else // otherwise put it into default profile.
{
lstrcpyW(pIcmInfo->DefaultDstProfile,ProfileName);
pIcmInfo->flInfo |= (ICM_VALID_DEFAULT_PROFILE|
ICM_VALID_CURRENT_PROFILE);
}
}
//
// If default device profile could be found, associate it into this DC.
//
if ((ProfileName[0] != UNICODE_NULL) || (pNewColorSpace != NULL))
{
#if DBG
if (ProfileName[0] != UNICODE_NULL)
{
ICMMSG(("IcmUpdateLocalDCColorSpace():Default Device Profile = %ws\n",ProfileName));
}
#endif
//
// try to find desired color space from cache.
//
if (pNewColorSpace == NULL)
{
pNewColorSpace = IcmGetColorSpaceByName(
(HGDIOBJ)hdc,
ProfileName,
pIcmInfo->dwDefaultIntent,
dwColorSpaceFlag);
if (pNewColorSpace == NULL)
{
//
// create new one.
//
pNewColorSpace = IcmCreateColorSpaceByName(
(HGDIOBJ)hdc,
ProfileName,
pIcmInfo->dwDefaultIntent,
dwColorSpaceFlag);
}
}
if (pNewColorSpace)
{
//
// Is this same destination color space as currently selected in DC ?
//
if (IcmSameColorSpace(pNewColorSpace,pIcmInfo->pDestColorSpace))
{
ICMMSG(("IcmUpdateLocalDCColorSpace():Same color space is selected already\n"));
//
// Color space does NOT changed.
//
IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE);
bRet = TRUE;
}
else
{
//
// Notify new color format to kernel.
//
if (NtGdiSetIcmMode(hdc,ICM_CHECK_COLOR_MODE,pNewColorSpace->ColorFormat))
{
//
// if we have some color space currently selected, delete it.
//
if (pIcmInfo->pDestColorSpace)
{
IcmReleaseColorSpace(NULL,pIcmInfo->pDestColorSpace,FALSE);
}
//
// DC can accept this color space, Set new colorspace to destination.
//
pIcmInfo->pDestColorSpace = pNewColorSpace;
//
// Color space is changed. so color transform should be updated.
//
bDirtyXform = TRUE;
bRet = TRUE;
}
else
{
WARNING("ICM:Detected colorspace was not accepted by target DC\n");
//
// This color space does not match to this DC.
//
IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE);
}
}
}
else
{
WARNING("Failed IcmUpdateLocalDCColorSpace(), Failed to create new color space.\n");
}
}
else
{
WARNING("Failed IcmUpdateLocalDCColorSpace(), no device profile is detected.\n");
}
}
else
{
ICMMSG(("IcmUpdateLocalDCColoSpace(): Destination Color Space cache is valid\n"));
bRet = TRUE;
}
//
// [Only for Printer]
//
// If we haven't asked default source color profile for this Printer DC,
// Now is the time to ask it. Only do this when apps does NOT specified
// thier own color space.
//
if (bRet && pldc && pldc->hSpooler)
{
if ((pdcattr->hColorSpace == GetStockObject(PRIV_STOCK_COLORSPACE)) &&
(pIcmInfo->hDefaultSrcColorSpace == NULL))
{
PDEVMODEW pDevModeW = NULL;
PVOID pvFree = NULL;
BOOL bRetSource = FALSE;
//
// Default is no DC specific source color space (= INVALID_COLORSPACE),
// this also make sure we will not come here again.
//
pIcmInfo->hDefaultSrcColorSpace = INVALID_COLORSPACE;
//
// Invalidate profilename.
//
ProfileName[0] = UNICODE_NULL;
dwColorSpaceFlag = 0;
if (pldc->pDevMode)
{
ICMMSG(("IcmUpdateLocalDCColorSpace():Cached DEVMODE used\n"));
pDevModeW = pldc->pDevMode;
}
else
{
ICMMSG(("IcmUpdateLocalDCColorSpace():Get default DEVMODE\n"));
pDevModeW = pdmwGetDefaultDevMode(pldc->hSpooler,NULL,&pvFree);
}
if (pDevModeW)
{
//
// Get source color proflie from driver.
//
if (IcmAskDriverForColorProfile(pldc,QCP_SOURCEPROFILE,
pDevModeW,ProfileName,&dwColorSpaceFlag) <= 0)
{
//
// No source profile specified.
//
ProfileName[0] = UNICODE_NULL;
}
}
//
// Free devmode buffer.
//
if (pvFree)
{
LOCALFREE(pvFree);
}
//
// 1) If default source profile could be found, or
// 2) the default intent in devmode is different from LCS_DEFAULT_INTENT,
//
// we need to create new source color space, then associate it into this DC.
//
if ((ProfileName[0] != UNICODE_NULL) ||
(pIcmInfo->dwDefaultIntent != LCS_DEFAULT_INTENT))
{
HCOLORSPACE hColorSpace = NULL;
ICMMSG(("IcmUpdateLocalDCColorSpace():Default devmode Intent = %d\n",
pIcmInfo->dwDefaultIntent));
//
// If no color profile specified, use sRGB.
//
if (ProfileName[0] == UNICODE_NULL)
{
ULONG ulSize = MAX_PATH;
if (!(*fpGetStandardColorSpaceProfileW)(NULL,LCS_sRGB,ProfileName,&ulSize))
{
ICMMSG(("IcmUpdateLocalDCColorSpace():Fail to SCS(sRGB), use hardcode\n"));
//
// If error, use hardcoded profile name.
//
wcscpy(ProfileName,sRGB_PROFILENAME);
}
}
ICMMSG(("IcmUpdateLocalDCColorSpace():Default Source Profile = %ws\n",ProfileName));
//
// Find from cache first.
//
pNewColorSpace = IcmGetColorSpaceByName(
(HGDIOBJ)hdc,
ProfileName,
pIcmInfo->dwDefaultIntent,
dwColorSpaceFlag);
if (pNewColorSpace == NULL)
{
//
// create new one.
//
pNewColorSpace = IcmCreateColorSpaceByName(
(HGDIOBJ)hdc,
ProfileName,
pIcmInfo->dwDefaultIntent,
dwColorSpaceFlag);
}
if (pNewColorSpace)
{
//
// Create kernel-mode handle.
//
hColorSpace = CreateColorSpaceW(&(pNewColorSpace->LogColorSpace));
if (hColorSpace)
{
//
// Select this into DC.
//
if (IcmSetSourceColorSpace(hdc,hColorSpace,pNewColorSpace,0))
{
//
// IcmSetSourceColorSpace increments ref. count of colorspace.
// but we have done it by Icm[Get|Create]ColorSpaceByName, so
// decrement ref count of color space here.
//
IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE);
//
// Keep these into ICMINFO.
//
pIcmInfo->hDefaultSrcColorSpace = hColorSpace;
//
// This color space should be deleted later.
//
pIcmInfo->flInfo |= ICM_DELETE_SOURCE_COLORSPACE;
//
// Source color space has been changed.
// (color transform is updated inside IcmSetSourceColorSpace().
// so not nessesary to set bDirtyXfrom to TRUE)
//
bRetSource = TRUE;
}
else
{
WARNING("Failed IcmUpdateLocalDCColorSpace(), Failed to select new source color space.\n");
}
}
else
{
WARNING("Failed IcmUpdateLocalDCColorSpace(), Failed to create new source color space.\n");
}
}
else
{
WARNING("Failed IcmUpdateLocalDCColorSpace(), Failed to create new source color space cache.\n");
}
if (!bRetSource)
{
if (hColorSpace)
{
DeleteColorSpace(hColorSpace);
}
if (pNewColorSpace)
{
IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE);
}
}
}
else
{
ICMMSG(("IcmUpdateLocalDCColoSpace(): No default source color Space cache specified\n"));
}
}
}
//
// Now color space is valid.
//
if (bRet)
{
pdcattr->ulDirty_ &= ~DIRTY_COLORSPACE;
}
if (bDirtyXform)
{
pdcattr->ulDirty_ |= DIRTY_COLORTRANSFORM;
}
return (bRet);
}
/******************************Public*Routine******************************\
* IcmCleanupIcmInfo()
*
* ATTENTION: semListIcmInfo must be hold by caller
*
* History:
* 16-Feb-1999 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmCleanupIcmInfo(
PDC_ATTR pdcattr, // This can be NULL for clean up case.
PGDI_ICMINFO pIcmInfo // This can *NOT* be NULL at any rate.
)
{
if (ghICM)
{
//
// Delete Saved ICMINFO data (if present)
//
IcmRestoreDC(pdcattr,1,pIcmInfo);
}
//
// If there is any default source profile (kernel-side), do something here.
//
if ((pIcmInfo->hDefaultSrcColorSpace != NULL) &&
(pIcmInfo->hDefaultSrcColorSpace != INVALID_COLORSPACE))
{
ICMMSG(("IcmCleanupIcmInfo():Delete/Unselect default source color space\n"));
if (pdcattr)
{
//
// If it is currently selected into this DC, un-select it.
//
if (pIcmInfo->hDefaultSrcColorSpace == pdcattr->hColorSpace)
{
NtGdiSetColorSpace(pIcmInfo->hdc,GetStockObject(PRIV_STOCK_COLORSPACE));
}
}
//
// And it should be delete it.
//
if (pIcmInfo->flInfo & ICM_DELETE_SOURCE_COLORSPACE)
{
DeleteColorSpace(pIcmInfo->hDefaultSrcColorSpace);
}
pIcmInfo->hDefaultSrcColorSpace = NULL;
}
if (ghICM)
{
//
// Delete Color transforms
//
IcmDeleteDCColorTransforms(pIcmInfo);
//
// Delete Cached color transform related to this DC.
// (like device color transform)
//
IcmDeleteCachedColorTransforms(pIcmInfo->hdc);
//
// Free ICM colorspace datas.
//
IcmReleaseDCColorSpace(pIcmInfo,TRUE);
//
// Delete Cached color space which related to this DC.
// (like color space in metafile)
//
IcmReleaseCachedColorSpace((HGDIOBJ)(pIcmInfo->hdc));
}
pIcmInfo->hdc = NULL;
pIcmInfo->pvdcattr = NULL;
pIcmInfo->flInfo = 0;
return(TRUE);
}
/******************************Public*Routine******************************\
* IcmDeleteLocalDC()
*
* Arguments:
*
* Return Value:
*
* History:
*
* Jan.31.1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmDeleteLocalDC(
HDC hdc,
PDC_ATTR pdcattr,
PGDI_ICMINFO pIcmInfo
)
{
ICMAPI(("gdi32: IcmDeleteLocalDC\n"));
ASSERTGDI(pdcattr != NULL,"IcmDeleteLocalDC():pdcattr == NULL\n");
//
// If callee does not provide ICMINFO, get it from pdcattr.
//
if (pIcmInfo == NULL)
{
pIcmInfo = GET_ICMINFO(pdcattr);
}
//
// Invalidate current color tansform.
//
// (but the cache in ICMINFO is still valid, and will be delete
// inside IcmDeleteDCColorTransforms() called from IcmCleanupIcmInfo().)
//
IcmSelectColorTransform(hdc,pdcattr,NULL,TRUE);
if (IS_ICM_INSIDEDC(pdcattr->lIcmMode))
{
//
// Tell the kernel to disable ICM before delete client side data.
//
NtGdiSetIcmMode(hdc,ICM_SET_MODE,REQ_ICM_OFF);
}
//
// Clean up ICMINFO.
//
if (pIcmInfo != NULL)
{
ENTERCRITICALSECTION(&semListIcmInfo);
if (pIcmInfo->flInfo & ICM_ON_ICMINFO_LIST)
{
//
// Remove this ICMINFO from list. (since this will be deleted).
//
RemoveEntryList(&(pIcmInfo->ListEntry));
}
//
// Clean up ICMINFO.
//
IcmCleanupIcmInfo(pdcattr,pIcmInfo);
//
// Invalidate ICM info in DC_ATTR.
//
pdcattr->pvICM = NULL;
LEAVECRITICALSECTION(&semListIcmInfo);
//
// Free ICM structure.
//
LOCALFREE(pIcmInfo);
}
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL IcmSelectColorTransform (HDC, PDC_ATTR, PCACHED_COLORTRANSFORM)
*
* History:
* 23-Sep-1997 -by- Hideyuki Nagase [hideyukn]
* Wrote it.
\**************************************************************************/
BOOL
IcmSelectColorTransform(
HDC hdc,
PDC_ATTR pdcattr,
PCACHED_COLORTRANSFORM pCXform,
BOOL bDeviceCalibrate)
{
if (pCXform)
{
BMFORMAT ColorFormat = pCXform->DestinationColorSpace->ColorFormat;
// LATER :
//
// if (GET_COLORTYPE(pdcattr->lIcmMode) != IcmConvertColorFormat(ColorFormat))
//
if (TRUE)
{
if (!NtGdiSetIcmMode(hdc,ICM_SET_COLOR_MODE,ColorFormat))
{
//
// The transform color format is not accepted by DC.
//
return (FALSE);
}
}
//
// Select into the color transform to DC_ATTR.
//
pdcattr->hcmXform = pCXform->ColorTransform;
}
else
{
//
// If curent color type is not RGB, call kernel to reset.
//
if (GET_COLORTYPE(pdcattr->lIcmMode) != DC_ICM_RGB_COLOR)
{
//
// Reset current color mode to RGB (default).
//
NtGdiSetIcmMode(hdc,ICM_SET_COLOR_MODE,BM_xBGRQUADS);
}
//
// Select null-color transfrom into the DC_ATTR.
//
pdcattr->hcmXform = NULL;
}
//
// If device calibration mode need to updated, call kernel to update it.
//
if ((bDeviceCalibrate ? 1 : 0) !=
(IS_ICM_DEVICE_CALIBRATE(pdcattr->lIcmMode) ? 1 : 0))
{
NtGdiSetIcmMode(hdc,ICM_SET_CALIBRATE_MODE,bDeviceCalibrate);
}
//
// Remove dirty transform flag.
//
pdcattr->ulDirty_ &= ~DIRTY_COLORTRANSFORM;
return(TRUE);
}
/******************************Public*Routine******************************\
* HBRUSH IcmSelectBrush (HDC hdc, HBRUSH hbrush)
*
* History:
* 04-June-1995 -by- Lingyun Wang [lingyunW]
* Wrote it.
\**************************************************************************/
HBRUSH
IcmSelectBrush (
HDC hdc,
PDC_ATTR pdcattr,
HBRUSH hbrushNew)
{
HBRUSH hbrushOld = pdcattr->hbrush;
ICMAPI(("gdi32: IcmSelectBrush\n"));
//
// Mark brush as dirty, select new brush in dcattr.
// Color translation may fail, but still select brush
//
pdcattr->ulDirty_ |= DC_BRUSH_DIRTY;
pdcattr->hbrush = hbrushNew;
if (bNeedTranslateColor(pdcattr))
{
IcmTranslateBrushColor(hdc,pdcattr,hbrushNew);
}
return (hbrushOld);
}
/******************************Public*Routine******************************\
* HBRUSH IcmTranslateBrushColor(HDC hdc, PDC_ATTR pdcattr, HBRUSH hbrush)
*
* History:
* 10-Apr-1997 -by- Hideyuki Nagase [hideyukn]
* Wrote it.
\**************************************************************************/
BOOL
IcmTranslateBrushColor(
HDC hdc,
PDC_ATTR pdcattr,
HBRUSH hbrush)
{
BOOL bStatus = FALSE;
COLORREF OldColor;
COLORREF NewColor;
PBRUSHATTR pbra;
//
// Invalidate BRUSH_TRANSLATED
//
pdcattr->ulDirty_ &= ~ICM_BRUSH_TRANSLATED;
PSHARED_GET_VALIDATE(pbra,hbrush,BRUSH_TYPE);
if (pbra)
{
//
// translate to new icm mode if not paletteindex
//
OldColor = pbra->lbColor;
if (!(OldColor & 0x01000000))
{
bStatus = IcmTranslateCOLORREF(hdc,
pdcattr,
OldColor,
&NewColor,
ICM_FORWARD);
if (bStatus)
{
pdcattr->IcmBrushColor = NewColor;
}
else
{
pdcattr->IcmBrushColor = OldColor;
}
}
else
{
pdcattr->IcmBrushColor = OldColor;
}
//
// Somehow, IcmBrushColor is initialized.
//
pdcattr->ulDirty_ |= ICM_BRUSH_TRANSLATED;
}
else
{
LOGBRUSH lbrush;
//
// stock brush or bitmap/hatch/dib brush
//
if(GetObjectW(hbrush,sizeof(LOGBRUSH),&lbrush))
{
if ((lbrush.lbStyle == BS_SOLID) || (lbrush.lbStyle == BS_HATCHED))
{
//
// try to translate color
//
OldColor = lbrush.lbColor;
if (!(OldColor & 0x01000000))
{
bStatus = IcmTranslateCOLORREF(hdc,
pdcattr,
OldColor,
&NewColor,
ICM_FORWARD);
if (bStatus)
{
pdcattr->IcmBrushColor = NewColor;
}
else
{
pdcattr->IcmBrushColor = OldColor;
}
}
else
{
pdcattr->IcmBrushColor = OldColor;
}
//
// IcmBrushColor is initialized.
//
pdcattr->ulDirty_ |= ICM_BRUSH_TRANSLATED;
}
else if (lbrush.lbStyle == BS_DIBPATTERN)
{
PBITMAPINFO pbmiDIB;
//
// Allocate temorary bitmap info header to get brush bitmap
//
pbmiDIB = (PBITMAPINFO)LOCALALLOC(sizeof(BITMAPINFO)+((256-1)*sizeof(RGBQUAD)));
if (pbmiDIB)
{
ULONG iColorUsage;
BOOL bAlreadyTran;
BOOL bStatus;
PVOID pvBits = NULL;
ULONG cjBits = 0;
//
// Get brush bitmap information, colortype, size, etc.
//
bStatus = NtGdiIcmBrushInfo(hdc,
hbrush,
pbmiDIB,
pvBits,
&cjBits,
&iColorUsage,
&bAlreadyTran,
IcmQueryBrush);
if (bStatus)
{
if ((iColorUsage == DIB_RGB_COLORS) &&
(!bAlreadyTran) && (cjBits))
{
pvBits = (PVOID) LOCALALLOC(cjBits);
if (pvBits)
{
//
// Get brush bitmap bits.
//
bStatus = NtGdiIcmBrushInfo(hdc,
hbrush,
pbmiDIB,
pvBits,
&cjBits,
NULL,
NULL,
IcmQueryBrush);
if (bStatus)
{
//
// IcmTranslateDIB may create new copy of bitmap bits and/or
// bitmap info header, if nessesary.
//
PVOID pvBitsNew = NULL;
PBITMAPINFO pbmiDIBNew = NULL;
bStatus = IcmTranslateDIB(hdc,
pdcattr,
cjBits,
pvBits,
&pvBitsNew,
pbmiDIB,
&pbmiDIBNew,
NULL,
(DWORD)-1,
iColorUsage,
ICM_FORWARD,
NULL,NULL);
if (bStatus)
{
if (pvBitsNew != NULL)
{
//
// IcmTranslateDIB creates new bitmap buffer, then
// free original buffer and set new one.
//
LOCALFREE(pvBits);
pvBits = pvBitsNew;
}
if (pbmiDIBNew != NULL)
{
//
// If bitmapInfo header is updated, use new one.
// And, need to compute bitmap bits size based
// on new bitmap header.
//
LOCALFREE(pbmiDIB);
pbmiDIB = pbmiDIBNew;
//
// Calculate bitmap bits size based on BITMAPINFO and nNumScans
//
cjBits = cjBitmapBitsSize(pbmiDIB);
}
//
// Set ICM-translated DIB into brush
//
bStatus = NtGdiIcmBrushInfo(hdc,
hbrush,
pbmiDIB,
pvBits,
&cjBits,
NULL,
NULL,
IcmSetBrush);
if (bStatus)
{
//
// The color is translated.
//
bAlreadyTran = TRUE;
}
else
{
WARNING("IcmSelectBrush():NtGdiIcmBrushInfo(SET) Failed\n");
}
}
else
{
WARNING("IcmSelectBrush():IcmTranslateDIB() Failed\n");
}
}
else
{
WARNING("IcmSelectBrush():NtGdiIcmBrushInfo(GET) Failed\n");
}
LOCALFREE(pvBits);
}
else
{
WARNING("IcmSelectBrush(): LOCALALLOC(pvBits) failed\n");
}
}
if (bAlreadyTran)
{
//
// Eventually, IcmBrushColor is initialized.
//
pdcattr->ulDirty_ |= ICM_BRUSH_TRANSLATED;
}
}
else
{
ICMWRN(("IcmSelectBrush(): Fail to get brush bitmap size or bitmap is DIB_PAL_COLORS\n"));
}
LOCALFREE(pbmiDIB);
}
else
{
WARNING("IcmSelectBrush(): LOCALALLOC(pbmi) failed\n");
}
}
else
{
ICMMSG(("IcmSelectBrush(): ICM will not done for this style - %d\n",lbrush.lbStyle));
}
}
else
{
WARNING("IcmSelectBrush(): GetObject failed on hbrush\n");
pdcattr->IcmBrushColor = CLR_INVALID;
}
}
return (bStatus);
}
/******************************Public*Routine******************************\
* IcmSelectPen()
*
* History:
*
* Wrote it:
* 31-Jul-1996 -by- Mark Enstrom [marke]
\**************************************************************************/
HPEN
IcmSelectPen(
HDC hdc,
PDC_ATTR pdcattr,
HPEN hpenNew
)
{
HPEN hpenOld = pdcattr->hpen;
ICMAPI(("gdi32: IcmSelectPen\n"));
pdcattr->ulDirty_ |= DC_PEN_DIRTY;
pdcattr->hpen = hpenNew;
if (bNeedTranslateColor(pdcattr))
{
IcmTranslatePenColor(hdc,pdcattr,hpenNew);
}
return (hpenOld);
}
/******************************Public*Routine******************************\
* BOOL IcmTranslatePenColor(HDC hdc, PDC_ATTR pdcattr, HBRUSH hbrush)
*
* History:
* 10-Apr-1997 -by- Hideyuki Nagase [hideyukn]
* Wrote it.
\**************************************************************************/
BOOL
IcmTranslatePenColor(
HDC hdc,
PDC_ATTR pdcattr,
HPEN hpen
)
{
BOOL bStatus = FALSE;
COLORREF OldColor;
COLORREF NewColor;
PBRUSHATTR pbra;
//
// Invalidate PEN_TRANSLATED
//
pdcattr->ulDirty_ &= ~ICM_PEN_TRANSLATED;
PSHARED_GET_VALIDATE(pbra,hpen,BRUSH_TYPE);
if (pbra)
{
OldColor = pbra->lbColor;
//
// translate to new icm mode if not paletteindex
//
if (!(OldColor & 0x01000000))
{
bStatus = IcmTranslateCOLORREF(hdc,
pdcattr,
OldColor,
&NewColor,
ICM_FORWARD);
if (bStatus)
{
pdcattr->IcmPenColor = NewColor;
}
else
{
pdcattr->IcmPenColor = OldColor;
}
}
else
{
pdcattr->IcmPenColor = OldColor;
}
//
// IcmPenColor is initialized.
//
pdcattr->ulDirty_ |= ICM_PEN_TRANSLATED;
}
else
{
LOGPEN logpen;
//
// stock brush or bitmap/hatch/dib brush
//
if(GetObjectW(hpen,sizeof(LOGPEN),&logpen))
{
if (logpen.lopnStyle != PS_NULL)
{
//
// try to translate color
//
OldColor = logpen.lopnColor;
if (!(OldColor & 0x01000000))
{
bStatus = IcmTranslateCOLORREF(hdc,
pdcattr,
OldColor,
&NewColor,
ICM_FORWARD);
if (bStatus)
{
pdcattr->IcmPenColor = NewColor;
}
else
{
pdcattr->IcmPenColor = OldColor;
}
}
else
{
pdcattr->IcmPenColor = OldColor;
}
//
// IcmPenColor is initialized.
//
pdcattr->ulDirty_ |= ICM_PEN_TRANSLATED;
}
else
{
ICMMSG(("IcmSelectPen():Pen style is PS_NULL\n"));
pdcattr->IcmPenColor = CLR_INVALID;
}
}
else
{
WARNING("GetObject failed on hbrush\n");
pdcattr->IcmPenColor = CLR_INVALID;
}
}
return(bStatus);
}
/******************************Public*Routine******************************\
* IcmSelectExtPen()
*
* History:
*
* Wrote it:
* 11-Mar-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
HPEN
IcmSelectExtPen(
HDC hdc,
PDC_ATTR pdcattr,
HPEN hpenNew
)
{
HPEN hpenOld;
ICMAPI(("gdi32: IcmSelectExtPen\n"));
//
// Invalidate PEN_TRANSLATED
//
pdcattr->ulDirty_ &= ~ICM_PEN_TRANSLATED;
//
// Call kernel to select this object.
//
hpenOld = NtGdiSelectPen(hdc,hpenNew);
if (hpenOld && bNeedTranslateColor(pdcattr))
{
IcmTranslateExtPenColor(hdc,pdcattr,hpenNew);
}
return (hpenOld);
}
/******************************Public*Routine******************************\
* BOOL IcmTranslateExtPenColor(HDC hdc, PDC_ATTR pdcattr, HBRUSH hbrush)
*
* History:
* 10-Apr-1997 -by- Hideyuki Nagase [hideyukn]
* Wrote it.
\**************************************************************************/
BOOL
IcmTranslateExtPenColor(
HDC hdc,
PDC_ATTR pdcattr,
HPEN hpen
)
{
BOOL bStatus = FALSE;
COLORREF OldColor;
COLORREF NewColor;
EXTLOGPEN logpenLocal;
EXTLOGPEN *plogpen = &logpenLocal;
if (!GetObjectW(hpen,sizeof(EXTLOGPEN),plogpen))
{
ULONG cbNeeded;
//
// It might be PS_USERSTYLE (go slow way...)
//
cbNeeded = GetObjectW(hpen,0,NULL);
if (cbNeeded)
{
plogpen = LOCALALLOC(cbNeeded);
if (plogpen)
{
if (!GetObjectW(hpen,cbNeeded,plogpen))
{
LOCALFREE(plogpen);
plogpen = NULL;
}
}
}
else
{
plogpen = NULL;
}
}
if (plogpen)
{
if ((plogpen->elpBrushStyle == BS_SOLID) || (plogpen->elpBrushStyle == BS_HATCHED))
{
ICMMSG(("IcmSelectExtPen:BS_SOLID or BS_HATCHED\n"));
//
// try to translate color
//
OldColor = plogpen->elpColor;
if (!(OldColor & 0x01000000))
{
bStatus = IcmTranslateCOLORREF(hdc,
pdcattr,
OldColor,
&NewColor,
ICM_FORWARD);
if (bStatus)
{
pdcattr->IcmPenColor = NewColor;
}
else
{
pdcattr->IcmPenColor = OldColor;
}
}
else
{
pdcattr->IcmPenColor = OldColor;
}
//
// Somehow, IcmPenColor is initialized.
//
pdcattr->ulDirty_ |= ICM_PEN_TRANSLATED;
}
else if ((plogpen->elpBrushStyle == BS_DIBPATTERN) || (plogpen->elpBrushStyle == BS_DIBPATTERNPT))
{
PBITMAPINFO pbmiDIB;
ICMMSG(("IcmSelectExtPen:BS_DIBPATTERN or BS_DIBPATTERNPT\n"));
//
// Allocate temorary bitmap info header to get brush bitmap
//
pbmiDIB = (PBITMAPINFO)LOCALALLOC(sizeof(BITMAPINFO)+((256-1)*sizeof(RGBQUAD)));
if (pbmiDIB)
{
ULONG iColorUsage;
BOOL bAlreadyTran;
PVOID pvBits = NULL;
ULONG cjBits = 0;
//
// Get brush bitmap information, colortype, size, etc.
//
bStatus = NtGdiIcmBrushInfo(hdc,
(HBRUSH)hpen,
pbmiDIB,
pvBits,
&cjBits,
&iColorUsage,
&bAlreadyTran,
IcmQueryBrush);
if (bStatus)
{
if ((iColorUsage == DIB_RGB_COLORS) &&
(!bAlreadyTran) &&
(cjBits))
{
pvBits = (PVOID) LOCALALLOC(cjBits);
if (pvBits)
{
//
// Get brush bitmap bits.
//
bStatus = NtGdiIcmBrushInfo(hdc,
(HBRUSH)hpen,
pbmiDIB,
pvBits,
&cjBits,
NULL,
NULL,
IcmQueryBrush);
if (bStatus)
{
//
// must make a copy of the DIB data
//
DWORD dwNumScan = ABS(pbmiDIB->bmiHeader.biHeight);
ULONG nColors = pbmiDIB->bmiHeader.biWidth *
dwNumScan * (pbmiDIB->bmiHeader.biBitCount/8);
//
// IcmTranslateDIB may create new copy of bitmap bits and/or
// bitmap info header, if nessesary.
//
PVOID pvBitsNew = NULL;
PBITMAPINFO pbmiDIBNew = NULL;
bStatus = IcmTranslateDIB(hdc,
pdcattr,
nColors,
pvBits,
&pvBitsNew,
pbmiDIB,
&pbmiDIBNew,
NULL,
dwNumScan,
iColorUsage,
ICM_FORWARD,
NULL,NULL);
if (bStatus)
{
if (pvBitsNew != NULL)
{
//
// IcmTranslateDIB creates new bitmap buffer, then
// free original buffer and set new one.
//
LOCALFREE(pvBits);
pvBits = pvBitsNew;
}
if (pbmiDIBNew != NULL)
{
//
// If bitmapInfo header is updated, use new one.
// And, need to compute bitmap bits size based
// on new bitmap header.
//
LOCALFREE(pbmiDIB);
pbmiDIB = pbmiDIBNew;
//
// Calculate bitmap bits size based on BITMAPINFO and nNumScans
//
cjBits = cjBitmapBitsSize(pbmiDIB);
}
//
// Set ICM-translated DIB into brush
//
bStatus = NtGdiIcmBrushInfo(hdc,
(HBRUSH)hpen,
pbmiDIB,
pvBits,
&cjBits,
NULL,
NULL,
IcmSetBrush);
if (bStatus)
{
//
// Translated.
//
bAlreadyTran = TRUE;
}
else
{
WARNING("IcmSelectExtPen():NtGdiIcmBrushInfo(SET) Failed\n");
}
}
else
{
WARNING("IcmSelectBrush():IcmTranslateDIB() Failed\n");
}
}
else
{
WARNING("IcmSelectExtPen():NtGdiIcmBrushInfo(GET) Failed\n");
}
LOCALFREE(pvBits);
}
else
{
WARNING("IcmSelectExtPen(): LOCALALLOC(pvBits) failed\n");
}
}
if (bAlreadyTran)
{
//
// Eventually, IcmPenColor is initialized.
//
pdcattr->ulDirty_ |= ICM_PEN_TRANSLATED;
}
}
else
{
ICMWRN(("IcmSelectBrush(): Fail to get brush bitmap size or bitmap is DIB_PAL_COLORS\n"));
}
LOCALFREE(pbmiDIB);
}
else
{
WARNING("IcmSelectExtPen(): LOCALALLOC(pbmi) failed\n");
}
}
else
{
#if DBG_ICM
DbgPrint("IcmSelectExtPen:ICM does not support this style (%d), yet\n",plogpen->elpBrushStyle);
#endif
}
if (plogpen != &logpenLocal)
{
LOCALFREE(plogpen);
}
}
else
{
WARNING("IcmSelectExtPen():GetObjectW() failed on hextpen\n");
}
return(bStatus);
}
/******************************Public*Routine******************************\
* IcmGetProfileColorFormat()
*
* History:
*
* Write it:
* 12-Feb-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BMFORMAT
IcmGetProfileColorFormat(
HPROFILE hProfile
)
{
//
// defaut is RGB
//
ULONG ColorFormat = BM_xBGRQUADS;
PROFILEHEADER ProfileHeader;
ICMAPI(("gdi32: IcmGetProfileColorFormat\n"));
//
// Get profile header information.
//
if (((*fpGetColorProfileHeader)(hProfile,&ProfileHeader)))
{
DWORD ColorSpace;
//
// Yes, we succeed to get profile header.
//
ColorSpace = ProfileHeader.phDataColorSpace;
//
// Figure out color format from color space.
//
switch (ColorSpace)
{
case SPACE_CMYK:
ICMMSG(("IcmGetProfileColorFormat(): CMYK Color Space\n"));
//
// Output format is CMYK color.
//
ColorFormat = BM_KYMCQUADS;
break;
case SPACE_RGB:
ICMMSG(("IcmGetProfileColorFormat(): RGB Color Space\n"));
//
// Output format is same as COLORREF (0x00bbggrr)
//
ColorFormat = BM_xBGRQUADS;
break;
default:
WARNING("IcmGetProfileColorFormat(): Unknown color space\n");
ColorFormat = 0xFFFFFFFF;
break;
}
}
return (ColorFormat);
}
/******************************Public*Routine******************************\
* IcmEnumColorProfile()
*
* History:
*
* Write it:
* 12-Feb-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
int
IcmEnumColorProfile(
HDC hdc,
PVOID pvCallBack,
LPARAM lParam,
BOOL bAnsiCallBack,
PDEVMODEW pDevModeW,
DWORD *pdwColorSpaceFlag
)
{
int iRet = -1; // -1 means fail.
int iRetFromCMS = -1;
BYTE StackDeviceData[MAX_PATH*2*sizeof(WCHAR)];
WCHAR StackProfileData[MAX_PATH];
WCHAR StackTempBuffer[MAX_PATH];
CHAR StackTempBufferA[MAX_PATH];
PVOID pvFree = NULL;
PWSTR ProfileNames = StackProfileData;
DWORD cjAllocate = 0;
LPWSTR pDeviceName = NULL;
DWORD dwDeviceClass = 0L;
PLDC pldc = NULL;
DWORD bDontAskDriver = FALSE;
DWORD dwSize;
ICMAPI(("gdi32: IcmEnumColorProfile\n"));
//
// Load external ICM dlls
//
LOAD_ICMDLL(iRet);
//
// Try to identify device name, class and devmode (if hdc is given)
//
if (hdc)
{
pldc = GET_PLDC(hdc);
if (pldc && pldc->hSpooler)
{
DWORD cbFilled;
//
// This is printer.
//
dwDeviceClass = CLASS_PRINTER;
//
// Get current DEVMODE for printer (if devmode is not given)
//
if (!pDevModeW)
{
if (pldc->pDevMode)
{
ICMMSG(("IcmEnumColorProfile():Cached DEVMODE used\n"));
pDevModeW = pldc->pDevMode;
}
else
{
ICMMSG(("IcmEnumColorProfile():Get default DEVMODE\n"));
//
// UNDER_CONSTRUCTION: NEED TO USE CURRENT DEVMODE, NOT DEFAULT DEVMODE.
//
pDevModeW = pdmwGetDefaultDevMode(pldc->hSpooler,NULL,&pvFree);
}
}
//
// Get printer device name, Try level 1 information.
//
if ((*fpGetPrinterW)(pldc->hSpooler,1,
(BYTE *) &StackDeviceData,sizeof(StackDeviceData),
&cbFilled))
{
PRINTER_INFO_1W *pPrinterInfo1 = (PRINTER_INFO_1W *) &StackDeviceData;
//
// Device name is in there.
//
pDeviceName = pPrinterInfo1->pName;
}
else
{
ICMMSG(("IcmEnumColorProfile():FAILED on GetPrinterW(INFO_1) - %d\n",GetLastError()));
//
// Failed on GetPrinter, So get device name from DEVMODE
// (this will be limited to 32 character, but better than nothing.)
//
if (pDevModeW)
{
pDeviceName = pDevModeW->dmDeviceName;
}
}
//
// Get configuration about we need to ask driver for profile or not.
//
dwSize = sizeof(DWORD);
if ((*fpInternalGetDeviceConfig)(pDeviceName, CLASS_PRINTER, MSCMS_PROFILE_ENUM_MODE,
&bDontAskDriver, &dwSize))
{
ICMMSG(("IcmEnumColorProfile():EnumMode = %d\n",bDontAskDriver));
}
else
{
bDontAskDriver = FALSE; // if error, set back as default.
}
}
else if (GetDeviceCaps(hdc,TECHNOLOGY) == DT_RASDISPLAY)
{
//
// This is display.
//
dwDeviceClass = CLASS_MONITOR;
//
// Get monitor name for this DC.
//
if (NtGdiGetMonitorID(hdc,sizeof(StackDeviceData), (LPWSTR) StackDeviceData))
{
pDeviceName = (LPWSTR) StackDeviceData;
}
else
{
WARNING("NtGdiGetMonitorID failed, use hardcoded data\n");
//
// If failed, use "DISPLAY"
//
pDeviceName = L"DISPLAY";
}
}
}
else if (pDevModeW)
{
pDeviceName = pDevModeW->dmDeviceName;
}
if (pDeviceName)
{
ICMMSG(("IcmEnumColorProfile() DeviceName = %ws\n",pDeviceName));
}
//
// If we have devmode, call printer driver UI first to obtain color profile.
//
if (pDevModeW && /* devmode should be given */
pdwColorSpaceFlag && /* no query context */
pldc && pldc->hSpooler && /* only for printer driver */
!bDontAskDriver) /* only when we need ask driver */
{
//
// Ask (Printer UI) driver for default device color profile
//
iRetFromCMS = IcmAskDriverForColorProfile(pldc,QCP_DEVICEPROFILE,
pDevModeW,ProfileNames,pdwColorSpaceFlag);
//
// if iRet is greater then 0, driver have paticular color profile to use.
//
if (iRetFromCMS > 0)
{
if (pvCallBack)
{
//
// Build ICM profile file path.
//
BuildIcmProfilePath(ProfileNames,StackTempBuffer,MAX_PATH);
if (bAnsiCallBack)
{
bToASCII_N(StackTempBufferA,MAX_PATH,
StackTempBuffer, wcslen(StackTempBuffer)+1);
//
// Callback application.
//
iRet = (*(ICMENUMPROCA)pvCallBack)(StackTempBufferA,lParam);
}
else
{
iRet = (*(ICMENUMPROCW)pvCallBack)(StackTempBuffer,lParam);
}
if (iRet > 0)
{
//
// If iRet is positive value, continue to enumeration.
//
iRetFromCMS = -1;
}
}
else
{
//
// There is no call back function, just use return value from CMS.
//
iRet = iRetFromCMS;
}
}
else
{
iRetFromCMS = -1;
}
}
if (iRetFromCMS == -1)
{
ENUMTYPEW EnumType;
//
// Initialize with zero.
//
RtlZeroMemory(&EnumType,sizeof(ENUMTYPEW));
//
// Fill up EnumType structure
//
EnumType.dwSize = sizeof(ENUMTYPEW);
EnumType.dwVersion = ENUM_TYPE_VERSION;
//
// If device name is given use it, otherwise get it from DEVMODE.
//
if (pDeviceName)
{
EnumType.dwFields |= ET_DEVICENAME;
EnumType.pDeviceName = pDeviceName;
}
//
// Set DeviceClass (if hdc is given)
//
if (dwDeviceClass)
{
EnumType.dwFields |= ET_DEVICECLASS;
EnumType.dwDeviceClass = dwDeviceClass;
}
//
// Pick up any additional info from devmode (if we have)
//
if (pDevModeW)
{
//
// Set MediaType is presented.
//
if (pDevModeW->dmFields & DM_MEDIATYPE)
{
EnumType.dwFields |= ET_MEDIATYPE;
EnumType.dwMediaType = pDevModeW->dmMediaType;
}
if (pDevModeW->dmFields & DM_DITHERTYPE)
{
EnumType.dwFields |= ET_DITHERMODE;
EnumType.dwDitheringMode = pDevModeW->dmDitherType;
}
if ((pDevModeW->dmFields & DM_PRINTQUALITY) &&
(pDevModeW->dmPrintQuality >= 0))
{
EnumType.dwFields |= ET_RESOLUTION;
EnumType.dwResolution[0] = pDevModeW->dmPrintQuality;
if (pDevModeW->dmFields & DM_YRESOLUTION)
{
EnumType.dwResolution[1] = pDevModeW->dmYResolution;
}
else
{
EnumType.dwResolution[1] = pDevModeW->dmPrintQuality;
}
ICMMSG(("Resolution in devmode (%d,%d)\n",
EnumType.dwResolution[0],EnumType.dwResolution[1]));
}
}
//
// Figure out how much memory we need.
//
iRetFromCMS = (*fpEnumColorProfilesW)(NULL,&EnumType,NULL,&cjAllocate,NULL);
//
// Buffer should be requested ,at least, more then 2 unicode-null.
//
if (cjAllocate > (sizeof(UNICODE_NULL) * 2))
{
//
// If the buffer on stack is not enough, allocate it.
//
if (cjAllocate > sizeof(StackProfileData))
{
//
// Allocate buffer to recieve data.
//
ProfileNames = LOCALALLOC(cjAllocate);
if (ProfileNames == NULL)
{
GdiSetLastError(ERROR_NOT_ENOUGH_MEMORY);
goto IcmEnumColorProfile_Cleanup;
}
}
//
// Enumurate profiles
//
iRetFromCMS = (*fpEnumColorProfilesW)(NULL,&EnumType,(PBYTE)ProfileNames,&cjAllocate,NULL);
if (iRetFromCMS == 0)
{
//
// There is no profile enumulated.
//
goto IcmEnumColorProfile_Cleanup;
}
if (pvCallBack)
{
PWSTR pwstr;
//
// Callback for each file.
//
pwstr = ProfileNames;
while(*pwstr)
{
//
// Build ICM profile file path.
//
BuildIcmProfilePath(pwstr,StackTempBuffer,MAX_PATH);
if (bAnsiCallBack)
{
bToASCII_N(StackTempBufferA,MAX_PATH,
StackTempBuffer, wcslen(StackTempBuffer)+1);
//
// Callback application.
//
iRet = (*(ICMENUMPROCA)pvCallBack)(StackTempBufferA,lParam);
}
else
{
iRet = (*(ICMENUMPROCW)pvCallBack)(StackTempBuffer,lParam);
}
if (iRet == 0)
{
//
// Stop enumlation.
//
break;
}
//
// Move pointer to next.
//
pwstr += (wcslen(pwstr)+1);
}
}
else
{
//
// There is no call back function, just use return value from CMS.
//
iRet = iRetFromCMS;
}
}
IcmEnumColorProfile_Cleanup:
if (ProfileNames && (ProfileNames != StackProfileData))
{
LOCALFREE(ProfileNames);
}
}
//
// Free devmode buffer.
//
if (pvFree)
{
LOCALFREE(pvFree);
}
return (iRet);
}
/******************************Public*Routine******************************\
* IcmQueryProfileCallBack()
*
* History:
*
* Write it:
* 19-Feb-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
int CALLBACK
IcmQueryProfileCallBack(
LPWSTR lpFileName,
LPARAM lAppData
)
{
PROFILECALLBACK_DATA *ProfileCallBack = (PROFILECALLBACK_DATA *)lAppData;
if (lpFileName)
{
PWSZ FileNameOnly = GetFileNameFromPath(lpFileName);
if (_wcsicmp(ProfileCallBack->pwszFileName,FileNameOnly) == 0)
{
//
// Yes, found it.
//
ProfileCallBack->bFound = TRUE;
//
// stop enumuration.
//
return (0);
}
}
//
// Continue to enumuration.
//
return (1);
}
/******************************Public*Routine******************************\
* IcmFindProfileCallBack()
*
* History:
*
* Write it:
* 19-Feb-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
int CALLBACK
IcmFindProfileCallBack(
LPWSTR lpFileName,
LPARAM lAppData
)
{
//
// OK, just pick up first enumuration.
//
lstrcpyW((PWSZ)lAppData,lpFileName);
//
// And then stop enumuration.
//
return (0);
}
/******************************Public*Routine******************************\
* GetFileNameFromPath()
*
* History:
*
* Write it:
* 19-Feb-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
PWSTR
GetFileNameFromPath(
PWSTR pwszFileName
)
{
PWSTR FileNameOnly = NULL;
//
// Check for: C:\PathName\Profile.icm
//
FileNameOnly = wcsrchr(pwszFileName,L'\\');
if (FileNameOnly != NULL)
{
FileNameOnly++; // Skip '\\'
}
else
{
//
// For: C:Profile.icm
//
FileNameOnly = wcschr(pwszFileName,L':');
if (FileNameOnly != NULL)
{
FileNameOnly++; // Skip ':'
}
else
{
//
// Otherwise Profile.icm
//
FileNameOnly = pwszFileName;
}
}
return (FileNameOnly);
}
/******************************Public*Routine******************************\
* IcmCreateProfileFromLCS()
*
* History:
*
* Write it:
* 19-Feb-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmCreateProfileFromLCS(
LPLOGCOLORSPACEW lpLogColorSpaceW,
PVOID *ppvProfileData,
PULONG pulProfileSize
)
{
BOOL bRet;
ICMAPI(("gdi32: IcmCreateProfileFromLCS\n"));
//
// Call MSCMS.DLL to create Profile from LOGCOLORSPACE
//
bRet = (*fpCreateProfileFromLogColorSpaceW)(lpLogColorSpaceW,
(PBYTE *)ppvProfileData);
if (bRet && *ppvProfileData)
{
*pulProfileSize = (ULONG)GlobalSize(*ppvProfileData);
}
return (bRet);
}
/******************************Public*Routine******************************\
* BuildIcmProfilePath()
*
* History:
*
* Write it:
* 07-Apr-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
PWSZ
BuildIcmProfilePath(
PWSZ FileName, // IN
PWSZ FullPathFileName, // OUT
ULONG BufferSize
)
{
PWSZ FileNameOnly;
//
// BufferSize - need to be used for overrap check sometime later...
//
FileNameOnly = GetFileNameFromPath(FileName);
if (FileName == FileNameOnly)
{
// It seems we don't have any specified path, just use color directory.
const UINT c_cBufChars = MAX_PATH;
// Use a temporary because FileName and FullPathFileName can be the same
// and wcsncpy doesn't like that.
WCHAR awchTemp[MAX_PATH];
int count = c_cBufChars;
// Copy color directory first, then filename
// wcsncpy does not append a NULL if the count is smaller than the
// string. Do it manually so that wcsncat and wcslen work.
wcsncpy(awchTemp, ColorDirectory, count);
awchTemp[c_cBufChars-1] = 0;
// Leave space for the NULL terminator. Note, because we append a
// NULL terminator above, wcslen cannot return a number bigger than
// BufferSize-1. Therefore the resulting count cannot be negative.
count = c_cBufChars-wcslen(awchTemp)-1;
ASSERT(count>=0);
wcsncat(awchTemp,L"\\",count);
// leave space for the NULL
count = c_cBufChars-wcslen(awchTemp)-1;
ASSERT(count>=0);
wcsncat(awchTemp, FileNameOnly, count);
// copy to the final destination and force NULL termination.
wcsncpy(FullPathFileName, awchTemp, BufferSize);
FullPathFileName[BufferSize-1] = 0;
}
else
{
//
// Input path contains path, just use that.
//
if (FileName != FullPathFileName)
{
//
// Source and destination buffer is different, need to copy.
//
wcsncpy(FullPathFileName,FileName,BufferSize);
FullPathFileName[BufferSize-1] = 0;
}
}
return (FileNameOnly);
}
/******************************Public*Routine******************************\
* IcmSameColorSpace()
*
* History:
*
* Write it:
* 21-Apr-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmSameColorSpace(
PCACHED_COLORSPACE pColorSpaceA,
PCACHED_COLORSPACE pColorSpaceB
)
{
ICMAPI(("gdi32: IcmSameColorSpace\n"));
if (pColorSpaceA == pColorSpaceB)
{
ICMMSG(("IcmSameColorSpace - Yes\n"));
return (TRUE);
}
else
{
ICMMSG(("IcmSameColorSpace - No\n"));
return (FALSE);
}
}
/******************************Public*Routine******************************\
* IcmGetColorSpaceByColorSpace()
*
* History:
*
* Write it:
* 21-Apr-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
PCACHED_COLORSPACE
IcmGetColorSpaceByColorSpace(
HGDIOBJ hObjRequest,
LPLOGCOLORSPACEW lpLogColorSpace,
PPROFILE pColorProfile,
DWORD dwColorSpaceFlags
)
{
PCACHED_COLORSPACE pCandidateColorSpace = NULL;
PWSZ pProfileName;
BOOL bNeedMatchHdc = FALSE;
PLIST_ENTRY p;
ICMAPI(("gdi32: IcmGetColorSpaceByColorSpace\n"));
//
// If this is "on memory" profile which size is larger than
// maximum size of cachable profile withOUT filename,
// don't search cache, since we never be able to find from cache.
//
if (pColorProfile &&
(pColorProfile->dwType == PROFILE_MEMBUFFER) &&
(pColorProfile->cbDataSize > MAX_SIZE_OF_COLORPROFILE_TO_CACHE) &&
(lpLogColorSpace->lcsFilename[0] == UNICODE_NULL))
{
return (NULL);
}
//
// If this is metafile color space, must match hdc.
//
if (GET_COLORSPACE_TYPE(dwColorSpaceFlags) == GET_COLORSPACE_TYPE(METAFILE_COLORSPACE))
{
bNeedMatchHdc = TRUE;
}
pProfileName = lpLogColorSpace->lcsFilename;
//
// Search from cache.
//
ENTERCRITICALSECTION(&semColorSpaceCache);
p = ListCachedColorSpace.Flink;
while(p != &ListCachedColorSpace)
{
pCandidateColorSpace = CONTAINING_RECORD(p,CACHED_COLORSPACE,ListEntry);
//
// If this colorspace depends on specific gdi object, check it.
//
if (/* hdc is match */
(pCandidateColorSpace->hObj == hObjRequest) ||
/* candidate is not specific to hdc, and does not need to match hdc */
((bNeedMatchHdc == FALSE) && (pCandidateColorSpace->hObj == NULL)))
{
LOGCOLORSPACEW *pCandidateLogColorSpace;
PWSZ pCandidateProfileName;
//
// Get pointer to profile
//
pCandidateLogColorSpace = &(pCandidateColorSpace->LogColorSpace);
pCandidateProfileName = pCandidateColorSpace->LogColorSpace.lcsFilename;
//
// Check lcsIntent.
//
if (pCandidateLogColorSpace->lcsIntent == lpLogColorSpace->lcsIntent)
{
//
// Check profile name if given
//
if (*pProfileName && *pCandidateProfileName)
{
if (_wcsicmp(pProfileName,pCandidateProfileName) == 0)
{
ICMMSG(("IcmGetColorSpaceByColorSpace():Find in cache (by profile name)\n"));
//
// Find it ! then Increment ref. counter
//
pCandidateColorSpace->cRef++;
break;
}
}
else if ((*pProfileName == UNICODE_NULL) && (*pCandidateProfileName == UNICODE_NULL))
{
if (pColorProfile == NULL)
{
//
// Both of color space does not have color profile, check inside LOGCOLORSPACE.
//
if ((pCandidateLogColorSpace->lcsCSType == lpLogColorSpace->lcsCSType) &&
(pCandidateLogColorSpace->lcsGammaRed == lpLogColorSpace->lcsGammaRed) &&
(pCandidateLogColorSpace->lcsGammaGreen == lpLogColorSpace->lcsGammaGreen) &&
(pCandidateLogColorSpace->lcsGammaBlue == lpLogColorSpace->lcsGammaBlue) &&
(RtlCompareMemory(&(pCandidateLogColorSpace->lcsEndpoints),
&(lpLogColorSpace->lcsEndpoints),sizeof(CIEXYZTRIPLE))
== sizeof(CIEXYZTRIPLE)))
{
ICMMSG(("IcmGetColorSpaceByColorSpace():Find in cache (by metrics)\n"));
//
// Find it ! then Increment ref. counter
//
pCandidateColorSpace->cRef++;
break;
}
}
else if ((pColorProfile->dwType == PROFILE_MEMBUFFER) &&
(pCandidateColorSpace->ColorProfile.dwType == PROFILE_MEMBUFFER))
{
if (pCandidateColorSpace->ColorProfile.cbDataSize == pColorProfile->cbDataSize)
{
if (RtlCompareMemory(pCandidateColorSpace->ColorProfile.pProfileData,
pColorProfile->pProfileData,
pColorProfile->cbDataSize)
== pColorProfile->cbDataSize)
{
ICMMSG(("IcmGetColorSpaceByColorSpace():Find in cache (by on memory profile)\n"));
//
// Find it ! then Increment ref. counter
//
pCandidateColorSpace->cRef++;
break;
}
}
}
}
}
}
p = p->Flink;
pCandidateColorSpace = NULL;
}
LEAVECRITICALSECTION(&semColorSpaceCache);
return (pCandidateColorSpace);
}
/******************************Public*Routine******************************\
* IcmGetColorSpaceByHandle()
*
* History:
*
* Write it:
* 21-Apr-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
PCACHED_COLORSPACE
IcmGetColorSpaceByHandle(
HGDIOBJ hObj,
HCOLORSPACE hColorSpace,
LPLOGCOLORSPACEW lpLogColorSpace,
DWORD dwFlags
)
{
ULONG cRet;
ICMAPI(("gdi32: IcmGetColorSpaceByHandle\n"));
//
// Get LOGCOLORSPACE from handle
//
cRet = NtGdiExtGetObjectW(hColorSpace,sizeof(LOGCOLORSPACEW),lpLogColorSpace);
if (cRet >= sizeof(LOGCOLORSPACEW))
{
if (lpLogColorSpace->lcsFilename[0] != UNICODE_NULL)
{
//
// Normalize filename
//
BuildIcmProfilePath(lpLogColorSpace->lcsFilename,lpLogColorSpace->lcsFilename,MAX_PATH);
}
else
{
if (lpLogColorSpace->lcsCSType != LCS_CALIBRATED_RGB)
{
ULONG ulSize = MAX_PATH;
//
// if CSType is not LCS_CALIBRATED_RGB, we should go to MSCMS.DLL
// to get color profile for corresponding LCSType, then any given
// profile name from application is IGNORED.
//
if ((*fpGetStandardColorSpaceProfileW)(
NULL,
lpLogColorSpace->lcsCSType,
lpLogColorSpace->lcsFilename,
&ulSize))
{
ICMMSG(("IcmGetColorSpaceByHandle():CSType %x = %ws\n",
lpLogColorSpace->lcsCSType,
lpLogColorSpace->lcsFilename));
}
else
{
ICMWRN(("IcmGetColorSpaceByHandle():Error CSType = %x\n",
lpLogColorSpace->lcsCSType));
return (NULL);
}
}
}
//
// Find it !
//
return (IcmGetColorSpaceByColorSpace(hObj,lpLogColorSpace,NULL,dwFlags));
}
else
{
ICMWRN(("IcmGetColorSpaceByHandle():Failed on GetObject\n"));
return (NULL);
}
}
/******************************Public*Routine******************************\
* IcmGetColorSpaceByName()
*
* History:
*
* Write it:
* 21-Apr-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
PCACHED_COLORSPACE
IcmGetColorSpaceByName(
HGDIOBJ hObj,
PWSZ ColorProfileName,
DWORD dwIntent,
DWORD dwFlags
)
{
ICMAPI(("gdi32: IcmGetColorSpaceByName (%ws)\n",(ColorProfileName ? ColorProfileName : L"null")));
if (ColorProfileName)
{
LOGCOLORSPACEW LogColorSpace;
RtlZeroMemory(&LogColorSpace,sizeof(LOGCOLORSPACEW));
//
// Put intent in LOGCOLORSPACE
//
LogColorSpace.lcsIntent = (LCSGAMUTMATCH) dwIntent;
//
// Normalize path name
//
BuildIcmProfilePath(ColorProfileName,LogColorSpace.lcsFilename,MAX_PATH);
//
// Find it !
//
return (IcmGetColorSpaceByColorSpace(hObj,&LogColorSpace,NULL,dwFlags));
}
else
{
return (NULL);
}
}
/******************************Public*Routine******************************\
* IcmCreateColorSpaceByName()
*
* History:
*
* Write it:
* 21-Apr-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
PCACHED_COLORSPACE
IcmCreateColorSpaceByName(
HGDIOBJ hObj,
PWSZ ColorProfileName,
DWORD dwIntent,
DWORD dwFlags
)
{
LOGCOLORSPACEW LogColorSpace;
ICMAPI(("gdi32: IcmCreateColorSpaceByName\n"));
RtlZeroMemory(&LogColorSpace,sizeof(LOGCOLORSPACEW));
//
// Fill up LOGCOLORSPACE fields.
//
LogColorSpace.lcsSignature = LCS_SIGNATURE;
LogColorSpace.lcsVersion = 0x400;
LogColorSpace.lcsSize = sizeof(LOGCOLORSPACEW);
LogColorSpace.lcsCSType = LCS_CALIBRATED_RGB;
LogColorSpace.lcsIntent = (LCSGAMUTMATCH) dwIntent;
//
// Put profile file name in lcsFilename[]
//
lstrcpyW(LogColorSpace.lcsFilename,ColorProfileName);
//
// Create colorspace with LOGCOLORSPACE
//
return (IcmCreateColorSpaceByColorSpace(hObj,&LogColorSpace,NULL,dwFlags));
}
/******************************Public*Routine******************************\
* IcmCreateColorSpaceByColorSpace()
*
* History:
*
* Write it:
* 21-Apr-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
PCACHED_COLORSPACE
IcmCreateColorSpaceByColorSpace(
HGDIOBJ hObj,
LPLOGCOLORSPACEW lpLogColorSpace,
PPROFILE pProfileData,
DWORD dwFlags
)
{
PCACHED_COLORSPACE pColorSpace = NULL;
ICMAPI(("gdi32: IcmCreateColorSpaceByColorSpace\n"));
if (lpLogColorSpace)
{
//
// If ICMDLL is not loaded, yet, Just Load ICMDLL regardless current ICM mode,
// since we need it for handle this color profile. And apps can enable ICM
// later at that time, the opened color profile mighted be used.
//
if ((ghICM == NULL) && (!IcmInitialize()))
{
ICMWRN(("IcmCreateColorSpace():Fail to load ICM dlls\n"));
return (NULL);
}
//
// Allocate CACHED_COLORSPACE
//
pColorSpace = LOCALALLOC(sizeof(CACHED_COLORSPACE));
if (pColorSpace)
{
//
// Zero init CACHED_COLORSPACE
//
RtlZeroMemory(pColorSpace,sizeof(CACHED_COLORSPACE));
//
// Copy LOGCOLORSPACE into CACHED_COLORSPACE
//
RtlCopyMemory(&(pColorSpace->LogColorSpace),lpLogColorSpace,sizeof(LOGCOLORSPACEW));
//
// Default colorspace is RGB (BGR = 0x00bbggrr same as COLORREF format)
//
pColorSpace->ColorFormat = BM_xBGRQUADS;
//
// Map intent value for MSCMS from LOGCOLORSPACE.
//
switch (lpLogColorSpace->lcsIntent)
{
case LCS_GM_BUSINESS:
pColorSpace->ColorIntent = INTENT_SATURATION;
break;
case LCS_GM_GRAPHICS:
pColorSpace->ColorIntent = INTENT_RELATIVE_COLORIMETRIC;
break;
case LCS_GM_IMAGES:
pColorSpace->ColorIntent = INTENT_PERCEPTUAL;
break;
case LCS_GM_ABS_COLORIMETRIC:
pColorSpace->ColorIntent = INTENT_ABSOLUTE_COLORIMETRIC;
break;
default:
ICMWRN(("IcmCreateColorSpace():Invalid intent value\n"));
LOCALFREE(pColorSpace);
return (NULL);
}
//
// Keep flags
//
pColorSpace->flInfo = dwFlags;
//
// if the color space is specific to some GDI object, keep its handle.
//
// for DIBSECTION_COLORSPACE, CreateDIBSection calls us this hdc in hObj,
// then later overwrite hObj with thier bitmap handle. this prevent from
// this color space is shared with others.
//
if (dwFlags & HGDIOBJ_SPECIFIC_COLORSPACE)
{
pColorSpace->hObj = hObj;
}
//
// If this is not LCS_CALIBRATED_RGB, get color profile name.
//
if (lpLogColorSpace->lcsCSType != LCS_CALIBRATED_RGB)
{
ULONG ulSize = MAX_PATH;
//
// if CSType is not LCS_CALIBRATED_RGB, we should go to MSCMS.DLL
// to get color profile for corresponding LCSType, then any given
// profile name from application is IGNORED.
//
if ((*fpGetStandardColorSpaceProfileW)(
NULL, lpLogColorSpace->lcsCSType,
pColorSpace->LogColorSpace.lcsFilename, &ulSize))
{
ICMMSG(("IcmCreateColorSpace():CSType %x = %ws\n",
lpLogColorSpace->lcsCSType,
pColorSpace->LogColorSpace.lcsFilename));
}
else
{
ICMWRN(("IcmCreateColorSpace():Error CSType = %x\n",
lpLogColorSpace->lcsCSType));
LOCALFREE(pColorSpace);
return (NULL);
}
}
//
// Use PROFILE if profile is given
//
if ((pProfileData != NULL) &&
(pProfileData->dwType == PROFILE_MEMBUFFER) &&
(pProfileData->pProfileData != NULL) &&
(pProfileData->cbDataSize != 0))
{
ICMMSG(("IcmCreateColorSpace():Create ColorSpace cache by memory profile\n"));
ASSERTGDI(dwFlags & ON_MEMORY_PROFILE,
"IcmCreateColorSpace():dwFlags does not have ON_MEMORY_PROFILE");
if (!(dwFlags & NOT_CACHEABLE_COLORSPACE))
{
//
// Try to make a copy, if profile size is small enough,
// so that we can cache this profile.
//
if (pProfileData->cbDataSize <= MAX_SIZE_OF_COLORPROFILE_TO_CACHE)
{
pColorSpace->ColorProfile.pProfileData = GlobalAlloc(GMEM_FIXED,pProfileData->cbDataSize);
if (pColorSpace->ColorProfile.pProfileData)
{
ICMMSG(("IcmCreateColorSpace():Profile data can be cacheable\n"));
pColorSpace->ColorProfile.dwType = PROFILE_MEMBUFFER;
pColorSpace->ColorProfile.cbDataSize = pProfileData->cbDataSize;
RtlCopyMemory(pColorSpace->ColorProfile.pProfileData,
pProfileData->pProfileData,
pProfileData->cbDataSize);
//
// Make sure it is cachable...
//
ASSERTGDI((pColorSpace->flInfo & NOT_CACHEABLE_COLORSPACE) == 0,
"IcmCreateColorSpace():flInfo has NOT_CACHEABLE_COLORSPACE");
//
// Profile memory need to be freed at deletion.
//
pColorSpace->flInfo |= NEED_TO_FREE_PROFILE;
}
}
}
//
// If not able to cache, it the profile data in application.
//
if (pColorSpace->ColorProfile.pProfileData == NULL)
{
//
// Use PROFILE data if it's given in parameter.
//
pColorSpace->ColorProfile = *pProfileData;
//
// We don't make a copy of profile data, so profile data possible to be
// free by application, so this color space can not be cached
//
pColorSpace->flInfo |= NOT_CACHEABLE_COLORSPACE;
}
}
else if (lpLogColorSpace->lcsFilename[0] != UNICODE_NULL)
{
PWSZ pszFileNameOnly;
ICMMSG(("IcmCreateColorSpace():Create ColorSpace cache by file - %ws\n",
lpLogColorSpace->lcsFilename));
//
// Normalize filename
//
pszFileNameOnly = BuildIcmProfilePath(pColorSpace->LogColorSpace.lcsFilename,
pColorSpace->LogColorSpace.lcsFilename,MAX_PATH);
//
// If this is sRGB (= sRGB Color Space Profile.icm) color profile, ...
//
if (_wcsicmp(pszFileNameOnly,sRGB_PROFILENAME) == 0)
{
//
// Mark device_calibrate_colorspace flag.
//
pColorSpace->flInfo |= DEVICE_CALIBRATE_COLORSPACE;
}
//
// Fill up PROFILE structure and open it.
//
pColorSpace->ColorProfile.dwType = PROFILE_FILENAME;
pColorSpace->ColorProfile.pProfileData = pColorSpace->LogColorSpace.lcsFilename;
pColorSpace->ColorProfile.cbDataSize = MAX_PATH * sizeof(WCHAR);
}
else // if we only have parameter in LOGCOLORSPACE but not lcsFileName.
{
BOOL bRet;
//
// Convert LOGCOLORSPACE to ICC Profile.
//
ICMMSG(("IcmCreateColorSpace():Create ColorSpace cache by LOGCOLRSPACE\n"));
//
// Fill up PROFILE structure.
//
pColorSpace->ColorProfile.dwType = PROFILE_MEMBUFFER;
pColorSpace->ColorProfile.pProfileData = NULL;
//
// Call convert function. (LOGCOLORSPACE -> ICC PROFILE)
//
bRet = IcmCreateProfileFromLCS(
&(pColorSpace->LogColorSpace), // source logColorSpace
&(pColorSpace->ColorProfile.pProfileData), // receive pointer to profile image
&(pColorSpace->ColorProfile.cbDataSize)); // receive size of profile image
if ((bRet == FALSE) ||
(pColorSpace->ColorProfile.pProfileData == NULL) ||
(pColorSpace->ColorProfile.cbDataSize == 0))
{
ICMWRN(("IcmCreateColorSpaceByColorSpace():IcmCreateProfileFromLCS() failed\n"));
LOCALFREE(pColorSpace);
return (NULL);
}
//
// Mark pProfileData must be freed at deletion.
//
pColorSpace->flInfo |= NEED_TO_FREE_PROFILE;
}
//
// At this point, we don't have color format yet,
// so call IcmRealizeColorProfile with no color format checking.
//
if (IcmRealizeColorProfile(pColorSpace,FALSE))
{
//
// Get profile color format
//
pColorSpace->ColorFormat = IcmGetProfileColorFormat(pColorSpace->hProfile);
//
// Until create color transform, we don't need realized color space.
//
IcmUnrealizeColorProfile(pColorSpace);
}
else
{
ICMWRN(("IcmCreateColorSpace():Fail to realize color profile\n"));
if (pColorSpace->flInfo & NEED_TO_FREE_PROFILE)
{
GlobalFree(pColorSpace->ColorProfile.pProfileData);
}
LOCALFREE(pColorSpace);
return (NULL);
}
//
// Initialize ref. counter
//
pColorSpace->cRef = 1;
//
// Put the created color space into the list
//
ENTERCRITICALSECTION(&semColorSpaceCache);
InsertTailList(&ListCachedColorSpace,&(pColorSpace->ListEntry));
cCachedColorSpace++;
LEAVECRITICALSECTION(&semColorSpaceCache);
}
else
{
WARNING("gdi32:IcmCreateColorSpace():LOCALALLOC failed\n");
}
}
return (pColorSpace);
}
/******************************Public*Routine******************************\
* ColorProfile on demand loading/unloading support functions
*
* History:
*
* Write it:
* 29-Nov-1998 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmRealizeColorProfile(
PCACHED_COLORSPACE pColorSpace,
BOOL bCheckColorFormat
)
{
ICMAPI(("gdi32: IcmRealizeColorProfile\n"));
if (pColorSpace)
{
if ((pColorSpace->hProfile == NULL) &&
(pColorSpace->ColorProfile.pProfileData != NULL))
{
HPROFILE hProfile = (*fpOpenColorProfileW)(
&(pColorSpace->ColorProfile),
PROFILE_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
OPEN_EXISTING);
if (hProfile)
{
//
// Make sure color format of color profile has not been changed.
//
if ((bCheckColorFormat == FALSE) ||
(pColorSpace->ColorFormat == IcmGetProfileColorFormat(hProfile)))
{
pColorSpace->hProfile = hProfile;
}
else
{
(*fpCloseColorProfile)(hProfile);
}
}
}
return ((BOOL)!!pColorSpace->hProfile);
}
else
{
return (TRUE);
}
}
VOID
IcmUnrealizeColorProfile(
PCACHED_COLORSPACE pColorSpace
)
{
ICMAPI(("gdi32: IcmUnrealizeColorProfile\n"));
if (pColorSpace && pColorSpace->hProfile)
{
(*fpCloseColorProfile)(pColorSpace->hProfile);
pColorSpace->hProfile = NULL;
}
}
/******************************Public*Routine******************************\
* Metafiling support functions
*
* History:
*
* Write it:
* 23-May-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
VOID
IcmInsertMetafileList(
PLIST_ENTRY pListHead,
PWSZ pName
)
{
PMETAFILE_COLORPROFILE pData;
pData = LOCALALLOC(sizeof(METAFILE_COLORPROFILE));
if (pData)
{
wcscpy(pData->ColorProfile,pName);
InsertTailList(pListHead,&(pData->ListEntry));
}
}
BOOL
IcmCheckMetafileList(
PLIST_ENTRY pListHead,
PWSZ pName
)
{
PLIST_ENTRY p;
PMETAFILE_COLORPROFILE pData;
p = pListHead->Flink;
while (p != pListHead)
{
pData = (PVOID) CONTAINING_RECORD(p,METAFILE_COLORPROFILE,ListEntry);
if (_wcsicmp(pData->ColorProfile,pName) == 0)
{
return TRUE;
}
p = p->Flink;
}
return FALSE;
}
VOID
IcmFreeMetafileList(
PLIST_ENTRY pListHead
)
{
PLIST_ENTRY p;
PVOID pData;
p = pListHead->Flink;
while(p != pListHead)
{
pData = (PVOID) CONTAINING_RECORD(p,METAFILE_COLORPROFILE,ListEntry);
//
// Need to get pointer to next before free memory.
//
p = p->Flink;
//
// then free memory.
//
LOCALFREE(pData);
}
InitializeListHead(pListHead);
}
/******************************Public*Routine******************************\
* IcmStretchBlt()
*
* History:
*
* Write it:
* 29-May-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmStretchBlt(HDC hdc, int x, int y, int cx, int cy,
HDC hdcSrc, int x1, int y1, int cx1, int cy1, DWORD rop,
PDC_ATTR pdcattr, PDC_ATTR pdcattrSrc)
{
int iRet = 0;
PGDI_ICMINFO pIcmInfo;
HBITMAP hbm;
PVOID pvBits;
PBITMAPINFO pbmi;
ULONG cjBits;
HCOLORSPACE hSourceColorSpace = NULL,
hOldColorSpace = NULL;
PCACHED_COLORSPACE pSourceColorSpace = NULL;
POINT ptDevice[2];
UINT nNumScan, nNumWidth;
UINT nStartScan, nStartWidth;
BOOL bNoScaling;
BYTE dibData[(sizeof(DIBSECTION)+256*sizeof(RGBQUAD))];
ICMAPI(("gdi32: IcmStretchBlt\n"));
//
// Convert Logical coord to Physical coord on source.
//
ptDevice[0].x = x1;
ptDevice[0].y = y1;
ptDevice[1].x = x1 + cx1;
ptDevice[1].y = y1 + cy1;
if (LPtoDP(hdcSrc,ptDevice,2) == FALSE)
{
//
// can't handle, let callee handle this.
//
return (FALSE);
}
//
// Compute new origin.
//
nStartWidth = ptDevice[0].x;
nStartScan = ptDevice[0].y;
nNumWidth = ptDevice[1].x - ptDevice[0].x;
nNumScan = ptDevice[1].y - ptDevice[0].y;
//
// Check source bounds.
//
if (((INT)nStartWidth < 0) || ((INT)nStartScan < 0) || ((INT)nNumWidth < 0) || ((INT)nNumScan < 0))
{
ICMWRN(("IcmStretchBlt: (x1,y1) is out of surface\n"));
//
// We can't handle this, let callee handle this.
//
return (FALSE);
}
//
// Is there any scaling ?
//
bNoScaling = ((cx == (int)nNumWidth) && (cy == (int)nNumScan));
//
// Get bitmap handle.
//
hbm = (HBITMAP) GetDCObject(hdcSrc, LO_BITMAP_TYPE);
if (bDIBSectionSelected(pdcattrSrc))
{
//
// Get DIBSECTION currently selected in source DC.
//
if (GetObject(hbm, sizeof(DIBSECTION), &dibData) != (int)sizeof(DIBSECTION))
{
WARNING("IcmStretchBlt: GetObject(DIBSECTION) failed\n");
return(FALSE);
}
//
// Load color table and overwrite DIBSECTION structure from right after BITMAPINFOHEADER
//
if (((DIBSECTION *)&dibData)->dsBm.bmBitsPixel <= 8)
{
GetDIBColorTable(hdcSrc, 0, 256, (RGBQUAD *)&((DIBSECTION *)&dibData)->dsBitfields[0]);
}
pbmi = (PBITMAPINFO)&(((DIBSECTION *)&dibData)->dsBmih);
// if ((nStartScan + nNumScan) > (((DIBSECTION *)&dibData)->dsBm.bmHeight))
// {
// nNumScan = (((DIBSECTION *)&dibData)->dsBm.bmHeight - nStartScan);
// }
//
// Setup color source/destination colorspaces
//
if (IS_ICM_INSIDEDC(pdcattrSrc->lIcmMode))
{
//
// if ICM is turned on source DC. we will use source DC's
// destination color space as destination DC's source
// color space.
//
pIcmInfo = GET_ICMINFO(pdcattrSrc);
if (pIcmInfo && pIcmInfo->pDestColorSpace)
{
hSourceColorSpace = CreateColorSpaceW(&(pIcmInfo->pDestColorSpace->LogColorSpace));
pSourceColorSpace = pIcmInfo->pDestColorSpace;
}
}
if (hSourceColorSpace == NULL)
{
//
// if no colorspace, use sRGB.
//
hSourceColorSpace = GetStockObject(PRIV_STOCK_COLORSPACE);
pSourceColorSpace = NULL;
}
}
else if (IS_ICM_LAZY_CORRECTION(pdcattrSrc->lIcmMode))
{
//
// Get BITMAP currently selected in source DC.
//
if (GetObject(hbm, sizeof(BITMAP), &dibData) != (int)sizeof(BITMAP))
{
WARNING("IcmStretchBlt: GetObject(BITMAP) failed\n");
return(FALSE);
}
//
// Create bitmap info header
//
pbmi = (PBITMAPINFO) ((PBYTE)dibData+sizeof(BITMAP));
pbmi->bmiHeader.biSize = sizeof(BITMAPINFO);
pbmi->bmiHeader.biHeight = ((BITMAP *)&dibData)->bmHeight;
pbmi->bmiHeader.biWidth = ((BITMAP *)&dibData)->bmWidth;
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biBitCount = 24; // 24bpp
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = 0;
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
// if ((nStartScan + nNumScan) > pbmi->bmiHeader.biHeight)
// {
// nNumScan = pbmi->bmiHeader.biHeight - nStartScan;
// }
ASSERTGDI(IS_ICM_INSIDEDC(pdcattrSrc->lIcmMode),
"IcmStretchBlt():Lazy color correction, but ICM is not enabled\n");
pIcmInfo = GET_ICMINFO(pdcattrSrc);
if (pIcmInfo && pIcmInfo->pSourceColorSpace)
{
hSourceColorSpace = CreateColorSpaceW(&(pIcmInfo->pSourceColorSpace->LogColorSpace));
pSourceColorSpace = pIcmInfo->pSourceColorSpace;
}
else
{
//
// Otherwise, just use Stcok color space (= sRGB)
//
hSourceColorSpace = GetStockObject(PRIV_STOCK_COLORSPACE);
pSourceColorSpace = NULL;
}
}
else
{
//
// Can't handle here, let callee handle it.
//
return (FALSE);
}
//
// Get bitmap size
//
cjBits = cjBitmapScanSize(pbmi,nNumScan);
pvBits = LOCALALLOC(cjBits);
if (pvBits)
{
//
// Fix up the start scan (bottom-left).
//
nStartScan = (pbmi->bmiHeader.biHeight - nStartScan - nNumScan);
//
// Call NtGdiGetDIBitsInternal directly, because
// we don't want to backward color correction to
// source color space in hdcSrc.
//
if (NtGdiGetDIBitsInternal(
hdcSrc,hbm,
nStartScan,nNumScan,
pvBits,pbmi,
DIB_RGB_COLORS,
cjBits,0) == 0)
{
WARNING("IcmStretchBlt(): Failed on GetDIBits()\n");
LOCALFREE(pvBits);
pvBits = NULL;
}
//
// Fix up the bitmap height, since pvBits only has nNumScan image.
//
pbmi->bmiHeader.biHeight = nNumScan;
}
if (pvBits)
{
if (hSourceColorSpace)
{
hOldColorSpace = IcmSetSourceColorSpace(hdc,hSourceColorSpace,pSourceColorSpace,0);
}
//
// Draw the bitmap.
//
// Target - x,y (upper left).
// Source - nStartWidth,0 (upper left).
//
if (bNoScaling && (rop == SRCCOPY))
{
iRet = SetDIBitsToDevice(hdc,x,y,cx,cy,nStartWidth,0,0,nNumScan,
pvBits,pbmi,DIB_RGB_COLORS);
}
else
{
iRet = StretchDIBits(hdc,x,y,cx,cy,nStartWidth,0,nNumWidth,nNumScan,
pvBits,pbmi,DIB_RGB_COLORS,rop);
}
//
// Back to original color space, if created
//
if (hOldColorSpace)
{
IcmSetSourceColorSpace(hdc,hOldColorSpace,NULL,0);
}
LOCALFREE(pvBits);
}
if (hSourceColorSpace)
{
DeleteColorSpace(hSourceColorSpace);
}
return (BOOL) !!iRet;
}
/******************************Public*Routine******************************\
* IcmGetColorSpaceforBitmap()
*
* History:
*
* Write it:
* 29-May-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
PCACHED_COLORSPACE
IcmGetColorSpaceforBitmap(HBITMAP hbm)
{
ICMAPI(("gdi32: IcmGetColorSpaceforBitmap\n"));
FIXUP_HANDLE(hbm);
return ((PCACHED_COLORSPACE)NtGdiGetColorSpaceforBitmap(hbm));
}
/******************************Public*Routine******************************\
* IcmEnableForCompatibleDC()
*
* History:
*
* Write it:
* 13-Jun-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmEnableForCompatibleDC(
HDC hdcCompatible,
HDC hdcDevice,
PDC_ATTR pdcaDevice
)
{
PDC_ATTR pdcaCompatible;
ICMAPI(("gdi32: IcmEnableForCompatibleDC\n"));
PSHARED_GET_VALIDATE(pdcaCompatible,hdcCompatible,DC_TYPE);
if (pdcaCompatible)
{
PGDI_ICMINFO pIcmInfoCompatible;
PGDI_ICMINFO pIcmInfoDevice;
// Initialize ICMINFO
//
// for device DC, ICMINFO should be presented.
//
if ((pIcmInfoDevice = GET_ICMINFO(pdcaDevice)) == NULL)
{
WARNING("gdi32: IcmEnableForCompatibleDC: Can't init icm info\n");
return (FALSE);
}
//
// for compatible DC, it was just created, ICMINFO is not exist, then create here.
//
if ((pIcmInfoCompatible = INIT_ICMINFO(hdcCompatible,pdcaCompatible)) == NULL)
{
WARNING("gdi32: IcmEnableForCompatibleDC: Can't init icm info\n");
return (FALSE);
}
//
// Set Source color space as same as original DC
//
// Kernel side...
//
if (pdcaDevice->hColorSpace)
{
if (pdcaDevice->hColorSpace != GetStockObject(PRIV_STOCK_COLORSPACE))
{
//
// Call directly kernel to set the color space to DC. (don't need client stuff)
//
NtGdiSetColorSpace(hdcCompatible,(HCOLORSPACE)pdcaDevice->hColorSpace);
}
//
// Keep it in ICMINFO, so that we can un-select it later.
//
pIcmInfoCompatible->hDefaultSrcColorSpace = pdcaDevice->hColorSpace;
}
// And client side...
//
ENTERCRITICALSECTION(&semColorSpaceCache);
if (pIcmInfoDevice->pSourceColorSpace)
{
pIcmInfoCompatible->pSourceColorSpace = pIcmInfoDevice->pSourceColorSpace;
pIcmInfoCompatible->pSourceColorSpace->cRef++;
}
//
// Set destination color space as same as original DC
//
if (pIcmInfoDevice->pDestColorSpace)
{
pIcmInfoCompatible->pDestColorSpace = pIcmInfoDevice->pDestColorSpace;
pIcmInfoCompatible->pDestColorSpace->cRef++;
}
LEAVECRITICALSECTION(&semColorSpaceCache);
//
// copy default profile name (if they has)
//
if (pIcmInfoDevice->DefaultDstProfile[0] != UNICODE_NULL)
{
wcscpy(pIcmInfoCompatible->DefaultDstProfile,pIcmInfoDevice->DefaultDstProfile);
pIcmInfoCompatible->flInfo |= (ICM_VALID_DEFAULT_PROFILE|
ICM_VALID_CURRENT_PROFILE);
}
//
// Make sure we have valid color space.
//
pdcaCompatible->ulDirty_ &= ~DIRTY_COLORSPACE;
//
// And we don't have valid color transform.
//
pdcaCompatible->ulDirty_ |= DIRTY_COLORTRANSFORM;
if (IS_ICM_INSIDEDC(pdcaDevice->lIcmMode))
{
//
// For compatible DC, use host ICM anytime...
//
ULONG ReqIcmMode = REQ_ICM_HOST;
//
// Turn ICM on for this compatible DC.
//
if (!NtGdiSetIcmMode(hdcCompatible,ICM_SET_MODE,ReqIcmMode))
{
//
// something wrong... we are fail to enable ICM.
//
return (FALSE);
}
//
// Update color transform.
//
if (!IcmUpdateDCColorInfo(hdcCompatible,pdcaCompatible))
{
//
// Fail to create new transform
//
NtGdiSetIcmMode(hdcCompatible,ICM_SET_MODE,REQ_ICM_OFF);
return (FALSE);
}
}
}
return (TRUE);
}
/******************************Public*Routine******************************\
* IcmAskDriverForColorProfile
*
* History:
* 08-Oct-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
int
IcmAskDriverForColorProfile(
PLDC pldc,
ULONG ulQueryMode,
PDEVMODEW pDevMode,
PWSTR pProfileName,
DWORD *pdwColorSpaceFlag
)
{
INT iRet;
BYTE TempProfileData[MAX_PATH];
PVOID pvProfileData = (PVOID) TempProfileData;
ULONG cjProfileSize = sizeof(TempProfileData);
FLONG flProfileFlag = 0;
ICMAPI(("gdi32: IcmAskDriverForColorProfile\n"));
//
// Call driver to get device profile data.
//
iRet = QueryColorProfileEx(pldc,
pDevMode,
ulQueryMode,
pvProfileData,
&cjProfileSize,
&flProfileFlag);
if (iRet == -1)
{
ICMMSG(("gdi32: IcmAskDriverForColorProfile():Driver does not hook color profile\n"));
//
// Driver does not support profile hook.
//
return iRet;
}
else if ((iRet == 0) &&
(cjProfileSize > sizeof(TempProfileData)) &&
(GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{
ICMMSG(("gdi32: IcmAskDriverForColorProfile():Allocate larger memory\n"));
//
// Buffer is not enough, so allocate it.
//
pvProfileData = LOCALALLOC(cjProfileSize);
if (pvProfileData)
{
iRet = QueryColorProfileEx(pldc,
pDevMode,
ulQueryMode,
pvProfileData,
&cjProfileSize,
&flProfileFlag);
}
}
if ((iRet > 0) && (pvProfileData != NULL) && (cjProfileSize != 0))
{
if (flProfileFlag == QCP_PROFILEDISK)
{
ICMMSG(("gdi32: IcmAskDriverForColorProfile():Profiles - %ws\n",pvProfileData));
//
// pvProfileData contains filename in Unicode.
//
wcsncpy(pProfileName,(PWSTR)pvProfileData,MAX_PATH);
}
else if (flProfileFlag == QCP_PROFILEMEMORY)
{
//
// pvProfileData contains color profile itself.
//
//
// No desired name.
//
*pProfileName = UNICODE_NULL;
//
// Create temporary color profile.
//
if (IcmCreateTemporaryColorProfile(pProfileName,pvProfileData,cjProfileSize))
{
ICMMSG(("gdi32: IcmAskDriverForColorProfile():Profiles - %ws\n",pProfileName));
//
// Mark this as temporary file, so that when this is not used
// the file will be deleted.
//
*pdwColorSpaceFlag = (DRIVER_COLORSPACE | NEED_TO_DEL_PROFILE);
}
else
{
ICMMSG(("gdi32: IcmAskDriverForColorProfile():Failed to create temp file\n"));
//
// failed to create temporary color profile.
//
iRet = 0;
}
}
else
{
//
// Unknown data type.
//
iRet = 0;
}
}
else
{
iRet = 0;
}
if (pvProfileData && (pvProfileData != TempProfileData))
{
LOCALFREE(pvProfileData);
}
return (iRet);
}
/******************************Public*Routine******************************\
* GdiConvertBitmapV5
*
* pbBitmapData - pointer to BITMAPV4/V5 data
* iSizeOfBitmapData - size of buffer
* uConvertFormat - either of CF_DIB or CF_BITMAP
*
* History:
* 12-Dec-1997 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
HANDLE GdiConvertBitmapV5(
LPBYTE pbBitmapData,
int iSizeOfBitmapData,
HPALETTE hPalette,
UINT uConvertFormat
)
{
HANDLE hRet = NULL;
UNREFERENCED_PARAMETER(hPalette);
ICMAPI(("gdi32: GdiConvertBitmapV5\n"));
if (pbBitmapData && iSizeOfBitmapData)
{
BITMAPINFO *pbmi = (BITMAPINFO *)pbBitmapData;
BITMAPINFOHEADER *pbmih = &(pbmi->bmiHeader);
PVOID pvBits = NULL;
ULONG ulColorTableSize = (ULONG)-1;
BOOL bTransColorTable = FALSE;
BOOL bMoveColorMasks = FALSE;
//
// Load external ICM dlls.
//
LOAD_ICMDLL(NULL);
//
// Find the bitmap bits pointer.
//
try
{
//
// Calculate color table size.
//
if (pbmih->biCompression == BI_BITFIELDS)
{
//
// Bitfields are a part of BITMAPV4/V5 header.
//
ulColorTableSize = 0;
bMoveColorMasks = TRUE;
}
else if (pbmih->biCompression == BI_RGB)
{
if (pbmih->biClrUsed)
{
ulColorTableSize = (pbmih->biClrUsed * sizeof(RGBQUAD));
if (pbmih->biBitCount <= 8)
{
bTransColorTable = TRUE;
}
}
else if (pbmih->biBitCount <= 8)
{
ulColorTableSize = ((1 << pbmih->biBitCount) * sizeof(RGBQUAD));
bTransColorTable = TRUE;
}
else
{
ulColorTableSize = 0;
}
}
else if (pbmih->biCompression == BI_RLE4)
{
ulColorTableSize = 16 * sizeof(RGBQUAD);
bTransColorTable = TRUE;
}
else if (pbmih->biCompression == BI_RLE8)
{
ulColorTableSize = 256 * sizeof(RGBQUAD);
bTransColorTable = TRUE;
}
else
{
//
// BI_JPEG, BI_PNG, and others can not convert
//
ICMWRN(("GdiConvertBitmapV5: "
"given data is BI_JPEG, BI_PNG, or unkown\n"));
}
if (ulColorTableSize != (ULONG)-1)
{
//
// Make sure given data is either BITMAPV4 or V5 header.
//
if (pbmih->biSize == sizeof(BITMAPV5HEADER))
{
pvBits = (BYTE *)pbmi
+ sizeof(BITMAPV5HEADER)
+ ulColorTableSize
+ ((LPBITMAPV5HEADER)pbmi)->bV5ProfileSize;
}
else if (pbmih->biSize != sizeof(BITMAPV4HEADER))
{
pvBits = (BYTE *)pbmi
+ sizeof(BITMAPV4HEADER)
+ ulColorTableSize;
}
else
{
ICMWRN(("GdiConvertBitmapV5: given data is not bitmapV4/V5\n"));
}
}
}
except(EXCEPTION_EXECUTE_HANDLER)
{
pvBits = NULL;
}
if (pvBits)
{
if (uConvertFormat == CF_DIB)
{
ULONG cjBitmapBits;
ICMMSG(("GdiConvertBitmapV5(): CF_DIBV5 -----> CF_DIB\n"));
//
// Calculate size of bitmap bits
//
try
{
cjBitmapBits = cjBitmapBitsSize(pbmi);
}
except(EXCEPTION_EXECUTE_HANDLER)
{
cjBitmapBits = 0;
}
if (cjBitmapBits)
{
//
// Allocate buffer for color translation
//
hRet = GlobalAlloc(GHND,sizeof(BITMAPINFOHEADER)
+ (bMoveColorMasks ? (3 * sizeof(DWORD)) : \
(ulColorTableSize))
+ cjBitmapBits);
if (hRet)
{
PBYTE pjSrc = (PBYTE)pbmi;
PBYTE pjDest = GlobalLock(hRet);
BOOL bTransformError = FALSE;
if (pjDest)
{
PROFILE sRGBColorProfileData;
LOGCOLORSPACEW LogColorSpaceW;
PROFILE ColorProfile;
DWORD dwFlags = 0;
HANDLE hColorTransform = NULL;
HANDLE hsRGBColorProfile = NULL;
HANDLE hBitmapColorProfile = NULL;
PCACHED_COLORSPACE pColorSpace = NULL;
try
{
//
// Extract color space from BITMAPV4/V5 header.
//
bTransformError = !(IcmGetBitmapColorSpace(
pbmi,
&LogColorSpaceW,
&ColorProfile,
&dwFlags));
}
except(EXCEPTION_EXECUTE_HANDLER)
{
bTransformError = TRUE;
}
if (!bTransformError)
{
//
// Create color space and color transform
//
if ((LogColorSpaceW.lcsCSType == LCS_sRGB) ||
(LogColorSpaceW.lcsCSType == LCS_WINDOWS_COLOR_SPACE))
{
ICMMSG(("GdiConvertBitmapV5(): Original bitmap is sRGB\n"));
//
// No color translarion required.
//
hColorTransform = NULL;
}
else
{
//
// Get source color space (if bitmap has color space)
//
//
// First, find ColorSpace from cache.
//
pColorSpace = IcmGetColorSpaceByColorSpace(
(HGDIOBJ)NULL,
&LogColorSpaceW,
&ColorProfile,
dwFlags);
if (pColorSpace == NULL)
{
pColorSpace = IcmCreateColorSpaceByColorSpace(
(HGDIOBJ)NULL,
&LogColorSpaceW,
&ColorProfile,
dwFlags);
}
if (pColorSpace && IcmRealizeColorProfile(pColorSpace,TRUE))
{
hBitmapColorProfile = pColorSpace->hProfile;
}
//
// Open sRGB color space profile as destination color space.
//
sRGBColorProfileData.dwType = PROFILE_FILENAME;
sRGBColorProfileData.pProfileData = (PVOID)sRGB_PROFILENAME;
sRGBColorProfileData.cbDataSize = MAX_PATH * sizeof(WCHAR);
hsRGBColorProfile = (*fpOpenColorProfileW)(
&sRGBColorProfileData,
PROFILE_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
OPEN_EXISTING);
if (hBitmapColorProfile && hsRGBColorProfile)
{
DWORD ahIntents[2];
HPROFILE ahProfiles[2];
ahIntents[0] = INTENT_RELATIVE_COLORIMETRIC;
ahIntents[1] = pColorSpace->ColorIntent;
ahProfiles[0] = hBitmapColorProfile;
ahProfiles[1] = hsRGBColorProfile;
hColorTransform = (*fpCreateMultiProfileTransform)(
ahProfiles, 2,
ahIntents, 2,
NORMAL_MODE | ENABLE_GAMUT_CHECKING,
INDEX_DONT_CARE);
}
if (!hColorTransform)
{
bTransformError = TRUE;
}
}
if (!bTransformError)
{
//
// Copy the bitmap to target with proper color space conversion.
//
try
{
BITMAPV5HEADER *pbm5h = (BITMAPV5HEADER *)pbmi;
//
// Copy bitmap header to target.
//
RtlCopyMemory(pjDest,pjSrc,sizeof(BITMAPINFOHEADER));
//
// Adjust bmHeader.biSize
//
((BITMAPINFOHEADER *)pjDest)->biSize = sizeof(BITMAPINFOHEADER);
//
// Move src and dest pointers
//
pjSrc += pbmih->biSize;
pjDest += sizeof(BITMAPINFOHEADER);
//
// Copy bit mask or color table.
//
if (bMoveColorMasks)
{
//
// Move color masks. cast it to pointer to BITMAPV5HEADER
// since same offset on BITMAPV4HEADER too.
//
*(DWORD *)pjDest = pbm5h->bV5RedMask;
pjDest += sizeof(DWORD);
*(DWORD *)pjDest = pbm5h->bV5GreenMask;
pjDest += sizeof(DWORD);
*(DWORD *)pjDest = pbm5h->bV5BlueMask;
pjDest += sizeof(DWORD);
}
else
{
if (ulColorTableSize)
{
if (bTransColorTable && hColorTransform)
{
bTransformError = !(*fpTranslateBitmapBits)(
hColorTransform,
pjSrc, BM_xRGBQUADS,
ulColorTableSize/sizeof(RGBQUAD), 1,
0,
pjDest, BM_xRGBQUADS,
0,NULL,0);
}
else
{
RtlCopyMemory(pjDest,pjSrc,ulColorTableSize);
}
pjSrc += ulColorTableSize;
pjDest += ulColorTableSize;
}
}
if (bTransColorTable || (hColorTransform == NULL))
{
//
// All the color information is in the color table. and
// it has been translated, so just copy bitmap bits.
//
RtlCopyMemory(pjDest,pvBits,cjBitmapBits);
}
else
{
//
// Translate bitmap bits.
//
BMFORMAT bmColorType;
//
// Get BMFORMAT based on bitmap format.
//
if (pbmih->biBitCount == 16)
{
if (pbmih->biCompression == BI_RGB)
{
bmColorType = BM_x555RGB;
}
else if (pbmih->biCompression == BI_BITFIELDS)
{
if ((pbm5h->bV5RedMask == 0x007c00) &&
(pbm5h->bV5GreenMask == 0x0003e0) &&
(pbm5h->bV5BlueMask == 0x00001f))
{
bmColorType = BM_x555RGB;
}
else if ((pbm5h->bV5RedMask == 0x00f800) &&
(pbm5h->bV5GreenMask == 0x0007e0) &&
(pbm5h->bV5BlueMask == 0x00001f))
{
bmColorType = BM_565RGB;
}
else
{
ICMWRN(("GdiConvertBitmapV5: Bad Bitfields Mask for 16 bpp\n"));
bTransformError = TRUE;
}
}
else
{
ICMWRN(("GdiConvertBitmapV5: Bad biCompression for 16 bpp\n"));
bTransformError = TRUE;
}
}
else if (pbmih->biBitCount == 24)
{
bmColorType = BM_RGBTRIPLETS;
}
else if (pbmih->biBitCount == 32)
{
if (pbmih->biCompression == BI_RGB)
{
bmColorType = BM_xRGBQUADS;
}
else if (pbmih->biCompression == BI_BITFIELDS)
{
if ((pbm5h->bV5RedMask == 0x0000ff) && /* Red */
(pbm5h->bV5GreenMask == 0x00ff00) && /* Green */
(pbm5h->bV5BlueMask == 0xff0000)) /* Blue */
{
bmColorType = BM_xBGRQUADS;
}
else if ((pbm5h->bV5RedMask == 0xff0000) && /* Red */
(pbm5h->bV5GreenMask == 0x00ff00) && /* Green */
(pbm5h->bV5BlueMask == 0x0000ff)) /* Blue */
{
bmColorType = BM_xRGBQUADS;
}
else
{
ICMWRN(("GdiConvertBitmapV5: Bad Bitfields Mask for 32 bpp\n"));
bTransformError = TRUE;
}
}
else
{
ICMWRN(("GdiConvertBitmapV5: Bad biCompression for 32 bpp\n"));
bTransformError = TRUE;
}
}
else
{
ICMWRN(("GdiConvertBitmapV5: Bad biBitCount\n"));
bTransformError = TRUE;
}
if (!bTransformError)
{
bTransformError = !(*fpTranslateBitmapBits)(
hColorTransform,
pvBits, bmColorType,
pbmih->biWidth,
ABS(pbmih->biHeight),
0,
pjDest, bmColorType,
0,NULL,0);
}
}
}
except(EXCEPTION_EXECUTE_HANDLER)
{
bTransformError = TRUE;
}
}
//
// Clean up used color transform and color profile handles
//
if (hColorTransform)
{
(*fpDeleteColorTransform)(hColorTransform);
}
if (hsRGBColorProfile)
{
(*fpCloseColorProfile)(hsRGBColorProfile);
}
if (pColorSpace)
{
IcmReleaseColorSpace(NULL,pColorSpace,FALSE);
}
}
}
GlobalUnlock(hRet);
if (bTransformError)
{
GlobalFree(hRet);
hRet = NULL;
}
}
else
{
ICMWRN(("GdiConvertBitmapV5: Fail on GlobalAlloc()\n"));
}
}
else
{
ICMWRN(("GdiConvertBitmapV5: cjBitmapBits is 0\n"));
}
return (hRet);
}
else if (uConvertFormat == CF_BITMAP)
{
HDC hDC = GetDC(NULL);
HBITMAP hBitmap = NULL;
if (hDC)
{
ICMMSG(("GdiConvertBitmapV5(): CF_DIBV5 -----> CF_BITMAP\n"));
//
// Set destination color space as sRGB, and enable ICM.
//
if (IcmSetDestinationColorSpace(hDC,sRGB_PROFILENAME,NULL,0) &&
SetICMMode(hDC,ICM_ON))
{
try
{
//
// Create bitmap handle with given bitmap V5 data.
//
hBitmap = CreateDIBitmap(hDC,
pbmih,
CBM_INIT,
pvBits,
pbmi,
DIB_RGB_COLORS);
}
except(EXCEPTION_EXECUTE_HANDLER)
{
hBitmap = NULL;
}
if (!hBitmap)
{
ICMWRN(("GdiConvertBitmapV5: Fail on CreateDIBitmap()\n"));
}
}
//
// Clean up DC
//
SetICMMode(hDC,ICM_OFF);
ReleaseDC(NULL,hDC);
}
return ((HANDLE)hBitmap);
}
else
{
ICMWRN(("GdiConvertBitmapV5(): CF_DIBV5 -----> Unknown\n"));
}
}
}
return (hRet);
}
/******************************Public*Routine******************************\
* IcmSetTargetColorSpace()
*
* History:
* 8-Jun-1998 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmSetTargetColorSpace(
HDC hdc,
PCACHED_COLORSPACE pTargetColorSpace,
DWORD uiAction
)
{
BOOL bRet = FALSE;
PDC_ATTR pdcattr;
PGDI_ICMINFO pIcmInfo;
ICMAPI(("gdi32: IcmSetTargetColorSpace\n"));
FIXUP_HANDLE(hdc);
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (pdcattr == NULL)
{
return (FALSE);
}
if ((pIcmInfo = GET_ICMINFO(pdcattr)) == NULL)
{
return (FALSE);
}
switch (uiAction)
{
case CS_ENABLE:
{
//
// Check validation of given Target color space.
//
if (pTargetColorSpace != NULL)
{
PCACHED_COLORTRANSFORM pCXform;
BOOL bDeleteOldCXform = FALSE;
//
// Mark we are in proofing mode.
//
SET_ICM_PROOFING(pdcattr->lIcmMode);
if ((pIcmInfo->pProofCXform != NULL) &&
IcmSameColorSpace(pTargetColorSpace,pIcmInfo->pTargetColorSpace))
{
ICMMSG(("IcmSetTargetColorSpace():Use Cached Proof Transform\n"));
ENTERCRITICALSECTION(&semColorTransformCache);
//
// the cached proofing transform is still valid.
//
pCXform = pIcmInfo->pProofCXform;
if (pCXform)
{
//
// Increment ref count of it.
//
pCXform->cRef++;
}
LEAVECRITICALSECTION(&semColorTransformCache);
}
else
{
ICMMSG(("IcmSetTargetColorSpace():Create New Proof Transform\n"));
//
// We don't have cached color space or it is no longer valid.
//
//
// Check we still have cached color space and it's still valid ?
//
if (pIcmInfo->pTargetColorSpace &&
IcmSameColorSpace(pTargetColorSpace,pIcmInfo->pTargetColorSpace))
{
//
// Cached target color space are still valid, keep as is.
//
}
else
{
//
// Release old target color space.
//
IcmReleaseColorSpace(NULL,pIcmInfo->pTargetColorSpace,FALSE);
//
// Increment ref count of it.
//
IcmReferenceColorSpace(pTargetColorSpace);
//
// set target destination profile into current DC as target profile
//
pIcmInfo->pTargetColorSpace = pTargetColorSpace;
}
//
// create new transform
//
pCXform = IcmCreateColorTransform(hdc,pdcattr,NULL,ICM_FORWARD);
//
// Marks as need to delete old color transform if we have.
//
bDeleteOldCXform = pIcmInfo->pProofCXform ? TRUE : FALSE;
}
if ((pCXform == IDENT_COLORTRANSFORM) || (pCXform == NULL))
{
//
// Invalidate color transform
//
IcmSelectColorTransform(hdc,pdcattr,NULL,
bDeviceCalibrate(pIcmInfo->pDestColorSpace));
//
// Delete old color transform.
//
if (bDeleteOldCXform)
{
//
// Delete cached proofing color transform
//
IcmDeleteColorTransform(pIcmInfo->pProofCXform,FALSE);
}
//
// Set null color transform to ICMINFO
//
pIcmInfo->pProofCXform = NULL;
if (pCXform == IDENT_COLORTRANSFORM)
{
ICMMSG(("IcmSetTargetColorSpace():Input & Output colorspace is same\n"));
//
// Input & Destination & Target color space is same, there is
// no color translation needed.
//
bRet = TRUE;
}
else
{
ICMWRN(("IcmSetTargetColorSpace():Fail to create color transform\n"));
}
//
// Translate back to DC color object to original
//
IcmTranslateColorObjects(hdc,pdcattr,FALSE);
}
else
{
//
// Select the color transform to DC.
//
IcmSelectColorTransform(hdc,pdcattr,pCXform,
bDeviceCalibrate(pCXform->DestinationColorSpace));
//
// Delete old color transform.
//
if (bDeleteOldCXform)
{
//
// Delete cached proofing color transform
//
IcmDeleteColorTransform(pIcmInfo->pProofCXform,FALSE);
}
//
// Set new color transform to ICMINFO.
//
pIcmInfo->pProofCXform = pCXform;
//
// Initialize color attributes in this DC.
//
IcmTranslateColorObjects(hdc,pdcattr,TRUE);
bRet = TRUE;
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
WARNING("IcmSetTargetColorSpace: target color space is NULL\n");
//
// Anyway, just re-initialize without target profile.
//
IcmTranslateColorObjects(hdc,pdcattr,TRUE);
}
if (!bRet)
{
//
// if failed, mask off as we are not in proofing mode
//
CLEAR_ICM_PROOFING(pdcattr->lIcmMode);
if (pIcmInfo->pTargetColorSpace)
{
//
// Release target color space.
//
IcmReleaseColorSpace(NULL,pIcmInfo->pTargetColorSpace,FALSE);
//
// Disable target profile.
//
pIcmInfo->pTargetColorSpace = NULL;
}
}
break;
}
case CS_DISABLE:
case CS_DELETE_TRANSFORM:
{
//
// We are going to be out of proofing mode.
//
CLEAR_ICM_PROOFING(pdcattr->lIcmMode);
if (pdcattr->ulDirty_ & DIRTY_COLORTRANSFORM)
{
if (uiAction == CS_DELETE_TRANSFORM)
{
if (pIcmInfo->pTargetColorSpace)
{
//
// Release target color space.
//
IcmReleaseColorSpace(NULL,pIcmInfo->pTargetColorSpace,FALSE);
//
// Disable target profile.
//
pIcmInfo->pTargetColorSpace = NULL;
}
}
//
// While DC is in proofing mode, the source or
// destination color space has been changed by
// SetColorSpace() or SetICMProfile(). So,
// we will reset all color transform in this
// DC.
//
if (IcmUpdateDCColorInfo(hdc,pdcattr))
{
bRet = TRUE;
}
else
{
GdiSetLastError(ERROR_DELETING_ICM_XFORM);
}
}
else
{
//
// We are leaving proofing mode, Select back the normal colortransform into DC.
//
IcmSelectColorTransform(hdc,pdcattr,pIcmInfo->pCXform,
bDeviceCalibrate(pIcmInfo->pDestColorSpace));
//
// The color transform cache will effective...
//
if (uiAction == CS_DELETE_TRANSFORM)
{
if (pIcmInfo->pTargetColorSpace)
{
//
// Release target color space.
//
IcmReleaseColorSpace(NULL,pIcmInfo->pTargetColorSpace,FALSE);
//
// Disable target profile.
//
pIcmInfo->pTargetColorSpace = NULL;
}
//
// Delete ONLY proofing color transform (if it is)
//
if (pIcmInfo->pProofCXform)
{
if (!IcmDeleteColorTransform(pIcmInfo->pProofCXform,FALSE))
{
GdiSetLastError(ERROR_DELETING_ICM_XFORM);
return (FALSE);
}
//
// There is no proofing transform in this ICMINFO.
//
pIcmInfo->pProofCXform = NULL;
}
}
bRet = TRUE;
}
if (bRet)
{
//
// Initialize color attributes in this DC.
//
IcmTranslateColorObjects(hdc,pdcattr,TRUE);
}
break;
}
default:
{
WARNING("IcmSetTargetColorSpace: uiAction is invalid\n");
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
}
return (bRet);
}
/******************************Public*Routine******************************\
* IcmSetDestinationColorSpace()
*
* History:
* 17-Jul-1998 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmSetDestinationColorSpace(
HDC hdc,
LPWSTR pwszFileName,
PCACHED_COLORSPACE pColorSpace,
DWORD dwFlags
)
{
BOOL bRet = FALSE;
PDC_ATTR pdcattr;
ULONG FileNameSize;
if (pColorSpace)
{
ICMAPI(("gdi32: IcmSetDestinationColorSpace by ColorSpace (%ws):dwFlags - %d\n",
pColorSpace->LogColorSpace.lcsFilename,dwFlags));
}
else if (pwszFileName)
{
ICMAPI(("gdi32: IcmSetDestinationColorSpace by profile name (%ws):dwFlags - %x\n",
pwszFileName,dwFlags));
//
// Check filename
//
if (pwszFileName)
{
FileNameSize = lstrlenW(pwszFileName);
}
if ((FileNameSize == 0) || (FileNameSize > MAX_PATH))
{
ICMWRN(("IcmSetDestinatonColorSpace - no or too long profile name\n"));
return FALSE;
}
}
else
{
ICMAPI(("gdi32: IcmSetDestinationColorSpace - invalid parameter\n"));
return FALSE;
}
FIXUP_HANDLE(hdc);
//
// We are going to try to select this color space into thisDC,
// default is false.
//
bRet = FALSE;
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
//
// Profile filename or pColorSpace should be presented.
//
if (pdcattr)
{
PGDI_ICMINFO pIcmInfo;
//
// Initialize ICMINFO
//
if ((pIcmInfo = INIT_ICMINFO(hdc,pdcattr)) == NULL)
{
WARNING("gdi32: IcmSetDestinationColorSpace: Can't init icm info\n");
return(FALSE);
}
if (IsColorDeviceContext(hdc))
{
PCACHED_COLORSPACE pNewColorSpace = NULL;
//
// Load external ICM dlls.
//
LOAD_ICMDLL(FALSE);
if (pColorSpace == NULL)
{
//
// Find colorspace from cache
//
pNewColorSpace = IcmGetColorSpaceByName(
(HGDIOBJ)hdc,
pwszFileName,
pIcmInfo->dwDefaultIntent,
dwFlags);
if (pNewColorSpace == NULL)
{
ICMMSG(("IcmSetDestinationColorSpace():This is new color space, create it\n"));
//
// Can not find, Create new one
//
pNewColorSpace = IcmCreateColorSpaceByName(
(HGDIOBJ)hdc,
pwszFileName,
pIcmInfo->dwDefaultIntent,
dwFlags);
}
}
else
{
//
// Increment ref count of given color space
//
IcmReferenceColorSpace(pColorSpace);
//
// Use pColorSpace from parameter.
//
pNewColorSpace = pColorSpace;
}
//
// We are going to select this colorspace onto DC. and free previous profile.
//
if (pNewColorSpace)
{
PCACHED_COLORSPACE pOldColorSpace = pIcmInfo->pDestColorSpace;
//
// Is this same destination color space currently selected in DC ?
//
if (IcmSameColorSpace(pNewColorSpace,pIcmInfo->pDestColorSpace))
{
//
// Yes, early-out. We don't need new color space.
//
IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE);
return (TRUE);
}
//
// Before change destination color space, we need to flush batched gdi functions.
//
CHECK_AND_FLUSH(hdc,pdcattr);
//
// Check new color format is accepted by this DC or not.
//
if (!NtGdiSetIcmMode(hdc,ICM_CHECK_COLOR_MODE,pNewColorSpace->ColorFormat))
{
ICMWRN(("IcmSetDestinationColorSpace(): DC does not accept this color format\n"));
GdiSetLastError(ERROR_INVALID_PROFILE);
}
else
{
//
// Set new color space into DC.
//
pIcmInfo->pDestColorSpace = pNewColorSpace;
//
// Remove dirty transform flag.
//
pdcattr->ulDirty_ &= ~DIRTY_COLORSPACE;
if (IS_ICM_INSIDEDC(pdcattr->lIcmMode) && !IS_ICM_PROOFING(pdcattr->lIcmMode))
{
PCACHED_COLORTRANSFORM pCXform;
//
// create new color transform base on new colorspace
//
pCXform = IcmCreateColorTransform(hdc,pdcattr,NULL,ICM_FORWARD);
if (pCXform == IDENT_COLORTRANSFORM)
{
//
// Select null color transform to DC.
//
IcmSelectColorTransform(hdc,pdcattr,NULL,
bDeviceCalibrate(pIcmInfo->pDestColorSpace));
//
// delete old color transform in DC.
//
IcmDeleteDCColorTransforms(pIcmInfo);
//
// Select null color transform to ICMINFO.
//
pIcmInfo->pCXform = NULL;
//
// back it to original color (non-ICMed color).
//
IcmTranslateColorObjects(hdc,pdcattr,FALSE);
//
// And, everything O.K.
//
bRet = TRUE;
}
else if (pCXform)
{
//
// Select the colortransform into DC.
//
if (IcmSelectColorTransform(
hdc,pdcattr,pCXform,
bDeviceCalibrate(pCXform->DestinationColorSpace)))
{
//
// delete old color transform in DC.
//
IcmDeleteDCColorTransforms(pIcmInfo);
//
// Select it to ICMINFO.
//
pIcmInfo->pCXform = pCXform;
//
// Adjust to new color transform.
//
IcmTranslateColorObjects(hdc,pdcattr,TRUE);
//
// And, everything O.K.
//
bRet = TRUE;
}
else
{
//
// Failed to select it to the DC in client side.
// so delete it and invalidate pCXform.
//
IcmDeleteColorTransform(pCXform,FALSE);
pCXform = NULL;
}
}
if (pCXform == NULL)
{
//
// Failed to create/select color stransform,
// so put back previous color space.
//
pIcmInfo->pDestColorSpace = pOldColorSpace;
}
}
else
{
//
// if ICM is not turned on currently, we just mark
// cached color transform is no longer valid.
//
pdcattr->ulDirty_ |= DIRTY_COLORTRANSFORM;
// For ColorMatchToTarget()
//
// While color matching to the target is enabled by setting
// uiAction to CS_ENABLE, application changes to the color
// space or gamut matching method are ignored.
// Those changes then take effect when color matching to
// the target is disabled.
//
if (IS_ICM_PROOFING(pdcattr->lIcmMode))
{
ICMMSG(("IcmSetDestinationColorSpace():In Proofing mode, lazy setting...\n"));
}
bRet = TRUE;
}
}
if (bRet)
{
//
// We are succeeded to select new color space, then
// close and free references to old color space.
//
IcmReleaseColorSpace(NULL,pOldColorSpace,FALSE);
}
else
{
//
// We will not use this color space as destination color space,
// because 1) DC does not accept this color space, 2) Fail to
// create color transform based on this color space.
//
IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE);
}
}
else
{
GdiSetLastError(ERROR_PROFILE_NOT_FOUND);
}
}
else
{
ICMMSG(("IcmSetDestinationColorSpace(): for Mono-device\n"));
//
// Just copy Apps specifyed profile to internal buffer, which will
// be return to app by GetICMProfile(), but it is NEVER used for
// non-color device other than that case, since there is no ICM
// happen.
//
wcsncpy(pIcmInfo->DefaultDstProfile,pwszFileName,MAX_PATH);
//
// This is not default profile, but current profile.
//
pIcmInfo->flInfo &= ~ICM_VALID_DEFAULT_PROFILE;
pIcmInfo->flInfo |= ICM_VALID_CURRENT_PROFILE;
}
}
else
{
GdiSetLastError(ERROR_INVALID_PARAMETER);
}
return(bRet);
}
/******************************Public*Routine******************************\
* IcmSetSourceColorSpace()
*
* History:
* 17-Jul-1998 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
HCOLORSPACE
IcmSetSourceColorSpace(
HDC hdc,
HCOLORSPACE hColorSpace,
PCACHED_COLORSPACE pColorSpace,
DWORD dwFlags)
{
HANDLE hRet = NULL;
PDC_ATTR pdcattr;
ICMAPI(("gdi32: IcmSetSourceColorSpace\n"));
FIXUP_HANDLE(hdc);
FIXUP_HANDLE(hColorSpace);
//
// validate and access hdc
//
PSHARED_GET_VALIDATE(pdcattr,hdc,DC_TYPE);
if (pdcattr)
{
PGDI_ICMINFO pIcmInfo;
//
// Initialize ICMINFO
//
if ((pIcmInfo = INIT_ICMINFO(hdc,pdcattr)) == NULL)
{
WARNING("gdi32: IcmSetSourceColorSpace: Can't init icm info\n");
return(NULL);
}
if (pdcattr->hColorSpace != hColorSpace)
{
//
// Before change source color space, we need to flush batched gdi functions.
//
CHECK_AND_FLUSH(hdc,pdcattr);
//
// Return Old (currently selected) color space handle.
//
hRet = pdcattr->hColorSpace;
//
// set new color space, call kernel to keep reference count tracking
// of colospace object
//
if (NtGdiSetColorSpace(hdc,hColorSpace))
{
if (IsColorDeviceContext(hdc))
{
PCACHED_COLORSPACE pNewColorSpace;
LOGCOLORSPACEW LogColorSpaceW;
RtlZeroMemory(&LogColorSpaceW,sizeof(LOGCOLORSPACEW));
//
// Load external ICM dlls.
//
LOAD_ICMDLL(NULL);
if (pColorSpace == NULL)
{
//
// Check if there is client-cached colorspace for this or not.
//
pNewColorSpace = IcmGetColorSpaceByHandle(
(HGDIOBJ)hdc,
hColorSpace,
&LogColorSpaceW,dwFlags);
//
// If we can not find from cache, but succeeded to obtain
// valid logcolorspace from handle, create new one.
//
if ((pNewColorSpace == NULL) &&
(LogColorSpaceW.lcsSignature == LCS_SIGNATURE))
{
//
// Create new one.
//
pNewColorSpace = IcmCreateColorSpaceByColorSpace(
(HGDIOBJ)hdc,
&LogColorSpaceW,
NULL,
dwFlags);
}
}
else
{
//
// Increment ref count of given color space
//
IcmReferenceColorSpace(pColorSpace);
//
// Use pColorSpace from parameter.
//
pNewColorSpace = pColorSpace;
}
//
// Update current source color space to new one.
//
if (pNewColorSpace)
{
PCACHED_COLORSPACE pOldColorSpace = pIcmInfo->pSourceColorSpace;
//
// Check the colorspace is same one as currently selected ?
//
if (IcmSameColorSpace(pNewColorSpace,pIcmInfo->pSourceColorSpace))
{
//
// This is the "actually" same color space, but differrent handle,
// don't need to update
//
IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE);
return (hRet);
}
//
// Source color space should be RGB color space.
//
if (pNewColorSpace->ColorFormat != BM_xBGRQUADS)
{
ICMWRN(("IcmSetSourceColorSpace():Source color space is not RGB\n"));
//
// Set back previous color space. (can't fail these calls)
//
IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE);
NtGdiSetColorSpace(hdc,hRet);
GdiSetLastError(ERROR_INVALID_COLORSPACE);
return (NULL);
}
//
// And set new color space.
//
pIcmInfo->pSourceColorSpace = pNewColorSpace;
//
// if ICM is enabled, needs update color transform, right now.
//
if (IS_ICM_INSIDEDC(pdcattr->lIcmMode) && !IS_ICM_PROOFING(pdcattr->lIcmMode))
{
PCACHED_COLORTRANSFORM pCXform;
//
// create new color transform
//
pCXform = IcmCreateColorTransform(hdc,pdcattr,NULL,ICM_FORWARD);
if (pCXform == IDENT_COLORTRANSFORM)
{
ICMMSG(("IcmSetSourceColorSpace():Input & Output colorspace is same\n"));
//
// select NULL transform into DC.
//
IcmSelectColorTransform(hdc,pdcattr,NULL,
bDeviceCalibrate(pIcmInfo->pDestColorSpace));
//
// delete old colorspace/transform from ICMINFO.
//
IcmDeleteDCColorTransforms(pIcmInfo);
//
// select NULL tranform to ICMINFO.
//
pIcmInfo->pCXform = NULL;
//
// Set DC objects color to non-ICMed color.
//
IcmTranslateColorObjects(hdc,pdcattr,FALSE);
}
else if (pCXform)
{
//
// Select the color transform to DC.
//
if (IcmSelectColorTransform(
hdc,pdcattr,pCXform,
bDeviceCalibrate(pCXform->DestinationColorSpace)))
{
//
// delete old colorspace/transform from ICMINFO.
//
IcmDeleteDCColorTransforms(pIcmInfo);
//
// select new color transform to ICMINFO.
//
pIcmInfo->pCXform = pCXform;
//
// Succeed to select into DC, Validate DC color objects
//
IcmTranslateColorObjects(hdc,pdcattr,TRUE);
}
else
{
//
// Failed to select it to the DC in client side.
// so delete it and invalidate pCXform.
//
IcmDeleteColorTransform(pCXform,FALSE);
pCXform = NULL;
}
}
if (pCXform == NULL)
{
ICMMSG(("IcmSetSourceColorSpace():Fail to create/select color transform\n"));
//
// Set back previous color space. (can't fail these calls)
//
pIcmInfo->pSourceColorSpace = pOldColorSpace;
NtGdiSetColorSpace(hdc,hRet);
hRet = NULL;
}
}
else
{
//
// Otherwise, we just mark color transform might be dirty.
// Because new color space was selected.
//
pdcattr->ulDirty_ |= DIRTY_COLORTRANSFORM;
// For ColorMatchToTarget()
//
// While color matching to the target is enabled by setting
// uiAction to CS_ENABLE, application changes to the color
// space or gamut matching method are ignored.
// Those changes then take effect when color matching to
// the target is disabled.
//
if (IS_ICM_PROOFING(pdcattr->lIcmMode))
{
ICMMSG(("IcmSetSourceColorSpace():In Proofing mode, lazy setting...\n"));
}
}
if (hRet)
{
//
// Succeed to select new color space, then delete old one.
//
IcmReleaseColorSpace(NULL,pOldColorSpace,FALSE);
}
else
{
IcmReleaseColorSpace(NULL,pNewColorSpace,FALSE);
}
}
}
else
{
ICMMSG(("IcmSetSourceColorSpace(): for Mono-device\n"));
//
// For monochrome device case, just return kernel color space
// handle, then just don't create client-side representitive,
// since there is no ICM for monochrome device.
//
}
}
else
{
WARNING("Error: hdc and hColorSpace check out but NtGdi call failed\n");
hRet = NULL;
}
}
else
{
//
// Same color space was selected, just return current.
//
hRet = hColorSpace;
}
}
if (hRet == NULL)
{
GdiSetLastError(ERROR_INVALID_COLORSPACE);
}
return (hRet);
}
/******************************Public*Routine******************************\
* IcmSaveDC()
*
* History:
* 7-Dec-1998 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
BOOL
IcmSaveDC(
HDC hdc,
PDC_ATTR pdcattr,
PGDI_ICMINFO pIcmInfo)
{
BOOL bRet = TRUE;
ICMAPI(("gdi32: IcmSaveDC\n"));
if (pdcattr && pIcmInfo)
{
//
// Get currect saved level.
//
DWORD dwCurrentSavedDepth;
if (NtGdiGetDCDword(hdc,DDW_SAVEDEPTH,&dwCurrentSavedDepth))
{
PSAVED_ICMINFO pSavedIcmInfo = LOCALALLOC(sizeof(SAVED_ICMINFO));
if (pSavedIcmInfo)
{
PCACHED_COLORSPACE pSourceColorSpace = pIcmInfo->pSourceColorSpace;
PCACHED_COLORSPACE pDestColorSpace = pIcmInfo->pDestColorSpace;
PCACHED_COLORSPACE pTargetColorSpace = pIcmInfo->pTargetColorSpace;
PCACHED_COLORTRANSFORM pCXform = pIcmInfo->pCXform;
PCACHED_COLORTRANSFORM pBackCXform = pIcmInfo->pBackCXform;
PCACHED_COLORTRANSFORM pProofCXform = pIcmInfo->pProofCXform;
//
// Increment reference count of color spaces in DC.
//
IcmReferenceColorSpace(pSourceColorSpace);
IcmReferenceColorSpace(pDestColorSpace);
IcmReferenceColorSpace(pTargetColorSpace);
//
// Increment reference count of color transform in DC.
//
IcmReferenceColorTransform(pCXform);
IcmReferenceColorTransform(pBackCXform);
IcmReferenceColorTransform(pProofCXform);
//
// Save color spaces.
//
pSavedIcmInfo->pSourceColorSpace = pSourceColorSpace;
pSavedIcmInfo->pDestColorSpace = pDestColorSpace;
pSavedIcmInfo->pTargetColorSpace = pTargetColorSpace;
//
// Save color transforms.
//
pSavedIcmInfo->pCXform = pCXform;
pSavedIcmInfo->pBackCXform = pBackCXform;
pSavedIcmInfo->pProofCXform = pProofCXform;
//
// Put current saved level in DC.
//
pSavedIcmInfo->dwSavedDepth = dwCurrentSavedDepth;
//
// Insert saved data to list.
//
InsertHeadList(&(pIcmInfo->SavedIcmInfo),&(pSavedIcmInfo->ListEntry));
ICMMSG(("gdi32: IcmSaveDC() - Saved Depth = %d\n",dwCurrentSavedDepth));
}
else
{
WARNING("IcmSaveDC():Failed on LOCALALLOC()\n");
bRet = FALSE;
}
}
else
{
WARNING("IcmSaveDC():Failed on NtGdiGetDCDword(DDW_SAVEDEPTH)\n");
bRet = FALSE;
}
}
return (bRet);
}
/******************************Public*Routine******************************\
* IcmRestoreDC()
*
* History:
* 7-Dec-1998 -by- Hideyuki Nagase [hideyukn]
\**************************************************************************/
VOID
IcmRestoreDC(
PDC_ATTR pdcattr,
int iLevel,
PGDI_ICMINFO pIcmInfo)
{
ICMAPI(("gdi32: IcmRestoreDC - iLevel = %d\n",iLevel));
if (pIcmInfo)
{
//
// Still have same ICMINFO.
//
PLIST_ENTRY p = pIcmInfo->SavedIcmInfo.Flink;
BOOL bContinue = TRUE;
while (bContinue &&
(iLevel != 0) &&
(p != &(pIcmInfo->SavedIcmInfo)))
{
PSAVED_ICMINFO pSavedIcmInfo = CONTAINING_RECORD(p,SAVED_ICMINFO,ListEntry);
if (iLevel > 0)
{
//
// iLevel is absolute saved depth to restore
//
if (iLevel == (int) pSavedIcmInfo->dwSavedDepth)
{
bContinue = FALSE;
}
}
else
{
//
// iLevel is relative saved depth to restore
//
if (++iLevel == 0)
{
bContinue = FALSE;
}
}
if (bContinue == FALSE)
{
PCACHED_COLORSPACE pSourceColorSpace = pIcmInfo->pSourceColorSpace;
PCACHED_COLORSPACE pDestColorSpace = pIcmInfo->pDestColorSpace;
PCACHED_COLORSPACE pTargetColorSpace = pIcmInfo->pTargetColorSpace;
PCACHED_COLORTRANSFORM pCXform = pIcmInfo->pCXform;
PCACHED_COLORTRANSFORM pBackCXform = pIcmInfo->pBackCXform;
PCACHED_COLORTRANSFORM pProofCXform = pIcmInfo->pProofCXform;
//
// Restore this saved data to DC.
//
pIcmInfo->pSourceColorSpace = pSavedIcmInfo->pSourceColorSpace;
pIcmInfo->pDestColorSpace = pSavedIcmInfo->pDestColorSpace;
pIcmInfo->pTargetColorSpace = pSavedIcmInfo->pTargetColorSpace;
pIcmInfo->pCXform = pSavedIcmInfo->pCXform;
pIcmInfo->pBackCXform = pSavedIcmInfo->pBackCXform;
pIcmInfo->pProofCXform = pSavedIcmInfo->pProofCXform;
//
// Release color space which *WAS* selected in DC.
//
IcmReleaseColorSpace(NULL,pSourceColorSpace,FALSE);
IcmReleaseColorSpace(NULL,pDestColorSpace,FALSE);
IcmReleaseColorSpace(NULL,pTargetColorSpace,FALSE);
//
// Delete color transform which *WAS* selected in DC.
//
IcmDeleteColorTransform(pCXform,FALSE);
IcmDeleteColorTransform(pBackCXform,FALSE);
IcmDeleteColorTransform(pProofCXform,FALSE);
if (pdcattr)
{
//
// Validate flags.
//
pdcattr->ulDirty_ &= ~(DIRTY_COLORSPACE | DIRTY_COLORTRANSFORM);
}
}
else
{
//
// Decrement ref count of color space.
//
IcmReleaseColorSpace(NULL,pSavedIcmInfo->pSourceColorSpace,FALSE);
IcmReleaseColorSpace(NULL,pSavedIcmInfo->pDestColorSpace,FALSE);
IcmReleaseColorSpace(NULL,pSavedIcmInfo->pTargetColorSpace,FALSE);
//
// Decrement ref count of color transform.
//
IcmDeleteColorTransform(pSavedIcmInfo->pCXform,FALSE);
IcmDeleteColorTransform(pSavedIcmInfo->pBackCXform,FALSE);
IcmDeleteColorTransform(pSavedIcmInfo->pProofCXform,FALSE);
}
//
// Get pointer to next.
//
p = p->Flink;
//
// Remove from list.
//
RemoveEntryList(&(pSavedIcmInfo->ListEntry));
//
// Free SAVED_ICMINFO.
//
LOCALFREE(pSavedIcmInfo);
}
}
}