/******************************Module*Header*******************************\ * Module Name: region.c * * Client region support * * Created: 15-Jun-1995 * Author: Mark Enstrom [marke] * * Copyright (c) 1995-1999 Microsoft Corporation \**************************************************************************/ #include "precomp.h" void OrderRects(LPRECT lpR, int nRects) { RECT R; int i,j; //Sort Left to right for (i=0; itop == (lpR+i)->top); j++){ if (((lpR+j)->left < (lpR+i)->left)) { R = *(lpR+i); *(lpR+i) = *(lpR+j); *(lpR+j) = R; } } } } /******************************Public*Routine******************************\ * MirrorRgnByWidth * Mirror a region (hrgn) according a specific width (cx) * hrgn : region to get mirrored. * cx : width used to mirror the region. * phrgn : If it is not NULL the hrgn will not be touched and the new mirrored region will be returned in phrgn * But if it is NULL the mirrored region will be copied to hrgn. * * WORRNING: * if phrng is not NULL it is the caller responsibility to free *phrgn latter. * * returns: * TRUE : if the region get mirrored * FALSE : otherwise. * See the comment about phrng. * \**************************************************************************/ BOOL MirrorRgnByWidth(HRGN hrgn, int cx, HRGN *phrgn) { int nRects, i, nDataSize; HRGN hrgn2 = NULL; RECT *lpR; int Saveleft; RGNDATA *lpRgnData; BOOL bRet = FALSE; nDataSize = GetRegionData(hrgn, 0, NULL); if (nDataSize && (lpRgnData = (RGNDATA *)LocalAlloc(0, nDataSize * sizeof(DWORD)))) { if (GetRegionData(hrgn, nDataSize, lpRgnData)) { nRects = lpRgnData->rdh.nCount; lpR = (RECT *)lpRgnData->Buffer; Saveleft = lpRgnData->rdh.rcBound.left; lpRgnData->rdh.rcBound.left = cx - lpRgnData->rdh.rcBound.right; lpRgnData->rdh.rcBound.right = cx - Saveleft; for (i=0; ileft; lpR->left = cx - lpR->right; lpR->right = cx - Saveleft; lpR++; } OrderRects((RECT *)lpRgnData->Buffer, nRects); hrgn2 = ExtCreateRegion(NULL, nDataSize, lpRgnData); if (hrgn2) { if (phrgn == NULL) { CombineRgn(hrgn, hrgn2, NULL, RGN_COPY); DeleteObject((HGDIOBJ)hrgn2); } else { *phrgn = hrgn2; } bRet = TRUE; } } //Free mem. LocalFree(lpRgnData); } return bRet; } BOOL WINAPI MirrorRgn(HWND hwnd, HRGN hrgn) { RECT rc; GetWindowRect(hwnd, &rc); rc.right -= rc.left; return MirrorRgnByWidth(hrgn, rc.right, NULL); } BOOL MirrorRgnDC(HDC hdc, HRGN hrgn, HRGN *phrgn) { FIXUP_HANDLE(hdc); if(!IS_ALTDC_TYPE(hdc)) { PDC_ATTR pdcattr; PSHARED_GET_VALIDATE((PVOID)pdcattr,hdc,DC_TYPE); if (pdcattr) { return MirrorRgnByWidth(hrgn, NtGdiGetDeviceWidth(hdc), phrgn); } } return FALSE; } /******************************Public*Routine******************************\ * iRectRelation * * returns: * CONTAINS where prcl1 contains prcl2 * CONTAINED where prcl1 contained by prcl2 * 0 - otherwise * * History: * 19-Nov-1993 -by- Eric Kutter [erick] * Wrote it. \**************************************************************************/ int iRectRelation( PRECTL prcl1, PRECTL prcl2 ) { int iRet = 0; if ((prcl1->left <= prcl2->left) && (prcl1->right >= prcl2->right) && (prcl1->top <= prcl2->top) && (prcl1->bottom >= prcl2->bottom)) { iRet = CONTAINS; } else if ( (prcl2->left <= prcl1->left) && (prcl2->right >= prcl1->right) && (prcl2->top <= prcl1->top) && (prcl2->bottom >= prcl1->bottom)) { iRet = CONTAINED; } else if ( (prcl1->left >= prcl2->right) || (prcl1->right <= prcl2->left) || (prcl1->top >= prcl2->bottom) || (prcl1->bottom <= prcl2->top)) { iRet = DISJOINT; } return(iRet); } /******************************Public*Routine******************************\ * * CreateRectRgn gets an hrgn with user-mode PRGNATTR pointer and * sets the type to SIMPLEREGION. * * Arguments: * * x1 * y1 * x2 * y2 * * Return Value: * * HRGN or NULL * * History: * * 15-Jun-1995 -by- Mark Enstrom [marke] * \**************************************************************************/ #define MIN_REGION_COORD ((LONG) 0xF8000000) #define MAX_REGION_COORD ((LONG) 0x07FFFFFF) HRGN WINAPI CreateRectRgn( int x1, int y1, int x2, int y2 ) { // // get a region handle, allocate memory for the // region and associate handle with memory // PRGNATTR prRegion; HRGN hrgn; // // rectangle must be ordered // #if NOREORDER_RGN if ((x1 > x2) || (y1 > y2)) { WARNING("CreateRectRgn called with badly ordered region"); x1 = 0; x2 = 0; y1 = 0; y2 = 0; } #else if (x1 > x2) { int t = x1; x1 = x2; x2 = t; } if (y1 > y2) { int t = y1; y1 = y2; y2 = t; } #endif // // make sure ordered coordinates are legal // if ((x1 < MIN_REGION_COORD) || (y1 < MIN_REGION_COORD) || (x2 > MAX_REGION_COORD) || (y2 > MAX_REGION_COORD)) { GdiSetLastError(ERROR_INVALID_PARAMETER); return((HRGN) 0); } // // get a handle for the new region // hrgn = (HRGN)hGetPEBHandle(RegionHandle,0); if (hrgn == NULL) { hrgn = NtGdiCreateRectRgn(0,0,1,1); } PSHARED_GET_VALIDATE(prRegion,hrgn,RGN_TYPE); if (prRegion) { if ((x1 == x2) || (y1 == y2)) { prRegion->Flags = NULLREGION; prRegion->Rect.left = 0; prRegion->Rect.top = 0; prRegion->Rect.right = 0; prRegion->Rect.bottom = 0; } else { prRegion->Flags = SIMPLEREGION; // // assign region rectangle // prRegion->Rect.left = x1; prRegion->Rect.top = y1; prRegion->Rect.right = x2; prRegion->Rect.bottom = y2; } // // mark user-mode region as valid, not cached // prRegion->AttrFlags = ATTR_RGN_VALID | ATTR_RGN_DIRTY; } else { if (hrgn != NULL) { WARNING("Shared hrgn handle has no valid PRGNATTR"); DeleteRegion(hrgn); hrgn = NULL; } } return(hrgn); } /******************************Public*Routine******************************\ * CreateRectRgnIndirect * * * * Client side stub. * * * * Tue 04-Jun-1991 16:58:01 -by- Charles Whitmer [chuckwh] * * Wrote it. * \**************************************************************************/ HRGN WINAPI CreateRectRgnIndirect(CONST RECT *prcl) { return CreateRectRgn ( prcl->left, prcl->top, prcl->right, prcl->bottom ); } /******************************Public*Routine******************************\ * * The PtInRegion function determines whether the specified point is * inside the specified region. * * Arguments: * * hrgn - app region handle * x - point x * y - point y * * Return Value: * * If the specified point is in the region, the return value is TRUE. * If the function fails, the return value is FALSE. * * History: * * 21-Jun-1995 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL WINAPI PtInRegion( HRGN hrgn, int x, int y ) { BOOL bRet = FALSE; BOOL bUserMode = FALSE; PRECTL prcl; PRGNATTR prRegion; FIXUP_HANDLE(hrgn); PSHARED_GET_VALIDATE(prRegion,hrgn,RGN_TYPE); if (prRegion != NULL) { if (prRegion->Flags == NULLREGION) { bRet = FALSE; bUserMode = TRUE; } else if (prRegion->Flags == SIMPLEREGION) { prcl = &prRegion->Rect; if ((x >= prcl->left) && (x < prcl->right) && (y >= prcl->top) && (y < prcl->bottom)) { bRet = TRUE; } bUserMode = TRUE; } } if (!bUserMode) { bRet = NtGdiPtInRegion(hrgn,x,y); } return(bRet); } /******************************Public*Routine******************************\ * * The RectInRegion function determines whether any part of the specified * rectangle is within the boundaries of a region. * * Arguments: * * hrgn - app region handle * prcl - app rectangle * * Return Value: * * If any part of the specified rectangle lies within the boundaries * of the region, the return value is TRUE. * * If the function fails, the return value is FALSE. * * History: * * 21-Jun-1995 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL WINAPI RectInRegion( HRGN hrgn, CONST RECT *prcl ) { PRGNATTR prRegion; BOOL bRet = FALSE; RECTL TempRect; LONG iRelation; BOOL bUserMode = FALSE; FIXUP_HANDLE(hrgn); PSHARED_GET_VALIDATE(prRegion,hrgn,RGN_TYPE); if (prRegion != NULL) { if (prRegion->Flags == NULLREGION) { bRet = FALSE; bUserMode = TRUE; } else if (prRegion->Flags == SIMPLEREGION) { TempRect = *((PRECTL)prcl); ORDER_PRECTL((&TempRect)); iRelation = iRectRelation(&prRegion->Rect,&TempRect); if (iRelation != DISJOINT) { bRet = TRUE; } bUserMode = TRUE; } } if (!bUserMode) { bRet = NtGdiRectInRegion(hrgn, (PRECT)prcl); } return(bRet); } /******************************Public*Routine******************************\ * * The CombineRgn function combines two regions and stores the result in * a third region. The two regions are combined according to the specified * mode. * * Arguments: * * hrgnDst - destination region * hrgnSrc1 - source region * hrgnSrc2 - source region * iMode - destination region * * Return Value: * * The resulting type of region or ERROR * * History: * * 21-Jun-1995 -by- Mark Enstrom [marke] * \**************************************************************************/ int WINAPI CombineRgn( HRGN hrgnDst, HRGN hrgnSrc1, HRGN hrgnSrc2, int iMode ) { LONG ResultComplexity = COMPLEXREGION; int iRet = ERROR; // // Check if this operation can be completed in user-mode. // hrgnDst must have a user mode RGNATTR. hrgnSrc1 must // also have a user mode RGNATTR. If iMode is not RGN_COPY // then hrgnSrc2 must have a user mode RGNATTR except for certain // combinations. // PRGNATTR prRegionDst; PRGNATTR prRegionSrc1; PRGNATTR prRegionSrc2; PRECTL prclRes; PRECTL prclSrc1; PRECTL prclSrc2; LONG ComplexSrc1; LONG ComplexSrc2; FIXUP_HANDLE(hrgnDst); FIXUP_HANDLE(hrgnSrc1); FIXUP_HANDLEZ(hrgnSrc2); PSHARED_GET_VALIDATE(prRegionDst,hrgnDst,RGN_TYPE); PSHARED_GET_VALIDATE(prRegionSrc1,hrgnSrc1,RGN_TYPE); if ((prRegionDst != (PRGNATTR)NULL) && (prRegionSrc1 != (PRGNATTR)NULL)) { // // region Src1 must me NULL or SIMPLE for current // user-mode optimizations. If Rect is the region // bounding box, then it will be possible for // some combinations with regionC to become // SIMPLE or NULL. // prclSrc1 = &prRegionSrc1->Rect; ComplexSrc1 = prRegionSrc1->Flags; if (ComplexSrc1 > SIMPLEREGION) { goto CombineRgnKernelMode; } if (iMode == RGN_COPY) { prclRes = prclSrc1; ResultComplexity = ComplexSrc1; } else { LONG iRelation; // // validate regionSrc2 // PSHARED_GET_VALIDATE(prRegionSrc2,hrgnSrc2,RGN_TYPE); if ( (prRegionSrc2 == (PRGNATTR)NULL) || (prRegionSrc2->Flags > SIMPLEREGION) ) { goto CombineRgnKernelMode; } prclSrc2 = &prRegionSrc2->Rect; ComplexSrc2 = prRegionSrc2->Flags; switch (iMode) { case RGN_AND: // // Creates the intersection of the two // combined regions. // if ((ComplexSrc1 == NULLREGION) || (ComplexSrc2 == NULLREGION)) { // // intersection with NULL is NULL // ResultComplexity = NULLREGION; } else { iRelation = iRectRelation(prclSrc1,prclSrc2); if (iRelation == DISJOINT) { ResultComplexity = NULLREGION; } else if (iRelation == CONTAINED) { // // Src1 is contained in Src2 // ResultComplexity = SIMPLEREGION; prclRes = prclSrc1; } else if (iRelation == CONTAINS) { // // Src1 is contains Src2 // ResultComplexity = SIMPLEREGION; prclRes = prclSrc2; } } break; case RGN_OR: case RGN_XOR: // // RGN_OR: Creates the union of two combined regions. // RGN_XOR: Creates the union of two combined regions // except for any overlapping areas. // if (ComplexSrc1 == NULLREGION) { if (ComplexSrc2 == NULLREGION) { ResultComplexity = NULLREGION; } else { ResultComplexity = SIMPLEREGION; prclRes = prclSrc2; } } else if (ComplexSrc2 == NULLREGION) { ResultComplexity = SIMPLEREGION; prclRes = prclSrc1; } else if (iMode == RGN_OR) { iRelation = iRectRelation(prclSrc1,prclSrc2); if (iRelation == CONTAINED) { // // Src1 contained in Src2 // ResultComplexity = SIMPLEREGION; prclRes = prclSrc2; } else if (iRelation == CONTAINS) { // // Src1 contains Src2 // ResultComplexity = SIMPLEREGION; prclRes = prclSrc1; } } break; case RGN_DIFF: // // Combines the parts of hrgnSrc1 that are not // part of hrgnSrc2. // if (ComplexSrc1 == NULLREGION) { ResultComplexity = NULLREGION; } else if (ComplexSrc2 == NULLREGION) { ResultComplexity = SIMPLEREGION; prclRes = prclSrc1; } else { iRelation = iRectRelation(prclSrc1,prclSrc2); if (iRelation == DISJOINT) { // // don't intersect so don't subtract anything // ResultComplexity = SIMPLEREGION; prclRes = prclSrc1; } else if (iRelation == CONTAINED) { ResultComplexity = NULLREGION; } } break; } } // // try to combine // if (ResultComplexity == NULLREGION) { if (SetRectRgn(hrgnDst,0,0,0,0)) { iRet = NULLREGION; } } else if (ResultComplexity == SIMPLEREGION) { if (SetRectRgn(hrgnDst, prclRes->left, prclRes->top, prclRes->right, prclRes->bottom)) { iRet = SIMPLEREGION; } } } if (ResultComplexity != COMPLEXREGION) { prRegionDst->AttrFlags |= ATTR_RGN_DIRTY; } CombineRgnKernelMode: if (ResultComplexity == COMPLEXREGION) { iRet = NtGdiCombineRgn(hrgnDst,hrgnSrc1,hrgnSrc2,iMode); } return(iRet); } /******************************Public*Routine******************************\ * * OffsetRgn checks for user-mode region data, if it exits the the * rectregio is offset, otherwise the kernel is called * * Arguments: * * hrgn - app region handle * x - offset in x * y - offset in y * * Return Value: * * * * History: * * 21-Jun-1995 -by- Mark Enstrom [marke] * \**************************************************************************/ int WINAPI OffsetRgn( HRGN hrgn, int x, int y ) { int iRet; BOOL bClientRegion = FALSE; PRGNATTR prRegion; FIXUP_HANDLE(hrgn); PSHARED_GET_VALIDATE(prRegion,hrgn,RGN_TYPE); if (prRegion != NULL) { iRet = prRegion->Flags; if (iRet == NULLREGION) { bClientRegion = TRUE; } else if (iRet == SIMPLEREGION) { RECTL rcl = prRegion->Rect; bClientRegion = TRUE; // // try to offset the region, check for overflow // if ( !((rcl.left >= rcl.right) || (rcl.top >= rcl.bottom))) { rcl.left += x; rcl.top += y; rcl.right += x; rcl.bottom += y; if (VALID_SCRRC(rcl)) { prRegion->Rect = rcl; prRegion->AttrFlags |= ATTR_RGN_DIRTY; } else { // // over/underflow // iRet = ERROR; } } } } if (!bClientRegion) { iRet = NtGdiOffsetRgn(hrgn,x,y); } return(iRet); } /******************************Public*Routine******************************\ * * GetRgnBox tries to return user-mode rectregion data, otherwies * make kernel mode transition to get region data. * * Arguments: * * hrgn - app region handle * prcl - app rect pointer * * Return Value: * * region complexity, if the hrgn parameter does not identify a * valid region, the return value is zero. * * History: * * 21-Jun-1995 -by- Mark Enstrom [marke] * \**************************************************************************/ int WINAPI GetRgnBox( HRGN hrgn, LPRECT prcl ) { int iRet; BOOL bClientRegion = FALSE; // // check for user-mode region data // PRGNATTR prRegion; FIXUP_HANDLE(hrgn); PSHARED_GET_VALIDATE(prRegion,hrgn,RGN_TYPE); if (prRegion != NULL) { iRet = prRegion->Flags; if (iRet == NULLREGION) { bClientRegion = TRUE; prcl->left = 0; prcl->top = 0; prcl->right = 0; prcl->bottom = 0; } else if (iRet == SIMPLEREGION) { bClientRegion = TRUE; prcl->left = prRegion->Rect.left; prcl->top = prRegion->Rect.top; prcl->right = prRegion->Rect.right; prcl->bottom = prRegion->Rect.bottom; } } if (!bClientRegion) { iRet = NtGdiGetRgnBox(hrgn, prcl); } return(iRet); } /******************************Public*Routine******************************\ * PtVisible * * * * Client side stub. * * * * Thu 06-Jun-1991 00:58:46 -by- Charles Whitmer [chuckwh] * * Wrote it. * \**************************************************************************/ BOOL WINAPI PtVisible( HDC hdc, int x, int y ) { FIXUP_HANDLE(hdc); return(NtGdiPtVisible(hdc,x,y)); } /******************************Public*Routine******************************\ * RectVisible * * * * Client side stub. * * * * Thu 06-Jun-1991 00:58:46 -by- Charles Whitmer [chuckwh] * * Wrote it. * \**************************************************************************/ BOOL WINAPI RectVisible( HDC hdc, CONST RECT *prcl ) { FIXUP_HANDLE(hdc); return(NtGdiRectVisible(hdc,(LPRECT)prcl)); } /******************************Public*Routine******************************\ * * SetRectRgn checks for a user-mode portion of the region. If the * User-mode data is valid, the region is set to rect locally, otherwise * a kernel mode call is made to set the region * * Arguments: * * hrgn - app region handle * x1,y1,x2,y2 - app region data * * Return Value: * * BOOL status * \**************************************************************************/ BOOL WINAPI SetRectRgn( HRGN hrgn, int x1, int y1, int x2, int y2 ) { BOOL bStatus; PRGNATTR prRegion; // // if hrgn has a user-mode rectregion, then set // FIXUP_HANDLE(hrgn); PSHARED_GET_VALIDATE(prRegion,hrgn,RGN_TYPE); if (prRegion != NULL) { PRECTL prcl = &prRegion->Rect; if ((x1 == x2) || (y1 == y2)) { prRegion->Flags = NULLREGION; prcl->left = 0; prcl->top = 0; prcl->right = 0; prcl->bottom = 0; } else { // // assign and order rectangle // prcl->left = x1; prcl->top = y1; prcl->right = x2; prcl->bottom = y2; ORDER_PRECTL(prcl); // // set region flag // prRegion->Flags = SIMPLEREGION; } prRegion->AttrFlags |= ATTR_RGN_DIRTY; bStatus = TRUE; } else { bStatus = NtGdiSetRectRgn(hrgn,x1,y1,x2,y2); } return(bStatus); } /******************************Public*Routine******************************\ * GetRandomRgn * * Client side stub. * * 10-Mar-1992 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/ int APIENTRY GetRandomRgn(HDC hdc,HRGN hrgn,int iNum) { FIXUP_HANDLE(hdc); FIXUP_HANDLE(hrgn); return(NtGdiGetRandomRgn(hdc,hrgn,iNum)); } /******************************Public*Routine******************************\ * GetClipRgn * * * * Client side stub. * * * * Sat 08-Jun-1991 17:38:18 -by- Charles Whitmer [chuckwh] * * Wrote it. * \**************************************************************************/ int WINAPI GetClipRgn(HDC hdc,HRGN hrgn) { BOOL bRet; FIXUP_HANDLE(hdc); FIXUP_HANDLE(hrgn); bRet = NtGdiGetRandomRgn(hdc, hrgn, 1); if (hrgn && MIRRORED_HDC(hdc)) { MirrorRgnDC(hdc, hrgn, NULL); } return(bRet); } /******************************Public*Routine******************************\ * GetRegionData * * Download a region from the server * * History: * 29-Oct-1991 -by- Donald Sidoroff [donalds] * Wrote it. \**************************************************************************/ DWORD WINAPI GetRegionData( HRGN hrgn, DWORD nCount, LPRGNDATA lpRgnData ) { DWORD iRet; FIXUP_HANDLE(hrgn); // // If this is just an inquiry, pass over dummy parameters. // if (lpRgnData == (LPRGNDATA) NULL) { nCount = 0; } return(NtGdiGetRegionData(hrgn,nCount,lpRgnData)); } /******************************Public*Routine******************************\ * * Try to cache regions with user-mode rectregion defined * * Arguments: * * h - region handle * * Return Value: * * BOOL * * History: * * 21-Jun-1995 -by- Mark Enstrom [marke] * \**************************************************************************/ BOOL DeleteRegion( HRGN hRgn ) { PRGNATTR pRgnattr = NULL; BOOL bRet = FALSE; BEGIN_BATCH(BatchTypeDeleteRegion,BATCHDELETEREGION); PSHARED_GET_VALIDATE(pRgnattr,hRgn,RGN_TYPE); if (pRgnattr) { pBatch->hregion = hRgn; bRet = TRUE; } else { goto UNBATCHED_COMMAND; } COMPLETE_BATCH_COMMAND(); UNBATCHED_COMMAND: // // All other cases // if (!bRet) { bRet = NtGdiDeleteObjectApp(hRgn); } return(bRet); } /******************************Public*Routine******************************\ * SelectClipRgn * * Client side stub. * * History: * 01-Nov-1991 12:53:47 -by- Donald Sidoroff [donalds] * Now just call ExtSelectClipRgn \**************************************************************************/ int META WINAPI SelectClipRgn(HDC hdc,HRGN hrgn) { return(ExtSelectClipRgn(hdc, hrgn, RGN_COPY)); } /******************************Public*Routine******************************\ * * The ExtSelectClipRgn function combines the specified region with the * current clipping region by using the specified mode. * * Arguments: * * hdc - app DC handle * hrgn - app region handle * iMode - Select mode * * Return Value: * * If the function succeeds, the return value specifies the new clipping * region's complexity and can be any one of the following values: * * Value Meaning * NULLREGION Region is empty. * SIMPLEREGION Region is a single rectangle. * COMPLEXREGION Region is more than one rectangle. * ERROR An error occurred * * History: * * 21-Jun-1995 -by- Mark Enstrom [marke] * \**************************************************************************/ int META WINAPI ExtSelectClipRgn( HDC hdc, HRGN hrgn, int iMode ) { int iRet = RGN_ERROR; HRGN hrgnMirror = NULL; FIXUP_HANDLE(hdc); FIXUP_HANDLEZ(hrgn); // // Check Metafile // if (IS_ALTDC_TYPE(hdc)) { PLDC pldc; if (IS_METADC16_TYPE(hdc)) { return(MF16_SelectClipRgn(hdc,hrgn,iMode)); } DC_PLDC(hdc,pldc,iRet); if (pldc->iType == LO_METADC) { if (!MF_ExtSelectClipRgn(hdc,hrgn,iMode)) { return(iRet); } } } // // Attempt to batch ExtSelectClipRgn: // // The DC_ATTR structure has a copy of the current vis region // bounding rectangle, and the handle table has a flag indicating // whether this region is valid. // // Calls can be batched when the iMode is RGN_COPY and either // hrgn is NULL, or hrgn complexity is SIMPLE. (and the DC is not // a DIBSECTION DC) // // // FUTURE PERF: // // A check is made to determine if the region being selected // is the same as the last selected region. In this case, only the // correct return value needs to be calculated, no region changes // are needed. // // if (hrgn && MIRRORED_HDC(hdc)) { if (MirrorRgnDC(hdc, hrgn, &hrgnMirror) && hrgnMirror) { hrgn = hrgnMirror; } } if (iMode == RGN_COPY) { // // validate DC // BOOL bBatch = FALSE; PRGNATTR prRegion = NULL; PDC_ATTR pdca; PENTRY pDCEntry; PSHARED_GET_VALIDATE(pdca,hdc,DC_TYPE); // // check if call can be batched. DC must be valid,non-dibsection // DC and there must be room on the batch and same batch DC // BEGIN_BATCH_HDC(hdc,pdca,BatchTypeSelectClip,BATCHSELECTCLIP); pDCEntry = &pGdiSharedHandleTable[HANDLE_TO_INDEX(hdc)]; ASSERTGDI(pDCEntry,"pDCEntry must be valid when pdcattr is valid"); if (hrgn == NULL) { // // deleting the clip region, so the return complexity // will be the vis rgn complexity. Just batch the call. // if (!(pDCEntry->Flags & HMGR_ENTRY_INVALID_VIS)) { bBatch = TRUE; iRet = pdca->VisRectRegion.Flags; } } else { PSHARED_GET_VALIDATE(prRegion,hrgn,RGN_TYPE); // // pDCEntry must be valid because pdcattr is valid. // In order to batch, the user-mode RectRegion must // be valid and the complexity must be simple // if ( (prRegion) && (prRegion->Flags == SIMPLEREGION) && (!(prRegion->AttrFlags & ATTR_CACHED)) && !(pDCEntry->Flags & HMGR_ENTRY_INVALID_VIS) ) { // // Batch the call. // bBatch = TRUE; // // if the new clip region intersects the DC vis region, the // return value is SIMPLEREGION, otherwise it is NULLREGION // iRet = SIMPLEREGION; if ( (pdca->VisRectRegion.Rect.left >= prRegion->Rect.right) || (pdca->VisRectRegion.Rect.top >= prRegion->Rect.bottom) || (pdca->VisRectRegion.Rect.right <= prRegion->Rect.left) || (pdca->VisRectRegion.Rect.bottom <= prRegion->Rect.top) ) { iRet = NULLREGION; } } } // // if the call is to be batched, add to the batch // and return // if (!bBatch) { goto UNBATCHED_COMMAND; } if (hrgn == NULL) { iMode |= REGION_NULL_HRGN; } else { pBatch->rclClip.left = prRegion->Rect.left; pBatch->rclClip.top = prRegion->Rect.top; pBatch->rclClip.right = prRegion->Rect.right; pBatch->rclClip.bottom = prRegion->Rect.bottom; } pBatch->iMode = iMode; COMPLETE_BATCH_COMMAND(); goto BATCHED_COMMAND; } // // call kernel on fall-through and error cases // UNBATCHED_COMMAND: iRet = NtGdiExtSelectClipRgn(hdc,hrgn,iMode); BATCHED_COMMAND: if (hrgnMirror) { DeleteObject((HGDIOBJ)hrgnMirror); } return(iRet); } /******************************Public*Routine******************************\ * ExcludeClipRect * * * * Client side stub. * * * * History: * * Thu 06-Jun-1991 23:10:01 -by- Charles Whitmer [chuckwh] * * Wrote it. * \**************************************************************************/ int META WINAPI ExcludeClipRect( HDC hdc, int x1, int y1, int x2, int y2 ) { int iRet = RGN_ERROR; FIXUP_HANDLE(hdc); if (IS_ALTDC_TYPE(hdc)) { PLDC pldc; if (IS_METADC16_TYPE(hdc)) return(MF16_RecordParms5(hdc,x1,y1,x2,y2,META_EXCLUDECLIPRECT)); DC_PLDC(hdc,pldc,iRet); if (pldc->iType == LO_METADC) { if (!MF_AnyClipRect(hdc,x1,y1,x2,y2,EMR_EXCLUDECLIPRECT)) return(iRet); } } return(NtGdiExcludeClipRect(hdc,x1,y1,x2,y2)); } /******************************Public*Routine******************************\ * IntersectClipRect * * * * Client side stub. * * * * History: * * Thu 06-Jun-1991 23:10:01 -by- Charles Whitmer [chuckwh] * * Wrote it. * \**************************************************************************/ int META WINAPI IntersectClipRect( HDC hdc, int x1, int y1, int x2, int y2 ) { int iRet = RGN_ERROR; FIXUP_HANDLE(hdc); if (IS_ALTDC_TYPE(hdc)) { PLDC pldc; if (IS_METADC16_TYPE(hdc)) return(MF16_RecordParms5(hdc,x1,y1,x2,y2,META_INTERSECTCLIPRECT)); DC_PLDC(hdc,pldc,iRet); if (pldc->iType == LO_METADC) { if (!MF_AnyClipRect(hdc,x1,y1,x2,y2,EMR_INTERSECTCLIPRECT)) return(iRet); } } return(NtGdiIntersectClipRect(hdc,x1,y1,x2,y2)); }