|
|
/******************************Module*Header*******************************\
* Module Name: miscgdi.cxx * * Misc. GDI routines * * Created: 13-Aug-1990 by undead * * Copyright (c) 1989-1999 Microsoft Corporation \**************************************************************************/
#include "precomp.hxx"
//
// GCAPS2_SYNCFLUSH and GCAPS2_SYNCTIMER globals
//
LONG gcSynchronizeFlush = -1; LONG gcSynchronizeTimer = -1; UINT_PTR gidSynchronizeTimer;
//
// GCAPS2_SYNCTIMER timer interval, in milliseconds
//
#define SYNCTIMER_FREQUENCY 50
/******************************Public*Routine******************************\
* GreSaveScreenBits (hdev,iMode,iIdent,prcl) * * Passes the call to the device driver, or returns doing nothing. This * call is pretty fast, no locks are done. * * Fri 11-Sep-1992 -by- Patrick Haluptzok [patrickh] * Add cursor exclusion. * * Thu 27-Aug-1992 16:40:42 -by- Charles Whitmer [chuckwh] * Wrote it. \**************************************************************************/
ULONG_PTR GreSaveScreenBits(HDEV hdev,ULONG iMode,ULONG_PTR iIdent,RECTL *prcl) { ULONG_PTR ulReturn = 0; RECTL rcl = {0,0,0,0};
PDEVOBJ po(hdev);
GreAcquireSemaphoreEx(po.hsemDevLock(), SEMORDER_DEVLOCK, NULL); GreEnterMonitoredSection(po.ppdev, WD_DEVLOCK);
if (!po.bDisabled()) { PFN_DrvSaveScreenBits pfn = PPFNDRV(po,SaveScreenBits);
if (pfn != (PFN_DrvSaveScreenBits) NULL) { DEVEXCLUDEOBJ dxo;
if (iMode == SS_FREE) { // Make if a very small rectangle.
prcl = &rcl; }
ASSERTGDI(po.bDisplayPDEV(), "ERROR");
ulReturn = (*pfn)(po.pSurface()->pSurfobj(),iMode,iIdent,prcl); } } #if DBG
else { if (iMode == SS_FREE) WARNING("GreSaveScreenBits called to free memory in full screen - memory lost\n"); } #endif
GreExitMonitoredSection(po.ppdev, WD_DEVLOCK); GreReleaseSemaphoreEx(po.hsemDevLock());
return(ulReturn); }
/******************************Public*Routine******************************\
* GreValidateSurfaceHandle * * This allows USER to validate handles passed to it by the client side. * * Returns: TRUE if handle is valid and of the correct type, * FALSE otherwise. * * History: * 06-Sep-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
BOOL GreValidateServerHandle(HANDLE hobj, ULONG ulType) { return(HmgValidHandle((HOBJ)hobj, (OBJTYPE) ulType)); }
/******************************Public*Routine******************************\
* GreSetBrushOrg * * Set the application defined brush origin into the DC * * Returns: Old brush origin * * History: * 30-Oct-1990 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
BOOL GreSetBrushOrg( HDC hdc, int x, int y, LPPOINT ptl_) { DCOBJ dco(hdc); PPOINTL ptl = (PPOINTL)ptl_;
if (dco.bValid()) { if (ptl != NULL) *ptl = dco.pdc->ptlBrushOrigin();
//
// update DCATTR brush org
//
dco.pdc->pDCAttr->ptlBrushOrigin.x = x; dco.pdc->pDCAttr->ptlBrushOrigin.y = y;
//
// update km brush prg
//
dco.pdc->ptlBrushOrigin((LONG)x,(LONG)y); return(TRUE); } else { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); return(FALSE); } }
/******************************Public*Routine******************************\
* GreGetBrushOrg * * Returns: Old application brush origin * * History: * 30-Oct-1990 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
BOOL GreGetBrushOrg(HDC hdc,PPOINT ptl_) { DCOBJ dco(hdc); PPOINTL ptl = (PPOINTL)ptl_;
if (dco.bValid()) { *ptl = dco.pdc->ptlBrushOrigin(); return(TRUE); } else return(FALSE); }
/******************************Public*Routine******************************\
* vGetDeviceCaps() * * Common device capabilities routine. * \**************************************************************************/
VOID vGetDeviceCaps( PDEVOBJ& po, PDEVCAPS pDevCaps ) { GDIINFO* pGdiInfo;
pGdiInfo = po.GdiInfoNotDynamic(); // Use of this local removes pointer
// dereferences
pDevCaps->ulVersion = pGdiInfo->ulVersion; pDevCaps->ulTechnology = pGdiInfo->ulTechnology;
// Note that ul*Size fields are now in micrometers
pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize+500)/1000; pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize+500)/1000; pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize; pDevCaps->ulVertSize = pGdiInfo->ulVertSize; pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes; pDevCaps->ulVertRes = pGdiInfo->ulVertRes; pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel; if (pDevCaps->ulBitsPixel == 15) pDevCaps->ulBitsPixel = 16; // Some apps, such as PaintBrush or
// NetScape, break if we return 15bpp
pDevCaps->ulPlanes = pGdiInfo->cPlanes; pDevCaps->ulNumPens = (pGdiInfo->ulNumColors == (ULONG)-1) ? (ULONG)-1 : 5 * pGdiInfo->ulNumColors; pDevCaps->ulNumFonts = po.cFonts(); pDevCaps->ulNumColors = pGdiInfo->ulNumColors; pDevCaps->ulRasterCaps = pGdiInfo->flRaster; pDevCaps->ulShadeBlendCaps = pGdiInfo->flShadeBlend; pDevCaps->ulAspectX = pGdiInfo->ulAspectX; pDevCaps->ulAspectY = pGdiInfo->ulAspectY; pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY; pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX; pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY; pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg; pDevCaps->ulColorRes = pGdiInfo->ulDACRed + pGdiInfo->ulDACGreen + pGdiInfo->ulDACBlue; pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx; pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy; pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x; pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y;
pDevCaps->ulTextCaps = pGdiInfo->flTextCaps; pDevCaps->ulTextCaps |= (TC_OP_CHARACTER | TC_OP_STROKE | TC_CP_STROKE | TC_UA_ABLE | TC_SO_ABLE);
if (pGdiInfo->ulTechnology != DT_PLOTTER) pDevCaps->ulTextCaps |= TC_VA_ABLE;
pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh; pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes; pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes; pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment;
pDevCaps->ulColorManagementCaps = GetColorManagementCaps(po); }
/******************************Public*Routine******************************\
* NtGdiGetDeviceCapsAll() * * Get all the adjustable device caps for the dc. Allows us to cache this * information on the client side. * * History: * 09-Jan-1996 -by- Lingyun Wang [lingyunw] * Made it based on GreGetDeviceCapsAll from the old client\server code. \**************************************************************************/
BOOL APIENTRY NtGdiGetDeviceCapsAll( HDC hdc, PDEVCAPS pDevCaps ) { BOOL bRet = TRUE; DEVCAPS devCapsTmp;
// Lock the destination and its transform.
DCOBJ dco(hdc);
// return FALSE if it is a invalid DC
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); return(FALSE); }
// Lock down the pdev
PDEVOBJ po(dco.hdev());
ASSERTGDI(po.bValid(), "Invalid PDEV");
__try { ProbeForWrite(pDevCaps, sizeof(DEVCAPS), sizeof(BYTE));
vGetDeviceCaps(po, pDevCaps); } __except(EXCEPTION_EXECUTE_HANDLER) { WARNING ("try-except failed IN NtGdiGetDeviceCapsAll\n");
// SetLastError(GetExceptionCode());
bRet = FALSE; }
return(bRet); }
/******************************Public*Routine******************************\
* GreUpdateSharedDevCaps() * * Update the device caps in the shared memory * * History: * 09-Jan-1996 -by- Lingyun Wang [lingyunw] * Made it based on GreGetDeviceCapsAll from the old client\server code. \**************************************************************************/
BOOL GreUpdateSharedDevCaps( HDEV hdev ) { PDEVOBJ po(hdev); ASSERTGDI(po.bValid(), "Invalid HDEV");
vGetDeviceCaps(po, gpGdiDevCaps);
return(TRUE); }
/******************************Public*Routine******************************\
* GreGetDeviceCaps * * Returns: device driver specific information * * NOTE: This function MUST mirror NtGdiGetDeviceCapsAll and that in * client\dcquery.c! * * History: * 01-Mar-1992 -by- Donald Sidoroff [donalds] * Rewritten to corrected GDIINFO structure. * * 30-Oct-1990 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
int GreGetDeviceCaps(HDC hdc, int lIndex) { // Init return value
int iRet = 0;
// Lock the destination and its transform.
DCOBJ dco(hdc); if (dco.bValid()) { // Lock down the pdev
PDEVOBJ po(dco.hdev()); ASSERTGDI(po.bValid(), "Invalid PDEV");
// Note that dynamic mode changes may cause the GDIINFO data to change
// at any time (but not the actual 'pGdiInfo' pointer):
GDIINFO* pGdiInfo = po.GdiInfoNotDynamic();
switch (lIndex) { case DRIVERVERSION: // Version = 0100h for now
iRet = (pGdiInfo->ulVersion); break;
case TECHNOLOGY: // Device classification
iRet = (pGdiInfo->ulTechnology); break;
case HORZSIZE: // Horizontal size in millimeters
iRet = (pGdiInfo->ulHorzSize+500)/1000; break;
case VERTSIZE: // Vertical size in millimeters
iRet = (pGdiInfo->ulVertSize+500)/1000; break;
case HORZRES: // Horizontal width in pixels
iRet = (pGdiInfo->ulHorzRes); break;
case VERTRES: // Vertical height in pixels
iRet = (pGdiInfo->ulVertRes); break;
case BITSPIXEL: // Number of bits per pixel
iRet = (pGdiInfo->cBitsPixel); if (iRet == 15) iRet = 16; // Some apps, such as PaintBrush or
// NetScape, break if we return 15bpp
break;
case PLANES: // Number of planes
iRet = (pGdiInfo->cPlanes); break;
case NUMBRUSHES: // Number of brushes the device has
iRet = (-1); break;
case NUMPENS: // Number of pens the device has
iRet = (pGdiInfo->ulNumColors == (ULONG)-1) ? (ULONG)-1 : 5 * pGdiInfo->ulNumColors; break;
case NUMMARKERS: // Number of markers the device has
iRet = (0); break;
case NUMFONTS: // Number of fonts the device has
iRet = (po.cFonts()); break;
case NUMCOLORS: // Number of colors in color table
iRet = (pGdiInfo->ulNumColors); break;
case PDEVICESIZE: // Size required for the device descriptor
iRet = (0); break;
case CURVECAPS: // Curves capabilities
iRet = (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE | CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT); break;
case LINECAPS: // Line capabilities
iRet = (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE | LC_STYLED | LC_WIDESTYLED | LC_INTERIORS); break;
case POLYGONALCAPS: // Polygonal capabilities
iRet = (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_TRAPEZOID | PC_SCANLINE | PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS); break;
case TEXTCAPS: // Text capabilities
{
FLONG fl = pGdiInfo->flTextCaps;
// Engine will simulate vector fonts on raster devices.
if (pGdiInfo->ulTechnology != DT_PLOTTER) fl |= TC_VA_ABLE;
// Turn underlining, strikeout. Engine will do it for device if needed.
fl |= (TC_UA_ABLE | TC_SO_ABLE);
// Return flag.
iRet = fl; break; }
case CLIPCAPS: // Clipping capabilities
iRet = (CP_RECTANGLE); break;
case RASTERCAPS: // Bitblt capabilities
iRet = (pGdiInfo->flRaster); break;
case SHADEBLENDCAPS: // Shade and blend capabilities
iRet = (pGdiInfo->flShadeBlend); break;
case ASPECTX: // Length of X leg
iRet = (pGdiInfo->ulAspectX); break;
case ASPECTY: // Length of Y leg
iRet = (pGdiInfo->ulAspectY); break;
case ASPECTXY: // Length of hypotenuse
iRet = (pGdiInfo->ulAspectXY); break;
case LOGPIXELSX: // Logical pixels/inch in X
iRet = (pGdiInfo->ulLogPixelsX); break;
case LOGPIXELSY: // Logical pixels/inch in Y
iRet = (pGdiInfo->ulLogPixelsY); break;
case SIZEPALETTE: // # entries in physical palette
iRet = (pGdiInfo->ulNumPalReg); break;
case NUMRESERVED: // # reserved entries in palette
iRet = (20); break;
case COLORRES: iRet = (pGdiInfo->ulDACRed + pGdiInfo->ulDACGreen + pGdiInfo->ulDACBlue); break;
case PHYSICALWIDTH: // Physical Width in device units
iRet = (pGdiInfo->szlPhysSize.cx); break;
case PHYSICALHEIGHT: // Physical Height in device units
iRet = (pGdiInfo->szlPhysSize.cy); break;
case PHYSICALOFFSETX: // Physical Printable Area x margin
iRet = (pGdiInfo->ptlPhysOffset.x); break;
case PHYSICALOFFSETY: // Physical Printable Area y margin
iRet = (pGdiInfo->ptlPhysOffset.y); break;
case VREFRESH: // Vertical refresh rate of the device
iRet = (pGdiInfo->ulVRefresh); break;
//
// NOTE : temporarily disable this feature for the BETA.
// We will reenable when the engine does it.
//
case DESKTOPHORZRES: // Width of entire virtual desktop
iRet = (pGdiInfo->ulHorzRes); break;
case DESKTOPVERTRES: // Height of entire virtual desktop
iRet = (pGdiInfo->ulVertRes); break;
case BLTALIGNMENT: // Preferred blt alignment
iRet = (pGdiInfo->ulBltAlignment); break;
case HORZSIZEM: // Horizontal size in millimeters/1000
iRet = pGdiInfo->ulHorzSize; break;
case VERTSIZEM: // Vertical size in millimeters/1000
iRet = pGdiInfo->ulVertSize; break;
case CAPS1: // InternalCaps
iRet = (po.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) ? C1_MIRROR_DEVICE : 0; break;
case COLORMGMTCAPS: // Color management capabilities
iRet = GetColorManagementCaps(po);
default: iRet = 0; } }
return(iRet); }
/******************************Public*Routine******************************\
* BOOL GreDeleteObject(HOBJ) * * History: * Fri 13-Sep-1991 -by- Patrick Haluptzok [patrickh] * added DC deletion * * Tue 27-Nov-1990 -by- Patrick Haluptzok [patrickh] * added palette deletion, surface deletion, brush deletion. * * Wed 22-Aug-1990 Greg Veres [w-gregv] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreDeleteObject (HANDLE hobj) { int ii;
// don't allow deletion of stock objects, just succeed
if (HmgStockObj(hobj)) { return(TRUE); }
switch (HmgObjtype(hobj)) { case RGN_TYPE: return(bDeleteRegion((HRGN) hobj)); case SURF_TYPE: return(bDeleteSurface((HSURF)hobj)); case PAL_TYPE: return(bDeletePalette((HPAL) hobj)); case LFONT_TYPE: // see if its in cfont list.
for (ii = 0; ii < MAX_PUBLIC_CFONT; ++ii) { if (gpGdiSharedMemory->acfPublic[ii].hf == hobj) { // just nuke the hfont as this invalidates the whole entry
gpGdiSharedMemory->acfPublic[ii].hf = 0; break; } } return(bDeleteFont((HLFONT) hobj, FALSE));
case BRUSH_TYPE: return(bDeleteBrush((HBRUSH) hobj, FALSE)); case DC_TYPE: return(bDeleteDCInternal((HDC) hobj,TRUE,FALSE)); default: return(FALSE); } }
/******************************Public*Routine******************************\
* NtGdiDeleteObjectApp() * * Same as DeleteObject() but doesn't allow public objects to be deleted. * This should only be called from server.c coming from the client. User * and console should call the DeleteObject(). * * History: * 01-Nov-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiDeleteObjectApp( HANDLE hobj ) { ULONG objt;
// don't allow deletion of stock objects, just succeed
if (HmgStockObj(hobj)) { return(TRUE); }
objt = HmgObjtype(hobj);
// check if it is a public object. If it is, check if it is a public deletable
// surface set by user.
if (GreGetObjectOwner((HOBJ)hobj,objt) == OBJECT_OWNER_PUBLIC) { if (objt == SURF_TYPE) { WARNING("Trying to delete public surface!"); }
#if 0
BOOL bMsg = TRUE;
if (objt == BRUSH_TYPE) { BRUSHSELOBJ bo(hbrush);
if (bo.bValid() || bo.bIsGlobal()) bMsg = FALSE; }
if (bMsg) { DbgPrint("GDI Warning: app trying to delete public object %lx\n",hobj); } #endif
//
// return FALSE if hobj == NULL
// otherwise TRUE
//
return(hobj != NULL); }
switch (objt) { case RGN_TYPE: return(bDeleteRegion((HRGN) hobj)); case SURF_TYPE: return(bDeleteSurface((HSURF)hobj)); case PAL_TYPE: return(bDeletePalette((HPAL) hobj)); case LFONT_TYPE: return(bDeleteFont((HLFONT) hobj, FALSE)); case BRUSH_TYPE: return(bDeleteBrush((HBRUSH) hobj, FALSE)); case DC_TYPE: // don't allow deletion of DC's by an app if the undeletable flag is set
return(bDeleteDCInternal((HDC) hobj,FALSE,FALSE)); default: return(FALSE); } }
/******************************Public*Routine******************************\
* cjGetBrushOrPen * * Gets brush or pen object data. * * For extended pens, some information such as the style array are kept * only on this, the server side. Most of the brush data is also kept * on the client side for GetObject. * * returns: Number of bytes needed if pvDest == NULL, else bytes copied out. * For error it returns 0. * * History: * Thu 23-Mar-1992 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
LONG cjGetBrushOrPen(HANDLE hobj, int iCount, LPVOID pvDest) { LONG lRet = 0;
BRUSHSELOBJ bro((HBRUSH) hobj);
// NOTE SIZE: Most of this is bunk, since for NT all brush data is kept on the
// client side, and so some of this code path won't even be
// executed. [andrewgo]
//
// And for DOS, we would return some fields as zero, whereas under
// NT we would always return what we were given. [andrewgo]
if (bro.bValid()) { if (bro.bIsOldStylePen()) { // Old style pen...
bSyncBrushObj(bro.pbrush());
if (pvDest == (LPVOID) NULL) { lRet = sizeof(LOGPEN); } else if (iCount >= sizeof(LOGPEN)) { if ((iCount == (int) sizeof(EXTLOGPEN)) && ((UINT) bro.flStylePen() == PS_NULL)) { //moved the NULL extended pen handling from client
//side to server side
PEXTLOGPEN pelp = (PEXTLOGPEN) pvDest;
pelp->elpPenStyle = PS_NULL; pelp->elpWidth = 0; pelp->elpBrushStyle = 0; pelp->elpColor = 0; pelp->elpHatch = 0; pelp->elpNumEntries = 0;
lRet = sizeof(EXTLOGPEN); } else { // Fill in the logical pen.
((LOGPEN *) pvDest)->lopnStyle = (UINT) bro.flStylePen(); ((LOGPEN *) pvDest)->lopnWidth.x = (int) bro.lWidthPen(); ((LOGPEN *) pvDest)->lopnWidth.y = 0; ((LOGPEN *) pvDest)->lopnColor = bro.clrPen(); lRet = sizeof(LOGPEN); } } } else if (bro.bIsPen()) { // Extended pen...
ULONG cstyle = (bro.bIsUserStyled()) ? bro.cstyle() : 0;
int cj = (int) (sizeof(EXTLOGPEN) - sizeof(DWORD) + sizeof(DWORD) * (SIZE_T) cstyle);
if (pvDest == (LPVOID) NULL) { lRet = cj; } else if (iCount >= cj) { PEXTLOGPEN pelp = (PEXTLOGPEN) pvDest;
pelp->elpPenStyle = (UINT) bro.flStylePen(); pelp->elpWidth = (UINT) bro.lWidthPen(); pelp->elpNumEntries = cstyle;
if (cstyle > 0) { // We can't just do a RtlCopyMemory for cosmetics, because
// we don't know how the LONGs are packed in the
// FLOAT_LONG array:
PFLOAT_LONG pelSrc = bro.pstyle(); PLONG plDest = (PLONG) &pelp->elpStyleEntry[0];
for (; cstyle > 0; cstyle--) { if (bro.bIsCosmetic()) *plDest = pelSrc->l; else { EFLOATEXT efLength(pelSrc->e); BOOL b = efLength.bEfToL(*plDest);
ASSERTGDI(b, "Shouldn't have overflowed"); }
plDest++; pelSrc++; } }
// The client side GetObject will fill in the rest of the
// EXTLOGPEN struct. i.e. elpBrushStyle, elpColor, and elpHatch.
// Changed: added these here -30-11-94 -by- Lingyunw
// added lBrushStyle and lHatch to PEN
pelp->elpBrushStyle = bro.lBrushStyle(); pelp->elpColor = bro.crColor(); pelp->elpHatch = bro.lHatch();
lRet = cj; } } else { // Brush...
if (pvDest == (LPVOID) NULL) { lRet = sizeof(LOGBRUSH); } else if (iCount >= sizeof(LOGBRUSH)) { // make sure the kernel attributes match
bSyncBrushObj(bro.pbrush());
// Fill in logical brush. Figure out what type it is.
// Duplicates of this info is kept on the client side,
// so most calls won't even get here:
if (bro.flAttrs() & BR_IS_SOLID) { ((LOGBRUSH *) pvDest)->lbStyle = BS_SOLID; ((LOGBRUSH *) pvDest)->lbColor = bro.crColor(); ((LOGBRUSH *) pvDest)->lbHatch = 0; } else if (bro.flAttrs() & BR_IS_BITMAP) { ((LOGBRUSH *) pvDest)->lbStyle = BS_PATTERN; ((LOGBRUSH *) pvDest)->lbColor = 0; ((LOGBRUSH *) pvDest)->lbHatch = (ULONG_PTR)bro.hbmClient(); } else if (bro.flAttrs() & BR_IS_HATCH) { ((LOGBRUSH *) pvDest)->lbStyle = BS_HATCHED; ((LOGBRUSH *) pvDest)->lbColor = bro.crColor(); ((LOGBRUSH *) pvDest)->lbHatch = bro.ulStyle(); } else if (bro.flAttrs() & BR_IS_NULL) { ((LOGBRUSH *) pvDest)->lbStyle = BS_HOLLOW; ((LOGBRUSH *) pvDest)->lbColor = 0; ((LOGBRUSH *) pvDest)->lbHatch = 0; } else if (bro.flAttrs() & BR_IS_DIB) { // Could be BS_DIBPATTERN or BS_DIBPATTERNPT, but we'll just
// return BS_DIBPATTERN.
((LOGBRUSH *) pvDest)->lbStyle = BS_DIBPATTERN; ((LOGBRUSH *) pvDest)->lbColor = bro.crColor(); ((LOGBRUSH *) pvDest)->lbHatch = (ULONG_PTR)bro.hbmClient(); } else RIP("ERROR GreGetObject invalid brush type");
lRet = sizeof(LOGBRUSH); } } } else { WARNING1("cjGetBrushOrPen():hobj is invalid\n"); SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER); }
return(lRet); }
/******************************Public*Routine******************************\
* GreGetObject * * API function * * returns: number of bytes needed if pvDest == NULL, else bytes copied out * for error it returns 0 * * in case a log font object is requested, the function will fill the buffer with * as many bytes of the EXTLOGFONT structure as requested. If a caller * wants a LOGFONTW structure in the buffer, he should specify * ulCount == sizeof(LOGFONTW) * The function will copy the first sizeof(LOGFONTW) bytes of the EXTLOGFONTW * structure to the buffer, which is precisely the LOGFONTW structure. The rest * of the EXTLOGFONTW structure will be chopped off. * * History: * * Thu 12-Dec-1996 -by- Bodin Dresevic [BodinD] * update: changed EXTLOGFONT to ENUMLOGFONTEXDVW * * Thu 30-Jan-1992 -by- J. Andrew Goossen [andrewgo] * added extended pen support. * * Wed 21-Aug-1991 -by- Bodin Dresevic [BodinD] * update: converted to return EXTLOGFONTW * * Fri 24-May-1991 -by- Patrick Haluptzok [patrickh] * added first pass pen and brush stuff. * * Tue 24-Apr-1991 -by- Patrick Haluptzok [patrickh] * added surface stuff. * * 08-Dec-1990 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
int APIENTRY GreExtGetObjectW(HANDLE hobj, int ulCount, LPVOID pvDest) { int cRet = 0;
switch (HmgObjtype(hobj)) { case PAL_TYPE: cRet = 2;
if (pvDest != NULL) { if (ulCount < 2) { cRet = 0; } else { SEMOBJ semo(ghsemPalette);
{ EPALOBJ pal((HPALETTE) hobj);
if (!(pal.bValid())) cRet = 0; else *((PUSHORT) pvDest) = (USHORT) (pal.cEntries()); } } } break;
case LFONT_TYPE:
// The output object is assumed to be
// an ENUMLOGFONTEXDVW structure.
// client side shall do the translation to LOGFONT if necessary
{ LFONTOBJ lfo((HLFONT) hobj); if (lfo.bValid()) { if (pvDest != (LPVOID) NULL) { SIZE_T cjCopy = MIN((SIZE_T) ulCount, lfo.cjElfw());
RtlCopyMemory(pvDest, lfo.pelfw(), (UINT) cjCopy);
cRet = (ULONG) cjCopy; } else { cRet = lfo.cjElfw(); } } else { WARNING("GreGetObject(): bad handle\n"); } } break;
case SURF_TYPE: if (pvDest != (LPVOID) NULL) { cRet = 0;
if (ulCount >= (int)sizeof(BITMAP)) { SURFREF SurfBm((HSURF) hobj);
if ((SurfBm.bValid()) && (SurfBm.ps->bApiBitmap() || SurfBm.ps->bDirectDraw())) { BITMAP *pbm = (BITMAP *) pvDest;
pbm->bmType = 0; pbm->bmWidth = SurfBm.ps->sizl().cx; pbm->bmHeight = SurfBm.ps->sizl().cy;
pbm->bmBitsPixel = (WORD) gaulConvert[SurfBm.ps->iFormat()]; pbm->bmWidthBytes = ((SurfBm.ps->sizl().cx * pbm->bmBitsPixel + 15) >> 4) << 1; pbm->bmPlanes = 1; pbm->bmBits = (LPSTR) NULL;
cRet = sizeof(BITMAP);
// Get the bitmapinfoheader for the dibsection if the buffer
// can hold it.
if (SurfBm.ps->bDIBSection() || SurfBm.ps->bDirectDraw()) { // Win95 compatability. They fill in the bits even if it
// is not big enough for a full DIBSECTION
pbm->bmBits = IS_USER_ADDRESS((LPSTR) SurfBm.ps->pvBits()) ? (LPSTR) SurfBm.ps->pvBits() : NULL;
// If this is a DIBSection/DirectDraw surface bmWidthBytes must be aligned
// on a DWORD boundary.
pbm->bmWidthBytes = ((SurfBm.ps->sizl().cx * pbm->bmBitsPixel + 31) & ~31) >> 3;
if (ulCount >= sizeof(DIBSECTION)) { PBITMAPINFOHEADER pbmih = &((DIBSECTION *)pvDest)->dsBmih;
pbmih->biSize = sizeof(BITMAPINFOHEADER); pbmih->biBitCount = 0;
if (GreGetDIBitsInternal(0,(HBITMAP)hobj,0,0,NULL, (PBITMAPINFO)pbmih,DIB_RGB_COLORS,0, sizeof(DIBSECTION))) { cRet = sizeof(DIBSECTION);
// More Win9x compatibility: for DDraw surfaces, the
// following field is always zero. GDI+ keys off
// this Win9x feature to do cheap detection of
// DDraw surfaces:
if (SurfBm.ps->bDirectDraw()) { pbmih->biSizeImage = 0; } }
XEPALOBJ pal(SurfBm.ps->ppal());
if (pal.bValid() && pal.bIsBitfields()) { ((DIBSECTION *)pvDest)->dsBitfields[0] = pal.flRed(); ((DIBSECTION *)pvDest)->dsBitfields[1] = pal.flGre(); ((DIBSECTION *)pvDest)->dsBitfields[2] = pal.flBlu(); }
// to be consistent with win95, Getobject returns BI_RGB for
// 24bpp, and 32bpp when BI_RGB is set at creation time
else { if (pal.bValid() && pal.bIsBGR()) { pbmih->biCompression = BI_RGB; }
((DIBSECTION *)pvDest)->dsBitfields[0] = 0; ((DIBSECTION *)pvDest)->dsBitfields[1] = 0; ((DIBSECTION *)pvDest)->dsBitfields[2] = 0; }
((DIBSECTION *)pvDest)->dshSection = SurfBm.ps->hDIBSection(); ((DIBSECTION *)pvDest)->dsOffset = SurfBm.ps->dwOffset(); } } } } } else { cRet = sizeof(BITMAP); }
break;
case BRUSH_TYPE: cRet = (int) cjGetBrushOrPen(hobj, ulCount, pvDest); break;
case ICMLCS_TYPE: cRet = cjGetLogicalColorSpace(hobj,ulCount,pvDest); break;
default: break; }
return(cRet); }
/******************************Public*Routine******************************\
* GreGetStockObject * * API function * * returns the handle to the stock object requested. * * History: * 08-Dec-1990 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/
HANDLE gahStockObjects[PRIV_STOCK_LAST+1] = {0};
HANDLE GreGetStockObject(int ulIndex) { if (((UINT)ulIndex) <= PRIV_STOCK_LAST) { return(gahStockObjects[ulIndex]); } else { return(0); } }
BOOL bSetStockObject( HANDLE h, int iObj ) { if (h) { gahStockObjects[iObj] = (HANDLE)((ULONG_PTR)h | GDISTOCKOBJ); HmgModifyHandleType((HOBJ) gahStockObjects[iObj]); } return(h != NULL); }
/******************************Public*Routine******************************\
* BOOL GreGetColorAdjustment * * Get the color adjustment data of the given DC. * * History: * 25-Aug-1992 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreGetColorAdjustment(HDC hdc, COLORADJUSTMENT *pca) { DCOBJ dco(hdc); BOOL Status;
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); Status = FALSE;
} else {
// Retrieve info from the DC. Mask out the internal flag.
*pca = *dco.pColorAdjustment(); pca->caFlags &= (CA_NEGATIVE | CA_LOG_FILTER); Status = TRUE; }
return Status; }
/******************************Public*Routine******************************\
* BOOL GreSetColorAdjustment * * Set the color adjustment data of the given DC. * * History: * 25-Aug-1992 -by- Wendy Wu [wendywu] * Wrote it. \**************************************************************************/
BOOL APIENTRY GreSetColorAdjustment(HDC hdc, COLORADJUSTMENT *pcaNew) { DCOBJ dco(hdc); BOOL Status;
if (!dco.bValid()) { SAVE_ERROR_CODE(ERROR_INVALID_HANDLE); Status = FALSE;
} else {
// Store info into the DC. Turn off any flags that we don't support.
*dco.pColorAdjustment() = *pcaNew; dco.pColorAdjustment()->caFlags &= (CA_NEGATIVE | CA_LOG_FILTER); Status = TRUE; }
return Status; }
/******************************Public*Routine******************************\
* HANDLE GreCreateClientObj() * * A ClientObj contains no data. It is purly to provide a handle to the * client for objects such as metafiles that exist only on the client side. * * ulType is a client type. * * History: * 17-Jan-1995 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
HANDLE NtGdiCreateClientObj( ULONG ulType) { HANDLE h = NULL;
// ClientObj handles should never have any INDEX bits set and have some
// ALT bits set. Also the type must be a LO_CLIENTOBJ_TYPE
if((ulType & (INDEX_MASK)) || !(ulType & (ALTTYPE_MASK)) || ((ulType & TYPE_MASK) != LO_CLIENTOBJ_TYPE)) { WARNING("GreCreateClientObj: bad type\n"); return(h); }
PVOID pv = ALLOCOBJ(sizeof(OBJECT), CLIENTOBJ_TYPE, FALSE);
if (pv) { h = HmgInsertObject(pv, 0, CLIENTOBJ_TYPE);
if (!h) { WARNING("GreCreateClientObj: HmgInsertObject failed\n"); FREEOBJ(pv, CLIENTOBJ_TYPE); } else { pv = HmgLock((HOBJ) h,CLIENTOBJ_TYPE);
if (pv != NULL) { h = MODIFY_HMGR_TYPE(h,ulType); HmgModifyHandleType((HOBJ)h); DEC_EXCLUSIVE_REF_CNT(pv); } else { RIP("GreCreateClientObj failed lock\n"); }
} } else { WARNING("GreCreateClientObj(): ALLOCOBJ failed\n"); }
return(h); }
/******************************Public*Routine******************************\
* * * History: * 17-Jan-1995 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
BOOL GreDeleteClientObj( HANDLE h) { PVOID pv = HmgRemoveObject((HOBJ)h, 0, 0, TRUE, CLIENTOBJ_TYPE);
if (pv != NULL) { FREEOBJ(pv, CLIENTOBJ_TYPE); return(TRUE); } else { WARNING("GreDeleteClientObj: HmgRemoveObject failed\n"); return(FALSE); } }
/******************************Public*Routine******************************\
* NtGdiDeleteClientObj() * * History: * 01-Nov-1994 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/
BOOL APIENTRY NtGdiDeleteClientObj( HANDLE h ) { return(GreDeleteClientObj(h)); }
/******************************Public*Routine******************************\
* GreFreePool * * Private USER call to delete memory allocated by GDI. * * Only known use is to delete the MDEV structure returned by DrvCreateMDEV * and cached by USER. * * History: * 24-Feb-1998 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
extern "C" VOID GreFreePool(PVOID pv) { GdiFreePool(pv); }
/******************************Public*Routine******************************\
* hdevEnumerate * * Enumerates all display PDEVs without keeping ghsemDriverMgmt, allowing * the devlock to be taken on each. This function must be called until it * returns NULL or proper cleanup will not occur. * * History: * 02-Jul-1999 -by- John Stephens [johnstep] * Wrote it. \**************************************************************************/
HDEV hdevEnumerate( HDEV hdevPrevious ) { PDEV* ppdev;
GreAcquireSemaphoreEx(ghsemDriverMgmt, SEMORDER_DRIVERMGMT, NULL);
// If we are called with NULL hdevPrevious then create the PDEVOBJ from
// gppdevList, else create it from hdevPrevious:
PDEVOBJ po(hdevPrevious ? hdevPrevious : (HDEV) gppdevList); ASSERTGDI(po.bValid(), "Invalid HDEV");
// Search for the next display PDEV. If hdevPrevious is NULL, then
// we start with po, else start from the next:
for (ppdev = hdevPrevious ? po.ppdev->ppdevNext : po.ppdev; ppdev; ppdev = ppdev->ppdevNext) { // We're only interested in display PDEVs:
if (ppdev->fl & PDEV_DISPLAY) { // We found the next display PDEV, so take a reference count
// on it before releasing ghsemDriverMgmt and returning. This
// reference count will be removed next time through:
ppdev->cPdevRefs++; break; } }
// If hdevPrevious is not NULL then we need to remove the reference
// count we took, and we'll also release ghsemDriverMgmt here in the
// appropriate place:
if (hdevPrevious) { // If our reference count is not the last, just decrement, else we
// need to call vUnreferencePdev so the PDEV will actually be
// deleted:
ASSERTGDI(po.cPdevRefs() > 0, "PDEV reference count is 0 but should be at least 1"); if (po.cPdevRefs() > 1) { po.ppdev->cPdevRefs--; GreReleaseSemaphoreEx(ghsemDriverMgmt); } else { // Release ghsemDriverMgmt before calling vUnreferencePdev
// because the call may result in the devlock being taken:
GreReleaseSemaphoreEx(ghsemDriverMgmt); po.vUnreferencePdev(); } } else { GreReleaseSemaphoreEx(ghsemDriverMgmt); }
return (HDEV) ppdev; }
/******************************Public*Routine******************************\
* vSynchronizeDriver * * Calls DrvSynchronize if the driver has set either GCAPS2_SYNCFLUSH * or GCAPS2_SYNCTIMER, as appropriate. * * History: * 15-Dec-1997 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
VOID vSynchronizeDriver(FLONG flSynchronizeType) { HDEV hdev;
//
// Note that we check the synchronize counts outside of a lock, which
// is okay.
//
//
// We just accumlate what needs to be synchronized when we are in the middle
// of a mode change.
//
if (CModeChangeInProgress::lInModeChange) { if(flSynchronizeType == GCAPS2_SYNCFLUSH && gcSynchronizeFlush != -1) InterlockedCompareExchange(&CModeChangeInProgress::lNeedSyncFlush,1,0); if(flSynchronizeType == GCAPS2_SYNCTIMER && gcSynchronizeTimer != -1) InterlockedCompareExchange(&CModeChangeInProgress::lNeedTimerFlush,1,0); return; }
if (((flSynchronizeType == GCAPS2_SYNCFLUSH) && (gcSynchronizeFlush != -1)) || ((flSynchronizeType == GCAPS2_SYNCTIMER) && (gcSynchronizeTimer != -1))) { for (hdev = hdevEnumerate(NULL); hdev; hdev = hdevEnumerate(hdev)) { PDEVOBJ pdo(hdev);
ASSERTGDI(pdo.bValid(), "GreFlush: invalid PDEV"); ASSERTGDI(pdo.bDisplayPDEV(), "GreFlush: not a display PDEV");
if (pdo.flGraphicsCaps2NotDynamic() & flSynchronizeType) { GreAcquireSemaphoreEx(pdo.hsemDevLock(), SEMORDER_DEVLOCK, NULL); GreEnterMonitoredSection(pdo.ppdev, WD_DEVLOCK);
if ((pdo.flGraphicsCaps2() & flSynchronizeType) && !(pdo.bDisabled())) { FLONG fl = 0;
if ((flSynchronizeType == GCAPS2_SYNCFLUSH) && (gcSynchronizeFlush != -1)) { fl |= DSS_FLUSH_EVENT; }
if ((flSynchronizeType == GCAPS2_SYNCTIMER) && (gcSynchronizeTimer != -1)) { fl |= DSS_TIMER_EVENT; }
pdo.vSync(pdo.pSurface()->pSurfobj(), NULL, fl); }
GreExitMonitoredSection(pdo.ppdev, WD_DEVLOCK); GreReleaseSemaphoreEx(pdo.hsemDevLock()); } } } }
/******************************Public*Routine******************************\
* GreFlush * * Called for GdiFlush. * * Calls DrvSynchronize if it is hooked and GCAPS2_SYNCFLUSH is set. * * History: * 15-Dec-1997 -by- Gilman Wong [gilmanw] * Wrote it. \**************************************************************************/
VOID APIENTRY GreFlush() { vSynchronizeDriver(GCAPS2_SYNCFLUSH); }
/******************************Public*Routine******************************\
* GreSynchronizeTimer * * When the synchronization timer is enabled, this routine will be called * by User's RIT. We, in turn, call any driver that has set GCAPS_SYNCTIMER. * * History: * 2-Jun-1998 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID APIENTRY GreSynchronizeTimer(PVOID pwnd, UINT msg, UINT_PTR id, LPARAM lParam) { vSynchronizeDriver(GCAPS2_SYNCTIMER); }
/******************************Public*Routine******************************\
* vEnableSynchronize * * This routine enables GCAPS2_SYNCFLUSH and GCAPS2_SYNCTIMER * synchronization for the driver. * * History: * 2-Jun-1998 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID vEnableSynchronize(HDEV hdev) { GDIFunctionID(vEnableSynchronize);
PDEVOBJ po(hdev);
FLONG flCaps = po.flGraphicsCaps2();
if (flCaps & (GCAPS2_SYNCFLUSH | GCAPS2_SYNCTIMER)) { BOOL AcquireUserCritSec;
//
// We will be calling User, which needs to acquire its critical
// section. The devlock must always be acquired after the User
// critical section; consequently, we cannot be holding a devlock
// at this point if we're not already holding the user lock.
//
AcquireUserCritSec = !UserIsUserCritSecIn(); if (AcquireUserCritSec) { po.vAssertNoDevLock(); UserEnterUserCritSec(); }
if (flCaps & GCAPS2_SYNCTIMER) { //
// It's the responsibility of the first thread to increment
// the count past -1 to create the timer.
//
if (++gcSynchronizeTimer == 0) { ASSERTGDI(gidSynchronizeTimer == 0, "Expected no timer to have already been created.");
//
// Note that at boot time we actually expect this timer
// creation to fail, as User hasn't had a chance to
// create the RIT yet. GreSetTimers handles the actual
// timer creation for that case. Because of this case,
// we can't strictly fail here if the timer can't be
// created; however, it's not the end of the world --
// this will happen only in a degenerate case, and at
// worst the video will be very jerky.
//
gidSynchronizeTimer = UserSetTimer(SYNCTIMER_FREQUENCY, GreSynchronizeTimer); } }
if (flCaps & GCAPS2_SYNCFLUSH) { gcSynchronizeFlush++; }
po.vSynchronizeEnabled(TRUE);
if (AcquireUserCritSec) { UserLeaveUserCritSec(); } } }
/******************************Public*Routine******************************\
* vDisableSynchronize(HDEV hdev) * * This routine disables GCAPS2_SYNCFLUSH and GCAPS2_SYNCTIMER * synchronization for the driver. * * History: * 2-Jun-1998 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID vDisableSynchronize(HDEV hdev) { GDIFunctionID(vDisableSynchronize);
PDEVOBJ po(hdev); BOOL AcquireUserCritSec;
//
// We will be calling User, which needs to acquire its critical
// section. The devlock must always be acquired after the User
// critical section; consequently, we cannot be holding a devlock
// at this point if we're not already holding the user lock.
//
AcquireUserCritSec = !UserIsUserCritSecIn(); if (AcquireUserCritSec) { po.vAssertNoDevLock(); UserEnterUserCritSec(); }
if (po.bSynchronizeEnabled()) { FLONG flCaps = po.flGraphicsCaps2();
if (flCaps & GCAPS2_SYNCFLUSH) { ASSERTGDI(gcSynchronizeFlush > -1, "Unexpected flush count");
gcSynchronizeFlush--; }
if (flCaps & GCAPS2_SYNCTIMER) { //
// It's the responsibility of the first thread to decrement
// the count to -1 to kill the timer.
//
ASSERTGDI(gcSynchronizeTimer > -1, "Unexpected timer count");
if (--gcSynchronizeTimer < 0) { if (gidSynchronizeTimer != 0) { UserKillTimer(gidSynchronizeTimer); gidSynchronizeTimer = 0; } } }
po.vSynchronizeEnabled(FALSE); }
if (AcquireUserCritSec) { UserLeaveUserCritSec(); } }
/******************************Public*Routine******************************\
* GreStartTimers() * * Called by User when the RIT thread is finally initialized, and we * can set up timers. We need this because driver initialization * occurs before the RIT is initialized, which would have been the * natural place to put the timer initialization for us. * * History: * 2-Jun-1998 -by- J. Andrew Goossen [andrewgo] * Wrote it. \**************************************************************************/
VOID GreStartTimers() { GDIFunctionID(GreStartTimers);
BOOL AcquireUserCritSec;
AcquireUserCritSec = !UserIsUserCritSecIn(); if (AcquireUserCritSec) { UserEnterUserCritSec(); }
if (gcSynchronizeTimer != -1) { ASSERTGDI(gidSynchronizeTimer == NULL, "Expected no timer to have already been created.");
gidSynchronizeTimer = UserSetTimer(SYNCTIMER_FREQUENCY, GreSynchronizeTimer); }
if (AcquireUserCritSec) { UserLeaveUserCritSec(); } }
/**************************************************************************\
* CmodeChangeInProgress::vDone(). * * Called by DrvChangeDisplaySettings just before it realeases the * ghsemShareDevLock so we may flush any pending vSynchronizeDriver calls. * * History: * 18-Oct-2001 -by- Pravin Santiago [pravins] * Wrote it. \**************************************************************************/
void CModeChangeInProgress::vDone() { InterlockedDecrement(&lInModeChange);
if (lNeedSyncFlush) { vSynchronizeDriver(GCAPS2_SYNCFLUSH); InterlockedDecrement(&lNeedSyncFlush); } if (lNeedTimerFlush) { vSynchronizeDriver(GCAPS2_SYNCTIMER); InterlockedDecrement(&lNeedTimerFlush); } }
|