📄 region.c
字号:
*/
VOID FASTCALL
IntDumpRegion(HRGN hRgn)
{
ROSRGNDATA *Data;
Data = RGNDATA_LockRgn(hRgn);
if (Data == NULL)
{
DbgPrint("IntDumpRegion called with invalid region!\n");
return;
}
DbgPrint("IntDumpRegion(%x): %d,%d-%d,%d %d\n",
hRgn,
Data->rdh.rcBound.left,
Data->rdh.rcBound.top,
Data->rdh.rcBound.right,
Data->rdh.rcBound.bottom,
Data->rdh.iType);
RGNDATA_UnlockRgn(Data);
}
#endif /* NDEBUG */
static BOOL FASTCALL REGION_CopyRegion(PROSRGNDATA dst, PROSRGNDATA src)
{
if(dst != src) // don't want to copy to itself
{
if (dst->rdh.nRgnSize < src->rdh.nCount * sizeof(RECT))
{
PRECT temp;
temp = ExAllocatePoolWithTag(PagedPool, src->rdh.nCount * sizeof(RECT), TAG_REGION );
if( !temp )
return FALSE;
if( dst->Buffer && dst->Buffer != &dst->rdh.rcBound )
ExFreePool( dst->Buffer ); //free the old buffer
dst->Buffer = temp;
dst->rdh.nRgnSize = src->rdh.nCount * sizeof(RECT); //size of region buffer
}
dst->rdh.nCount = src->rdh.nCount; //number of rectangles present in Buffer
dst->rdh.rcBound.left = src->rdh.rcBound.left;
dst->rdh.rcBound.top = src->rdh.rcBound.top;
dst->rdh.rcBound.right = src->rdh.rcBound.right;
dst->rdh.rcBound.bottom = src->rdh.rcBound.bottom;
dst->rdh.iType = src->rdh.iType;
COPY_RECTS(dst->Buffer, src->Buffer, src->rdh.nCount);
}
return TRUE;
}
static void FASTCALL REGION_SetExtents (ROSRGNDATA *pReg)
{
RECT *pRect, *pRectEnd, *pExtents;
if (pReg->rdh.nCount == 0)
{
pReg->rdh.rcBound.left = 0;
pReg->rdh.rcBound.top = 0;
pReg->rdh.rcBound.right = 0;
pReg->rdh.rcBound.bottom = 0;
pReg->rdh.iType = NULLREGION;
return;
}
pExtents = &pReg->rdh.rcBound;
pRect = (PRECT)pReg->Buffer;
pRectEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount - 1;
/*
* Since pRect is the first rectangle in the region, it must have the
* smallest top and since pRectEnd is the last rectangle in the region,
* it must have the largest bottom, because of banding. Initialize left and
* right from pRect and pRectEnd, resp., as good things to initialize them
* to...
*/
pExtents->left = pRect->left;
pExtents->top = pRect->top;
pExtents->right = pRectEnd->right;
pExtents->bottom = pRectEnd->bottom;
while (pRect <= pRectEnd)
{
if (pRect->left < pExtents->left)
pExtents->left = pRect->left;
if (pRect->right > pExtents->right)
pExtents->right = pRect->right;
pRect++;
}
pReg->rdh.iType = (1 == pReg->rdh.nCount ? SIMPLEREGION : COMPLEXREGION);
}
/***********************************************************************
* REGION_CropAndOffsetRegion
*/
static BOOL FASTCALL REGION_CropAndOffsetRegion(const PPOINT off, const PRECT rect, PROSRGNDATA rgnSrc, PROSRGNDATA rgnDst)
{
if(!rect) // just copy and offset
{
PRECT xrect;
if(rgnDst == rgnSrc)
{
if(off->x || off->y)
xrect = (PRECT)rgnDst->Buffer;
else
return TRUE;
}
else{
xrect = ExAllocatePoolWithTag(PagedPool, rgnSrc->rdh.nCount * sizeof(RECT), TAG_REGION);
if( rgnDst->Buffer && rgnDst->Buffer != &rgnDst->rdh.rcBound )
ExFreePool( rgnDst->Buffer ); //free the old buffer. will be assigned to xrect below.
}
if(xrect)
{
ULONG i;
if(rgnDst != rgnSrc)
{
*rgnDst = *rgnSrc;
}
if(off->x || off->y)
{
for(i = 0; i < rgnDst->rdh.nCount; i++)
{
xrect[i].left = ((PRECT)rgnSrc->Buffer + i)->left + off->x;
xrect[i].right = ((PRECT)rgnSrc->Buffer + i)->right + off->x;
xrect[i].top = ((PRECT)rgnSrc->Buffer + i)->top + off->y;
xrect[i].bottom = ((PRECT)rgnSrc->Buffer + i)->bottom + off->y;
}
rgnDst->rdh.rcBound.left += off->x;
rgnDst->rdh.rcBound.right += off->x;
rgnDst->rdh.rcBound.top += off->y;
rgnDst->rdh.rcBound.bottom += off->y;
}
else
{
COPY_RECTS(xrect, rgnSrc->Buffer, rgnDst->rdh.nCount);
}
rgnDst->Buffer = xrect;
} else
return FALSE;
}
else if ((rect->left >= rect->right) ||
(rect->top >= rect->bottom) ||
!EXTENTCHECK(rect, &rgnSrc->rdh.rcBound))
{
goto empty;
}
else // region box and clipping rect appear to intersect
{
PRECT lpr, rpr;
ULONG i, j, clipa, clipb;
INT left = rgnSrc->rdh.rcBound.right + off->x;
INT right = rgnSrc->rdh.rcBound.left + off->x;
for(clipa = 0; ((PRECT)rgnSrc->Buffer + clipa)->bottom <= rect->top; clipa++)
//region and rect intersect so we stop before clipa > rgnSrc->rdh.nCount
; // skip bands above the clipping rectangle
for(clipb = clipa; clipb < rgnSrc->rdh.nCount; clipb++)
if(((PRECT)rgnSrc->Buffer + clipb)->top >= rect->bottom)
break; // and below it
// clipa - index of the first rect in the first intersecting band
// clipb - index of the last rect in the last intersecting band
if((rgnDst != rgnSrc) && (rgnDst->rdh.nCount < (i = (clipb - clipa))))
{
PRECT temp;
temp = ExAllocatePoolWithTag( PagedPool, i * sizeof(RECT), TAG_REGION );
if(!temp)
return FALSE;
if( rgnDst->Buffer && rgnDst->Buffer != &rgnDst->rdh.rcBound )
ExFreePool( rgnDst->Buffer ); //free the old buffer
rgnDst->Buffer = temp;
rgnDst->rdh.nCount = i;
rgnDst->rdh.nRgnSize = i * sizeof(RECT);
}
for(i = clipa, j = 0; i < clipb ; i++)
{
// i - src index, j - dst index, j is always <= i for obvious reasons
lpr = (PRECT)rgnSrc->Buffer + i;
if(lpr->left < rect->right && lpr->right > rect->left)
{
rpr = (PRECT)rgnDst->Buffer + j;
rpr->top = lpr->top + off->y;
rpr->bottom = lpr->bottom + off->y;
rpr->left = ((lpr->left > rect->left) ? lpr->left : rect->left) + off->x;
rpr->right = ((lpr->right < rect->right) ? lpr->right : rect->right) + off->x;
if(rpr->left < left) left = rpr->left;
if(rpr->right > right) right = rpr->right;
j++;
}
}
if(j == 0) goto empty;
rgnDst->rdh.rcBound.left = left;
rgnDst->rdh.rcBound.right = right;
left = rect->top + off->y;
right = rect->bottom + off->y;
rgnDst->rdh.nCount = j--;
for(i = 0; i <= j; i++) // fixup top band
if((rgnDst->Buffer + i)->top < left)
(rgnDst->Buffer + i)->top = left;
else
break;
for(i = j; i >= 0; i--) // fixup bottom band
if(((PRECT)rgnDst->Buffer + i)->bottom > right)
((PRECT)rgnDst->Buffer + i)->bottom = right;
else
break;
rgnDst->rdh.rcBound.top = ((PRECT)rgnDst->Buffer)->top;
rgnDst->rdh.rcBound.bottom = ((PRECT)rgnDst->Buffer + j)->bottom;
rgnDst->rdh.iType = (j >= 1) ? COMPLEXREGION : SIMPLEREGION;
}
return TRUE;
empty:
if(!rgnDst->Buffer)
{
rgnDst->Buffer = (PRECT)ExAllocatePoolWithTag(PagedPool, RGN_DEFAULT_RECTS * sizeof(RECT), TAG_REGION);
if(rgnDst->Buffer){
rgnDst->rdh.nCount = RGN_DEFAULT_RECTS;
rgnDst->rdh.nRgnSize = RGN_DEFAULT_RECTS * sizeof(RECT);
}
else
return FALSE;
}
EMPTY_REGION(rgnDst);
return TRUE;
}
/*!
* \param
* hSrc: Region to crop and offset.
* lpRect: Clipping rectangle. Can be NULL (no clipping).
* lpPt: Points to offset the cropped region. Can be NULL (no offset).
*
* hDst: Region to hold the result (a new region is created if it's 0).
* Allowed to be the same region as hSrc in which case everything
* will be done in place, with no memory reallocations.
*
* \return hDst if success, 0 otherwise.
*/
HRGN FASTCALL REGION_CropRgn(HRGN hDst, HRGN hSrc, const PRECT lpRect, PPOINT lpPt)
{
PROSRGNDATA objSrc, rgnDst;
HRGN hRet = NULL;
POINT pt = { 0, 0 };
if( !hDst )
{
if( !( hDst = RGNDATA_AllocRgn(1) ) )
{
return 0;
}
}
rgnDst = RGNDATA_LockRgn(hDst);
if(rgnDst == NULL)
{
return NULL;
}
objSrc = RGNDATA_LockRgn(hSrc);
if(objSrc == NULL)
{
RGNDATA_UnlockRgn(rgnDst);
return NULL;
}
if(!lpPt)
lpPt = &pt;
if(REGION_CropAndOffsetRegion(lpPt, lpRect, objSrc, rgnDst) == FALSE)
{ // ve failed cleanup and return
hRet = NULL;
}
else{ // ve are fine. unlock the correct pointer and return correct handle
hRet = hDst;
}
RGNDATA_UnlockRgn(objSrc);
RGNDATA_UnlockRgn(rgnDst);
return hRet;
}
/*!
* Attempt to merge the rects in the current band with those in the
* previous one. Used only by REGION_RegionOp.
*
* Results:
* The new index for the previous band.
*
* \note Side Effects:
* If coalescing takes place:
* - rectangles in the previous band will have their bottom fields
* altered.
* - pReg->numRects will be decreased.
*
*/
static INT FASTCALL REGION_Coalesce (
PROSRGNDATA pReg, /* Region to coalesce */
INT prevStart, /* Index of start of previous band */
INT curStart /* Index of start of current band */
) {
RECT *pPrevRect; /* Current rect in previous band */
RECT *pCurRect; /* Current rect in current band */
RECT *pRegEnd; /* End of region */
INT curNumRects; /* Number of rectangles in current band */
INT prevNumRects; /* Number of rectangles in previous band */
INT bandtop; /* top coordinate for current band */
pRegEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount;
pPrevRect = (PRECT)pReg->Buffer + prevStart;
prevNumRects = curStart - prevStart;
/*
* Figure out how many rectangles are in the current band. Have to do
* this because multiple bands could have been added in REGION_RegionOp
* at the end when one region has been exhausted.
*/
pCurRect = (PRECT)pReg->Buffer + curStart;
bandtop = pCurRect->top;
for (curNumRects = 0;
(pCurRect != pRegEnd) && (pCurRect->top == bandtop);
curNumRects++)
{
pCurRect++;
}
if (pCurRect != pRegEnd)
{
/*
* If more than one band was added, we have to find the start
* of the last band added so the next coalescing job can start
* at the right place... (given when multiple bands are added,
* this may be pointless -- see above).
*/
pRegEnd--;
while ((pRegEnd-1)->top == pRegEnd->top)
{
pRegEnd--;
}
curStart = pRegEnd - (PRECT)pReg->Buffer;
pRegEnd = (PRECT)pReg->Buffer + pReg->rdh.nCount;
}
if ((curNumRects == prevNumRects) && (curNumRects != 0)) {
pCurRect -= curNumRects;
/*
* The bands may only be coalesced if the bottom of the previous
* matches the top scanline of the current.
*/
if (pPrevRect->bottom == pCurRect->top)
{
/*
* Make sure the bands have rects in the same places. This
* assumes that rects have been added in such a way that they
* cover the most area possible. I.e. two rects in a band must
* have some horizontal space between them.
*/
do
{
if ((pPrevRect->left != pCurRect->left) ||
(pPrevRect->right != pCurRect->right))
{
/*
* The bands don't line up so they can't be coalesced.
*/
return (curStart);
}
pPrevRect++;
pCurRect++;
prevNumRects -= 1;
} while (prevNumRects != 0);
pReg->rdh.nCount -= curNumRects;
pCurRect -= curNumRects;
pPrevRect -= curNumRects;
/*
* The bands may be merged, so set the bottom of each rect
* in the previous band to that of the corresponding rect in
* the current band.
*/
do
{
pPrevRect->bottom = pCurRect->bottom;
pPrevRect++;
pCurRect++;
curNumRects -= 1;
} while (curNumRects != 0);
/*
* If only one band was added to the region, we have to backup
* curStart to the start of the previous band.
*
* If more than one band was added to the region, copy the
* other bands down. The assumption here is that the other bands
* came from the same region as the current one and no further
* coalescing can be done on them since it's all been done
* already... curStart is already in the right place.
*/
if (pCurRect == pRegEnd)
{
curStart = prevStart;
}
else
{
do
{
*pPrevRect++ = *pCurRect++;
} while (pCurRect != pRegEnd);
}
}
}
return (curStart);
}
/*!
* Apply an operation to two regions. Called by REGION_Union,
* REGION_Inverse, REGION_Subtract, REGION_Intersect...
*
* Results:
* None.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -