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.
733 lines
22 KiB
733 lines
22 KiB
/*******************************Module*Header*******************************\
|
|
* Module Name:
|
|
*
|
|
* icmobj.cxx
|
|
*
|
|
* Abstract
|
|
*
|
|
* This module contains object support for COLORTRANSFORM objects and ICM
|
|
* Objects
|
|
*
|
|
* Author:
|
|
*
|
|
* Feb.23.1997 -by- Hideyuki Nagase [hideyukn]
|
|
*
|
|
* Copyright (c) 1997-1999 Microsoft Corporation
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.hxx"
|
|
|
|
/******************************Public*Routine******************************\
|
|
* COLORTRANSFORMOBJ::hCreate()
|
|
*
|
|
* History:
|
|
*
|
|
* Write it:
|
|
* 23-Feb-1997 -by- Hideyuki Nagase [hideyukn]
|
|
\**************************************************************************/
|
|
|
|
HANDLE
|
|
COLORTRANSFORMOBJ::hCreate(
|
|
XDCOBJ& dco,
|
|
LOGCOLORSPACEW *pLogColorSpaceW,
|
|
PVOID pvSource,
|
|
ULONG cjSource,
|
|
PVOID pvDestination,
|
|
ULONG cjDestination,
|
|
PVOID pvTarget,
|
|
ULONG cjTarget
|
|
)
|
|
{
|
|
HANDLE hObject = NULL;
|
|
|
|
PCOLORTRANSFORM pNewCXform = NULL;
|
|
|
|
ICMAPI(("COLORTRANSFORM::hCreate()\n"));
|
|
|
|
HDEV hdev = dco.hdev();
|
|
|
|
//
|
|
// This object should not have any existing realization.
|
|
//
|
|
ASSERTGDI(_pColorTransform == NULL,"COLORTRANSFORMOBJ::hCreate() object is exist\n");
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
if (po.bValid())
|
|
{
|
|
//
|
|
// Allocate ColorTransform object.
|
|
//
|
|
pNewCXform = (PCOLORTRANSFORM) ALLOCOBJ(sizeof(COLORTRANSFORM),ICMCXF_TYPE, FALSE);
|
|
|
|
if (pNewCXform)
|
|
{
|
|
//
|
|
// Register COLORTRANSFORM handle.
|
|
//
|
|
hObject = (HCOLORSPACE)HmgInsertObject(
|
|
pNewCXform,
|
|
HMGR_ALLOC_ALT_LOCK,
|
|
ICMCXF_TYPE);
|
|
|
|
if (hObject)
|
|
{
|
|
HANDLE hDeviceColorTransform = NULL;
|
|
|
|
//
|
|
// Set new object to this COLORTRANSFORMNOBJ
|
|
//
|
|
_pColorTransform = pNewCXform;
|
|
|
|
//
|
|
// Lock device
|
|
//
|
|
DEVLOCKOBJ devLock(po);
|
|
|
|
//
|
|
// Create driver's transform.
|
|
//
|
|
if (PPFNVALID(po,IcmCreateColorTransform))
|
|
{
|
|
//
|
|
// Call device driver to obtain handle of device driver.
|
|
//
|
|
hDeviceColorTransform = (*PPFNDRV(po, IcmCreateColorTransform)) (
|
|
po.dhpdev(),
|
|
pLogColorSpaceW,
|
|
pvSource, cjSource,
|
|
pvDestination, cjDestination,
|
|
pvTarget, cjTarget,
|
|
0 /* dwReserved */);
|
|
}
|
|
else
|
|
{
|
|
WARNING("CreateColorTransform called on device that does not support call\n");
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (hDeviceColorTransform)
|
|
{
|
|
ICMMSG(("CreateColorTransform(): Succeed to get handle from driver\n"));
|
|
|
|
//
|
|
// Set the handle to COLORTRANSFORM object.
|
|
//
|
|
vSetDeviceColorTransform(hDeviceColorTransform);
|
|
|
|
//
|
|
// Insert this pColorTransform to this DC.
|
|
//
|
|
dco.bAddColorTransform(hObject);
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("CreateColorTransform(): Fail to get handle from driver\n"));
|
|
|
|
//
|
|
// Mark this object does not have driver's realization.
|
|
//
|
|
vSetDeviceColorTransform(NULL);
|
|
|
|
//
|
|
// We are fail to get driver's handle, delete this.
|
|
//
|
|
bDelete(dco);
|
|
|
|
//
|
|
// Invalidate hObject and pColorTransform.
|
|
// (these are deleted in above bDelete())
|
|
//
|
|
hObject = NULL;
|
|
pNewCXform = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SAVE_ERROR_CODE(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
if ((hObject == NULL) && (pNewCXform != NULL))
|
|
{
|
|
FREEOBJ(pNewCXform,ICMCXF_TYPE);
|
|
}
|
|
}
|
|
|
|
return (hObject);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* COLORTRANSFORMOBJ::bDelete()
|
|
*
|
|
* History:
|
|
*
|
|
* Write it:
|
|
* 23-Feb-1997 -by- Hideyuki Nagase [hideyukn]
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
COLORTRANSFORMOBJ::bDelete(XDCOBJ& dco,BOOL bProcessCleanup)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
PCOLORTRANSFORM pDeleteXCForm;
|
|
|
|
ICMAPI(("COLORTRANSFORM::bDelete()\n"));
|
|
|
|
if (bValid())
|
|
{
|
|
BOOL bCanBeRemoved;
|
|
|
|
//
|
|
// Get colortransform object handle.
|
|
//
|
|
HANDLE hObject = _pColorTransform->hColorTransform();
|
|
|
|
//
|
|
// Unlock it. (this was locked in constructor).
|
|
//
|
|
DEC_SHARE_REF_CNT(_pColorTransform);
|
|
|
|
//
|
|
// Remote from object table.
|
|
//
|
|
bCanBeRemoved = (BOOL)(ULONG_PTR)HmgRemoveObject((HOBJ)(hObject),0,0,TRUE,ICMCXF_TYPE);
|
|
|
|
if (bCanBeRemoved)
|
|
{
|
|
HANDLE hDeviceColorTransform;
|
|
|
|
//
|
|
// Yes, we can remove object from object table, try to delete driver's realization.
|
|
//
|
|
ICMMSG(("DeleteColorTransform(): Succeed to remove object from table\n"));
|
|
|
|
//
|
|
// Get device driver's handle.
|
|
//
|
|
hDeviceColorTransform = hGetDeviceColorTransform();
|
|
|
|
if (hDeviceColorTransform)
|
|
{
|
|
//
|
|
// Initialize PDEV object with owner.
|
|
//
|
|
PDEVOBJ po(dco.hdev());
|
|
|
|
if (po.bValid())
|
|
{
|
|
if (po.bUMPD() && bProcessCleanup)
|
|
{
|
|
ICMMSG(("DeleteColorTransform():Will not callout to user mode since UMPD.\n"));
|
|
|
|
//
|
|
// Overwrite driver transform as NULL.
|
|
//
|
|
vSetDeviceColorTransform(NULL);
|
|
}
|
|
else
|
|
{
|
|
DEVLOCKOBJ devLock(po);
|
|
|
|
//
|
|
// Delete driver's realization.
|
|
//
|
|
if (PPFNVALID(po,IcmDeleteColorTransform))
|
|
{
|
|
//
|
|
// Call device driver to free driver's handle
|
|
//
|
|
if ((*PPFNDRV(po, IcmDeleteColorTransform))(
|
|
po.dhpdev(),
|
|
hDeviceColorTransform))
|
|
{
|
|
ICMMSG(("DeleteColorTransform():Succeed to IcmDeleteColorTransform()\n"));
|
|
|
|
//
|
|
// This object does not have driver realization anymore.
|
|
//
|
|
vSetDeviceColorTransform(NULL);
|
|
}
|
|
else
|
|
{
|
|
WARNING("DeleteColorTransform():Fail to IcmDeleteColorTransform()\n");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
WARNING("DeleteColorTransform called on device that does not support call\n");
|
|
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("DeleteColorTransform(): There is no driver handle\n"));
|
|
}
|
|
|
|
//
|
|
// We could delete object allocation if there is no driver's realization.
|
|
//
|
|
if (hGetDeviceColorTransform() == NULL)
|
|
{
|
|
//
|
|
// Remove this pColorTransform from DC.
|
|
//
|
|
dco.bRemoveColorTransform(hObject);
|
|
|
|
//
|
|
// Free it.
|
|
//
|
|
FREEOBJ(_pColorTransform,ICMCXF_TYPE);
|
|
|
|
//
|
|
// Invalidate pointer.
|
|
//
|
|
_pColorTransform = NULL;
|
|
|
|
//
|
|
// Yes, everything fine!
|
|
//
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("DeleteColorTransform(): Fail to remove object from table\n"));
|
|
}
|
|
|
|
//
|
|
// If we could not remove this object from object table, or could not
|
|
// delete object (including driver's realization)
|
|
//
|
|
if ((!bCanBeRemoved) || (!bRet))
|
|
{
|
|
//
|
|
// can not delete now. somebody will using...
|
|
//
|
|
WARNING("COLORTRANSFORMOBJ::vDelete(): Fail to Delete object, lazy deletion may happen\n");
|
|
|
|
//
|
|
// Back reference counter (deconstuctor will decrement this).
|
|
//
|
|
INC_SHARE_REF_CNT(_pColorTransform);
|
|
|
|
//
|
|
// Anyway, we will delete later at cleanup.
|
|
//
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return (bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* XDCOBJ::bAddColorTransform()
|
|
*
|
|
* History:
|
|
*
|
|
* Write it:
|
|
* 27-Feb-1997 -by- Hideyuki Nagase [hideyukn]
|
|
\**************************************************************************/
|
|
|
|
BOOL XDCOBJ::bAddColorTransform(HANDLE hCXform)
|
|
{
|
|
CXFLIST *pCXFListThis;
|
|
|
|
//
|
|
// Allocate new cell of CXFLIST
|
|
//
|
|
pCXFListThis = (CXFLIST *) PALLOCMEM(sizeof(CXFLIST),'ddaG');
|
|
|
|
if (pCXFListThis)
|
|
{
|
|
//
|
|
// Fill up CXFLIST structure
|
|
//
|
|
pCXFListThis->hCXform = hCXform;
|
|
pCXFListThis->pNext = pdc->pCXFList;
|
|
|
|
//
|
|
// Insert this into top of list.
|
|
//
|
|
pdc->pCXFList = pCXFListThis;
|
|
|
|
return (TRUE);
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("XDCOBJ::bAddColorTransform() Failed\n"));
|
|
return (FALSE);
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* XDCOBJ::bRemoveColorTransform()
|
|
*
|
|
* History:
|
|
*
|
|
* Write it:
|
|
* 27-Feb-1997 -by- Hideyuki Nagase [hideyukn]
|
|
\**************************************************************************/
|
|
|
|
BOOL XDCOBJ::bRemoveColorTransform(HANDLE hCXform)
|
|
{
|
|
if (pdc->pCXFList)
|
|
{
|
|
PCXFLIST pPrev, pThis;
|
|
|
|
pPrev = pThis = pdc->pCXFList;
|
|
|
|
while (pThis)
|
|
{
|
|
if (pThis->hCXform == hCXform)
|
|
{
|
|
//
|
|
// This is the cell, we need to remove.
|
|
//
|
|
if (pPrev == pThis)
|
|
{
|
|
//
|
|
// We are going to remove first cell. then need to
|
|
// update root.
|
|
//
|
|
pdc->pCXFList = pThis->pNext;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Remove this from list.
|
|
//
|
|
pPrev->pNext = pThis->pNext;
|
|
}
|
|
|
|
//
|
|
// Invalidate root.
|
|
//
|
|
VFREEMEM(pThis);
|
|
|
|
return (TRUE);
|
|
}
|
|
|
|
//
|
|
// Move to next cell
|
|
//
|
|
pPrev = pThis;
|
|
pThis = pThis->pNext;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("bRemoveColorTransform():There is no colortransform()\n"));
|
|
}
|
|
|
|
return (FALSE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* XDCOBJ::vCleanupColorTransform()
|
|
*
|
|
* History:
|
|
*
|
|
* Write it:
|
|
* 27-Feb-1997 -by- Hideyuki Nagase [hideyukn]
|
|
\**************************************************************************/
|
|
|
|
VOID XDCOBJ::vCleanupColorTransform(BOOL bProcessCleanup)
|
|
{
|
|
if (pdc->pCXFList)
|
|
{
|
|
PCXFLIST pLast, pThis;
|
|
|
|
pThis = pdc->pCXFList;
|
|
|
|
while (pThis)
|
|
{
|
|
COLORTRANSFORMOBJ CXformObj(pThis->hCXform);
|
|
|
|
pLast = pThis;
|
|
|
|
if (CXformObj.bValid())
|
|
{
|
|
//
|
|
// Delete this color transform
|
|
//
|
|
if (CXformObj.bDelete(*this,bProcessCleanup))
|
|
{
|
|
ICMMSG(("vCleanupColorTransform():Delete colortransform in this DC\n"));
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("vCleanupColorTransform():Fail to delete colortransform in this DC\n"));
|
|
}
|
|
}
|
|
|
|
//
|
|
// we don't need to walk through the list, because above COLORTRANSFORMOBJ.bDelete()
|
|
// will re-chain this list, then we just pick up the cell on the top of list everytime.
|
|
//
|
|
pThis = pdc->pCXFList;
|
|
|
|
//
|
|
// But if still new pThis is eqaul to pLast, this means we might fail to
|
|
// delete object or un-chain list, then just un-chain this forcely.
|
|
//
|
|
if (pThis == pLast)
|
|
{
|
|
//
|
|
// Skip pThis.
|
|
//
|
|
pThis = pThis->pNext;
|
|
|
|
//
|
|
// Update root too,
|
|
//
|
|
pdc->pCXFList = pThis;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// ICMMSG(("vCleanupColorTransform():There is no color transform in this DC\n"));
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* XEPALOBJ::CorrectColors()
|
|
*
|
|
* History:
|
|
*
|
|
* Write it:
|
|
* 29-Apr-1997 -by- Hideyuki Nagase [hideyukn]
|
|
\**************************************************************************/
|
|
|
|
VOID XEPALOBJ::CorrectColors(PPALETTEENTRY ppalentry, ULONG cEntries)
|
|
{
|
|
ICMMSG(("XEPALOBJ::CorrectColors\n"));
|
|
|
|
PDEVOBJ po(hdevOwner());
|
|
|
|
if (po.bValid())
|
|
{
|
|
if (po.bHasGammaRampTable())
|
|
{
|
|
ICMMSG(("XEPALOBJ::CorrectColors(): Do Gamma Correction\n"));
|
|
ICMMSG(("XEPALOBJ::CorrectColors(): GammaRamp Owner HDEV = %x\n",po.hdev()));
|
|
|
|
PGAMMARAMP_ARRAY pGammaRampArray = (PGAMMARAMP_ARRAY)(po.pvGammaRampTable());
|
|
|
|
for (ULONG i = 0; i < cEntries; i++)
|
|
{
|
|
//
|
|
// Adjust colors based on GammaRamp table.
|
|
//
|
|
ppalentry->peRed = (pGammaRampArray->Red[ppalentry->peRed]) >> 8;
|
|
ppalentry->peGreen = (pGammaRampArray->Green[ppalentry->peGreen]) >> 8;
|
|
ppalentry->peBlue = (pGammaRampArray->Blue[ppalentry->peBlue]) >> 8;
|
|
|
|
//
|
|
// next palette entry
|
|
//
|
|
ppalentry++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("XEPALOBJ::CorrectColors(): PDEV does not have Gamma Table\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("XEPALOBJ::CorrectColors(): PDEV is invalid\n"));
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* UpdateGammaRampOnDevice()
|
|
*
|
|
* History:
|
|
*
|
|
* Write it:
|
|
* 29-Apr-1997 -by- Hideyuki Nagase [hideyukn]
|
|
\**************************************************************************/
|
|
|
|
BOOL UpdateGammaRampOnDevice(HDEV hdev,BOOL bForceUpdate)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
|
|
ICMMSG(("UpdateGammaRampOnDevice()\n"));
|
|
|
|
PDEVOBJ po(hdev);
|
|
|
|
if (po.bValid())
|
|
{
|
|
ICMMSG(("UpdateGammaRampOnDevice():Set GammaRamp to HDEV = %x\n",po.hdev()));
|
|
|
|
if ((po.iDitherFormat() == BMF_8BPP) ||
|
|
(po.iDitherFormat() == BMF_16BPP) ||
|
|
(po.iDitherFormat() == BMF_24BPP) ||
|
|
(po.iDitherFormat() == BMF_32BPP))
|
|
{
|
|
//
|
|
// Driver might provide the entry point.
|
|
//
|
|
if ((PPFNVALID(po, IcmSetDeviceGammaRamp)) &&
|
|
(po.flGraphicsCaps2() & GCAPS2_CHANGEGAMMARAMP))
|
|
{
|
|
//
|
|
// PDEV should have GammaRampTable
|
|
//
|
|
if (po.bHasGammaRampTable())
|
|
{
|
|
ICMMSG(("UpdateGammaRampOnDevice():Call SetDeviceGammaRamp()\n"));
|
|
|
|
//
|
|
// Call device driver to set new GammaRamp.
|
|
//
|
|
bRet = (*PPFNDRV(po, IcmSetDeviceGammaRamp))(po.dhpdev(),
|
|
IGRF_RGB_256WORDS,
|
|
po.pvGammaRampTable());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// if the drive does not support, we will simulate it only for 8bpp case.
|
|
//
|
|
if ((po.iDitherFormat() == BMF_8BPP) && (po.bIsPalManaged()))
|
|
{
|
|
ICMMSG(("UpdateGammaRampOnDevice(): Call SetPalette()\n"));
|
|
|
|
//
|
|
// Check:
|
|
// 1) Are we going to reset pallete forcely ? (ex. back to default GammaRamp)
|
|
// 2) Or, Adjust Palette based on GammaRamp in PDEV.
|
|
//
|
|
if (bForceUpdate || po.bHasGammaRampTable())
|
|
{
|
|
//
|
|
// Get palette on device surface.
|
|
//
|
|
XEPALOBJ palSurf(po.ppalSurf());
|
|
|
|
ASSERTGDI(palSurf.bIsIndexed(),"UpdateGammaRampOnDevice(): Palette is not indexed\n");
|
|
|
|
//
|
|
// Mark this palette need to Gamma correction
|
|
// (if this is not default GammaRamp, default GammaRamp case
|
|
// PDEV does not have table.)
|
|
//
|
|
palSurf.bNeedGammaCorrection(po.bHasGammaRampTable());
|
|
|
|
//
|
|
// And put owner of PDEV which has GammaRamp table.
|
|
// (if they already has some value in there, we will
|
|
// overwrite it, but actually it should be same or
|
|
// uninitialized.)
|
|
//
|
|
palSurf.hdevOwner(po.hdev());
|
|
|
|
ICMMSG(("UpdateGammaRampOnDevice():Set GammaRamp to HDEV = %x\n",po.hdev()));
|
|
|
|
//
|
|
// Update palettes based on new GammaRamp.
|
|
//
|
|
// (Color will be adjusted in PALOBJ_cGetColors())
|
|
//
|
|
GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL);
|
|
GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
|
|
{
|
|
SEMOBJ so(po.hsemPointer());
|
|
|
|
if (!po.bDisabled())
|
|
{
|
|
ASSERTGDI(PPFNVALID(po,SetPalette),"ERROR palette is not managed");
|
|
|
|
bRet = (*PPFNDRV(po, SetPalette))(po.dhpdev(),
|
|
(PALOBJ *) &palSurf,
|
|
0, 0, palSurf.cEntries());
|
|
}
|
|
}
|
|
GreExitMonitoredSection(po.ppdev, WD_DEVLOCK);
|
|
GreReleaseSemaphoreEx(po.hsemDevLock());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("UpdateGammaRampOnDevice():Driver doesn't have DrvSetDeviceGammaRamp()\n"));
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Can not set GammaRamp for 1/4 bpp surface
|
|
//
|
|
ICMMSG(("UpdateGammaRampOnDevice():GammaRamp does not support on 1/4 bpp\n"));
|
|
}
|
|
|
|
if (!bRet)
|
|
{
|
|
ICMMSG(("UpdateGammaRampOnDevice(): device driver returns error\n"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ICMMSG(("UpdateGammaRampOnDevice(): HDEV is invalid\n"));
|
|
}
|
|
|
|
return (bRet);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* GetColorManagementCaps()
|
|
*
|
|
* History:
|
|
*
|
|
* Write it:
|
|
* 24-Feb-1998 -by- Hideyuki Nagase [hideyukn]
|
|
\**************************************************************************/
|
|
|
|
ULONG GetColorManagementCaps(PDEVOBJ& po)
|
|
{
|
|
ULONG fl = CM_NONE;
|
|
|
|
PDEVINFO pDevInfo = po.pdevinfoNotDynamic();
|
|
|
|
//
|
|
// Check CM_GAMMA_RAMP - it will be enabled when
|
|
//
|
|
// 0) Only for display device.
|
|
// 1) DitherFormat is 8bpp. (GDI simulate regardless driver capabilities)
|
|
// 2) Driver can do it.
|
|
//
|
|
if (po.bDisplayPDEV())
|
|
{
|
|
if ((pDevInfo->iDitherFormat == BMF_8BPP) ||
|
|
(po.flGraphicsCaps2NotDynamic() & GCAPS2_CHANGEGAMMARAMP))
|
|
{
|
|
fl |= CM_GAMMA_RAMP;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check CM_CMYK_COLOR when driver can understand.
|
|
//
|
|
if (po.flGraphicsCapsNotDynamic() & GCAPS_CMYKCOLOR)
|
|
{
|
|
fl |= CM_CMYK_COLOR;
|
|
}
|
|
|
|
//
|
|
// Check CM_DEVICE_ICM when driver can do.
|
|
//
|
|
if (po.flGraphicsCapsNotDynamic() & GCAPS_ICM)
|
|
{
|
|
fl |= CM_DEVICE_ICM;
|
|
}
|
|
|
|
return fl;
|
|
}
|