/******************************Module*Header*******************************\ * Module Name: pixelapi.cxx * * This contains the functions that get/set individual pixels. * * Created: 25-Apr-1991 11:32:15 * Author: Patrick Haluptzok patrickh * * Copyright (c) 1990-1999 Microsoft Corporation \**************************************************************************/ #include "precomp.hxx" /******************************Public*Routine******************************\ * GreSetPixel * * API entry point for putting a single pixel on the screen. * * Returns: -1 if point not in clip rgn or for blt failure, * or the color put on the device surface for success. * * History: * Tue 17-May-1994 -by- Patrick Haluptzok [patrickh] * update for size/perf and bug fix. * * Thu 4-Mar-1992 -by- Kent Diamond [kentd] * Pass in Attribute cache. * * Thu 27-Feb-1992 -by- Patrick Haluptzok [patrickh] * Fix RGB return. * * Thu 05-Dec-1991 -by- Patrick Haluptzok [patrickh] * bug fix, optimize for size, add error code logging. * * Fri 16-Aug-1991 -by- Patrick Haluptzok [patrickh] * Bug fix, make it return -1 for blt failure, cleanup * * 20-Apr-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ DWORD APIENTRY NtGdiSetPixel(HDC hdcDst, int x, int y, COLORREF crColor) { PAL_ULONG palul; palul.ul = 0xFFFFFFFF; XDCOBJ dcoDst(hdcDst); if (dcoDst.bValid()) { // // Transform the coordinates to device space. // EPOINTL eptlDst(x,y); EXFORMOBJ xoDst(dcoDst, WORLD_TO_DEVICE); xoDst.bXform(eptlDst); ERECTL erclDst(eptlDst.x,eptlDst.y,eptlDst.x+1,eptlDst.y+1); // // Accumulate bounds. We can do this before knowing if the operation is // successful because bounds can be loose. // if (dcoDst.fjAccum()) dcoDst.vAccumulate(erclDst); // // Check surface is included in DC. // if (dcoDst.bHasSurface()) { // // Lock the device. // DEVLOCKOBJ dloTrg; if (dloTrg.bLock(dcoDst)) { SURFACE *pSurfDst = dcoDst.pSurface(); // // With a fixed DC origin we can change the destination to SCREEN coordinates. // erclDst += dcoDst.eptlOrigin(); // // Parameter validation to avoid sticky overflow errors. // Note the validation is performed after the transform. // Any point that starts out in the invalid FIX zone may // potentially be transformed into the valid range and // therefore should be plotted. // Any point that's had it's bottom right wrap will be also invalidated // by this check. // Use of BLTOFXOK is probably an overkill, but lower level code // could potentially do a FIX conversion. // if (!BLTOFXOK(erclDst.left) || !BLTOFXOK(erclDst.right) || !BLTOFXOK(erclDst.top) || !BLTOFXOK(erclDst.bottom)) { SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); // // XDCOBJ does not automagically clean up it's locks in // its destructor so we have do it explicitly here. // dcoDst.vUnlockFast(); return (DWORD)(GDI_ERROR); //fail } ECLIPOBJ *pco = NULL; // // This is a pretty knarly expression to save a return in here. // Basically pco can be NULL if the rect is completely in the // cached rect in the DC or if we set up a clip object that isn't empty. // if (((erclDst.left >= dcoDst.prclClip()->left) && (erclDst.right <= dcoDst.prclClip()->right) && (erclDst.top >= dcoDst.prclClip()->top) && (erclDst.bottom <= dcoDst.prclClip()->bottom)) || (pco = dcoDst.pco(), pco->vSetup(dcoDst.prgnEffRao(), erclDst,CLIP_NOFORCETRIV), !pco->erclExclude().bEmpty())) { // // Make a fake solid color brush for this guy. // XEPALOBJ palDst(pSurfDst->ppal()); XEPALOBJ palDstDC(dcoDst.ppal()); BBRUSHOBJ bo; BOOL bCMYKColor = dcoDst.pdc->bIsCMYKColor(); // // Initialize BRUSHOBJ on stack. // bo.pvRbrush = (PVOID) NULL; bo.flColorType = 0; // // if the in CMYK color mode, iSolidColor is CMYK color. // if (bCMYKColor) { bo.iSolidColor = crColor; bo.flColorType = (BR_CMYKCOLOR | BR_HOST_ICM); if (gbMultiMonMismatchColor) { bo.crRealized(crColor); bo.crDCPalColor(crColor); } } else { bo.iSolidColor = ulGetNearestIndexFromColorref(palDst, palDstDC, crColor); if (dcoDst.pdc->bIsSoftwareICM()) { bo.flColorType = BR_HOST_ICM; } else if (dcoDst.pdc->bIsDeviceICM()) { bo.flColorType = BR_DEVICE_ICM; } if (gbMultiMonMismatchColor) { bo.crRealized(crColor); bo.crDCPalColor(rgbFromColorref(palDst, palDstDC, crColor)); } } // // Set up the correct return value. // DEVEXCLUDEOBJ dxo(dcoDst,&erclDst,pco); INC_SURF_UNIQ(pSurfDst); ULONG rop4 = gaMix[dcoDst.pdc->jROP2() & 0x0F]; rop4 |= (rop4 << 8); if ((*(pSurfDst->pfnBitBlt())) ( pSurfDst->pSurfobj(), (SURFOBJ *) NULL, (SURFOBJ *) NULL, NULL, NULL, &erclDst, (POINTL *) NULL, (POINTL *) NULL, &bo, &dcoDst.pdc->ptlFillOrigin(), rop4 )) { if (bCMYKColor) { palul.ul = bo.iSolidColor; } else { palul.ul = ulIndexToRGB(palDst, palDstDC, bo.iSolidColor); } } } } } dcoDst.vUnlockFast(); } else { WARNING1("ERROR GreSetPixel called on invalid DC\n"); } return(palul.ul); } #if 0 /******************************Public*Routine******************************\ * EngGetPixel * * This facilitates GetPixel on DIBs. * * History: * 27-Apr-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ ULONG EngGetPixel( SURFACE *pSurfSrc, PPOINTL pptlSrc) { ULONG ulReturn; PBYTE pjBits; LONG lDelta; ASSERTGDI(pSurfSrc != (PDIBOBJ) NULL, "ERROR GDI EngCopyBits"); ASSERTGDI(pptlSrc != (PPOINTL) NULL, "ERROR GDI EngCopyBits"); ASSERTGDI(pSurfSrc->iType() == STYPE_BITMAP, "ERROR GDI EngCopyBits"); ASSERTGDI(pptlSrc->x < pSurfSrc->sizl().cx, "ERROR GDI EngCopyBits"); ASSERTGDI(pptlSrc->y < pSurfSrc->sizl().cy, "ERROR GDI EngCopyBits"); lDelta = pSurfSrc->lDelta(); pjBits = (PBYTE) pSurfSrc->pvScan0(); pjBits = pjBits + (lDelta * pptlSrc->y); // Synchronize with the device driver before touching the device surface. { PDEVOBJ po(pSurfSrc->hdev()); po.vSync(pSurfSrc,NULL,0); } switch(pSurfSrc->iFormat()) { case BMF_1BPP: // Get the correct byte. ulReturn = (ULONG) *(pjBits + (pptlSrc->x >> 3)); // Get the correct bit in the lowest bit. ulReturn = ulReturn >> (7 - (pptlSrc->x & 7)); // Mask off the top bits. ulReturn = ulReturn & 1; break; case BMF_4BPP: // Get the correct byte. ulReturn = (ULONG) *(pjBits + (pptlSrc->x >> 1)); if (pptlSrc->x & 1) ulReturn = ulReturn & 15; else ulReturn = ulReturn >> 4; ASSERTGDI(ulReturn < 16, "ERROR GDI EngCopyBits"); break; case BMF_8BPP: ulReturn = (ULONG) *(pjBits + pptlSrc->x); break; case BMF_16BPP: ulReturn = (ULONG) *((PUSHORT) (pjBits + (pptlSrc->x << 1))); break; case BMF_24BPP: pjBits += (pptlSrc->x * 3); ulReturn = (ULONG) *(pjBits + 2); ulReturn <<= 8; ulReturn |= ((ULONG) *(pjBits + 1)); ulReturn <<= 8; ulReturn |= ((ULONG) *pjBits); break; case BMF_32BPP: ulReturn = *((PULONG) (pjBits + (pptlSrc->x << 2))); break; default: RIP("ERROR GDI EngCopyBits1"); } return(ulReturn); } #endif /******************************Public*Routine******************************\ * GreGetPixel * * API entry point for getting a single pixel on the screen. * * Returns: -1 if point not in clip rgn or for blt failure, * the RGB color put on the device surface for success. * * History: * Tue 17-May-1994 -by- Patrick Haluptzok [patrickh] * update for size/perf and bug fix. * * Thu 27-Feb-1992 -by- Patrick Haluptzok [patrickh] * Fix RGB return, remove unnecesary work. * * 22-Apr-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ DWORD NtGdiGetPixel(HDC hdc, int x, int y) { // // Lock the destination and its transform. // DWORD iSolidColor = 0xFFFFFFFF; XDCOBJ dcoSrc(hdc); if (dcoSrc.bValid()) { // // Lock the Rao region if we are drawing on a display surface. The Rao // region might otherwise change asynchronously. The DEVLOCKOBJ also makes // sure that the VisRgn is up to date, calling the window manager if // necessary to recompute it. It also protects us from pSurfSrc // being changed asynchronously by a dynamic mode change. // DEVLOCKOBJ dlo; if (dlo.bLock(dcoSrc)) { // // Check we can really do a GetPixel on this device. // SURFACE *pSurfSrc = dcoSrc.pSurface(); if ((pSurfSrc != NULL) && (pSurfSrc->bReadable() || UserScreenAccessCheck())) { EXFORMOBJ xoSrc(dcoSrc, WORLD_TO_DEVICE); // // Transform the coordinates to device space. // EPOINTL eptlSrc(x,y); xoSrc.bXform(eptlSrc); ERECTL erclSrc(eptlSrc.x,eptlSrc.y,eptlSrc.x+1,eptlSrc.y+1); // // Shift to Sreen Coordinates // erclSrc += dcoSrc.eptlOrigin(); // // Parameter validation not necessary here. It seems // that if the +1 above wraps, the initialization of the // clip obj will catch it in this case. // // // Compute the clipping complexity and maybe reduce the exclusion rectangle. // ECLIPOBJ co(dcoSrc.prgnEffRao(), erclSrc); // // Check the destination which is reduced by clipping. // if (!co.erclExclude().bEmpty()) { // // Exclude the pointer. // DEVEXCLUDEOBJ dxo(dcoSrc,&erclSrc); // // Check target device color. // BOOL bCMYKColor = dcoSrc.pdc->bIsCMYKColor(); #if 0 if (pSurfSrc->iType() == STYPE_BITMAP) { // We have a special function to quick get it. iSolidColor = EngGetPixel( pSurfSrc, // Source surface. (POINTL *) &erclSrc // Source origin. ); if (!bCMYKColor) { iSolidColor = ulIndexToRGB(palSurf, palDC, iSolidColor); } } else #endif { iSolidColor = 0; // // Allocate up a temporary DIB. // DEVBITMAPINFO dbmi; dbmi.cxBitmap = 1; dbmi.cyBitmap = 1; dbmi.hpal = (HPALETTE) 0; dbmi.fl = BMF_TOPDOWN; RECTL rclDst; // // To make sure the color falls into the lower // bit/nibble/word, the destination rect is adjusted. // dbmi.iFormat = pSurfSrc->iFormat(); switch (dbmi.iFormat) { case BMF_1BPP: rclDst.left = 7; rclDst.right = 8; break; case BMF_4BPP: rclDst.left = 1; rclDst.right = 2; break; default: rclDst.left = 0; rclDst.right = 1; } SURFMEM SurfTempDIB; if (SurfTempDIB.bCreateDIB(&dbmi, &iSolidColor)) { rclDst.top = 0; rclDst.bottom = 1; PDEVOBJ pdo(pSurfSrc->hdev()); if ((*PPFNGET(pdo, CopyBits, pSurfSrc->flags())) (SurfTempDIB.pSurfobj(), pSurfSrc->pSurfobj(), (CLIPOBJ *) NULL, &xloIdent, &rclDst, (POINTL *) &erclSrc)) { if (!bCMYKColor) { XEPALOBJ palDC(dcoSrc.ppal()); XEPALOBJ palSurf(pSurfSrc->ppal()); iSolidColor = ulIndexToRGB(palSurf, palDC, iSolidColor); } } } } } } } dcoSrc.vUnlockFast(); } return(iSolidColor); }