You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1503 lines
37 KiB
1503 lines
37 KiB
|
|
/******************************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; i<nRects; i++){
|
|
for (j=i+1; (j<nRects) && ((lpR+j)->top == (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; i<nRects; i++){
|
|
Saveleft = lpR->left;
|
|
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));
|
|
|
|
}
|