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