📄 region.c
字号:
for (i = 0; i < srcObj->rdh.nCount; i++)
{
rc->left += x;
rc->right += x;
rc++;
}
REGION_IntersectRegion(destObj, destObj, srcObj);
/* Original region moved to left */
rc = (PRECT)srcObj->Buffer;
for (i = 0; i < srcObj->rdh.nCount; i++)
{
rc->left -= 2 * x;
rc->right -= 2 * x;
rc++;
}
REGION_IntersectRegion(destObj, destObj, srcObj);
/* Original region moved down */
rc = (PRECT)srcObj->Buffer;
for (i = 0; i < srcObj->rdh.nCount; i++)
{
rc->left += x;
rc->right += x;
rc->top += y;
rc->bottom += y;
rc++;
}
REGION_IntersectRegion(destObj, destObj, srcObj);
/* Original region moved up */
rc = (PRECT)srcObj->Buffer;
for (i = 0; i < srcObj->rdh.nCount; i++)
{
rc->top -= 2 * y;
rc->bottom -= 2 * y;
rc++;
}
REGION_IntersectRegion(destObj, destObj, srcObj);
/* Restore the original region */
rc = (PRECT)srcObj->Buffer;
for (i = 0; i < srcObj->rdh.nCount; i++)
{
rc->top += y;
rc->bottom += y;
rc++;
}
REGION_SubtractRegion(destObj, srcObj, destObj);
RGNDATA_UnlockRgn(destObj);
RGNDATA_UnlockRgn(srcObj);
return TRUE;
}
BOOL FASTCALL REGION_LPTODP(HDC hdc, HRGN hDest, HRGN hSrc)
{
RECT *pCurRect, *pEndRect;
PROSRGNDATA srcObj = NULL;
PROSRGNDATA destObj = NULL;
DC * dc = DC_LockDc(hdc);
RECT tmpRect;
BOOL ret = FALSE;
if(!dc)
return ret;
if(dc->Dc_Attr.iMapMode == MM_TEXT) // Requires only a translation
{
if(NtGdiCombineRgn(hDest, hSrc, 0, RGN_COPY) == ERROR)
goto done;
NtGdiOffsetRgn(hDest, dc->Dc_Attr.ptlViewportOrg.x - dc->Dc_Attr.ptlWindowOrg.x,
dc->Dc_Attr.ptlViewportOrg.y - dc->Dc_Attr.ptlWindowOrg.y);
ret = TRUE;
goto done;
}
if(!( srcObj = (PROSRGNDATA) RGNDATA_LockRgn( hSrc ) ))
goto done;
if(!( destObj = (PROSRGNDATA) RGNDATA_LockRgn( hDest ) ))
{
RGNDATA_UnlockRgn( srcObj );
goto done;
}
EMPTY_REGION(destObj);
pEndRect = (PRECT)srcObj->Buffer + srcObj->rdh.nCount;
for(pCurRect = (PRECT)srcObj->Buffer; pCurRect < pEndRect; pCurRect++)
{
tmpRect = *pCurRect;
tmpRect.left = XLPTODP(dc, tmpRect.left);
tmpRect.top = YLPTODP(dc, tmpRect.top);
tmpRect.right = XLPTODP(dc, tmpRect.right);
tmpRect.bottom = YLPTODP(dc, tmpRect.bottom);
if(tmpRect.left > tmpRect.right)
{ INT tmp = tmpRect.left; tmpRect.left = tmpRect.right; tmpRect.right = tmp; }
if(tmpRect.top > tmpRect.bottom)
{ INT tmp = tmpRect.top; tmpRect.top = tmpRect.bottom; tmpRect.bottom = tmp; }
REGION_UnionRectWithRegion(&tmpRect, destObj);
}
ret = TRUE;
RGNDATA_UnlockRgn( srcObj );
RGNDATA_UnlockRgn( destObj );
done:
DC_UnlockDc( dc );
return ret;
}
HRGN FASTCALL RGNDATA_AllocRgn(INT n)
{
HRGN hReg;
PROSRGNDATA pReg;
if ((hReg = (HRGN) GDIOBJ_AllocObj(GdiHandleTable, GDI_OBJECT_TYPE_REGION)))
{
if (NULL != (pReg = RGNDATA_LockRgn(hReg)))
{
if (1 == n)
{
/* Testing shows that > 95% of all regions have only 1 rect.
Including that here saves us from having to do another
allocation */
pReg->Buffer = &pReg->rdh.rcBound;
}
else
{
pReg->Buffer = ExAllocatePoolWithTag(PagedPool, n * sizeof(RECT), TAG_REGION);
}
if (NULL != pReg->Buffer)
{
EMPTY_REGION(pReg);
pReg->rdh.dwSize = sizeof(RGNDATAHEADER);
pReg->rdh.nCount = n;
pReg->rdh.nRgnSize = n*sizeof(RECT);
RGNDATA_UnlockRgn(pReg);
return hReg;
}
}
else
{
RGNDATA_FreeRgn(hReg);
}
}
return NULL;
}
BOOL INTERNAL_CALL
RGNDATA_Cleanup(PVOID ObjectBody)
{
PROSRGNDATA pRgn = (PROSRGNDATA)ObjectBody;
if(pRgn->Buffer && pRgn->Buffer != &pRgn->rdh.rcBound)
ExFreePool(pRgn->Buffer);
return TRUE;
}
// NtGdi Exported Functions
INT
STDCALL
NtGdiCombineRgn(HRGN hDest,
HRGN hSrc1,
HRGN hSrc2,
INT CombineMode)
{
INT result = ERROR;
PROSRGNDATA destRgn, src1Rgn, src2Rgn;
destRgn = RGNDATA_LockRgn(hDest);
if( destRgn )
{
src1Rgn = RGNDATA_LockRgn(hSrc1);
if( src1Rgn )
{
if (CombineMode == RGN_COPY)
{
if( !REGION_CopyRegion(destRgn, src1Rgn) )
return ERROR;
result = destRgn->rdh.iType;
}
else
{
src2Rgn = RGNDATA_LockRgn(hSrc2);
if( src2Rgn )
{
switch (CombineMode)
{
case RGN_AND:
REGION_IntersectRegion(destRgn, src1Rgn, src2Rgn);
break;
case RGN_OR:
REGION_UnionRegion(destRgn, src1Rgn, src2Rgn);
break;
case RGN_XOR:
REGION_XorRegion(destRgn, src1Rgn, src2Rgn);
break;
case RGN_DIFF:
REGION_SubtractRegion(destRgn, src1Rgn, src2Rgn);
break;
}
RGNDATA_UnlockRgn(src2Rgn);
result = destRgn->rdh.iType;
}
else if(hSrc2 == NULL)
{
DPRINT1("NtGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode);
}
}
RGNDATA_UnlockRgn(src1Rgn);
}
RGNDATA_UnlockRgn(destRgn);
}
else
{
DPRINT("NtGdiCombineRgn: hDest unavailable\n");
result = ERROR;
}
return result;
}
HRGN
STDCALL
NtGdiCreateEllipticRgn(INT Left,
INT Top,
INT Right,
INT Bottom)
{
return NtGdiCreateRoundRectRgn(Left, Top, Right, Bottom,
Right - Left, Bottom - Top);
}
HRGN STDCALL
NtGdiCreateRectRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
{
HRGN hRgn;
/* Allocate region data structure with space for 1 RECT */
if ((hRgn = RGNDATA_AllocRgn(1)))
{
if (NtGdiSetRectRgn(hRgn, LeftRect, TopRect, RightRect, BottomRect))
return hRgn;
NtGdiDeleteObject(hRgn);
}
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
HRGN
STDCALL
NtGdiCreateRoundRectRgn(INT left, INT top, INT right, INT bottom,
INT ellipse_width, INT ellipse_height)
{
PROSRGNDATA obj;
HRGN hrgn;
int asq, bsq, d, xd, yd;
RECT rect;
/* Make the dimensions sensible */
if (left > right) { INT tmp = left; left = right; right = tmp; }
if (top > bottom) { INT tmp = top; top = bottom; bottom = tmp; }
ellipse_width = abs(ellipse_width);
ellipse_height = abs(ellipse_height);
/* Check parameters */
if (ellipse_width > right-left) ellipse_width = right-left;
if (ellipse_height > bottom-top) ellipse_height = bottom-top;
/* Check if we can do a normal rectangle instead */
if ((ellipse_width < 2) || (ellipse_height < 2))
return NtGdiCreateRectRgn( left, top, right, bottom );
/* Create region */
d = (ellipse_height < 128) ? ((3 * ellipse_height) >> 2) : 64;
if (!(hrgn = RGNDATA_AllocRgn(d))) return 0;
if (!(obj = RGNDATA_LockRgn(hrgn))) return 0;
/* Ellipse algorithm, based on an article by K. Porter */
/* in DDJ Graphics Programming Column, 8/89 */
asq = ellipse_width * ellipse_width / 4; /* a^2 */
bsq = ellipse_height * ellipse_height / 4; /* b^2 */
d = bsq - asq * ellipse_height / 2 + asq / 4; /* b^2 - a^2b + a^2/4 */
xd = 0;
yd = asq * ellipse_height; /* 2a^2b */
rect.left = left + ellipse_width / 2;
rect.right = right - ellipse_width / 2;
/* Loop to draw first half of quadrant */
while (xd < yd)
{
if (d > 0) /* if nearest pixel is toward the center */
{
/* move toward center */
rect.top = top++;
rect.bottom = rect.top + 1;
UnsafeIntUnionRectWithRgn( obj, &rect );
rect.top = --bottom;
rect.bottom = rect.top + 1;
UnsafeIntUnionRectWithRgn( obj, &rect );
yd -= 2*asq;
d -= yd;
}
rect.left--; /* next horiz point */
rect.right++;
xd += 2*bsq;
d += bsq + xd;
}
/* Loop to draw second half of quadrant */
d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
while (yd >= 0)
{
/* next vertical point */
rect.top = top++;
rect.bottom = rect.top + 1;
UnsafeIntUnionRectWithRgn( obj, &rect );
rect.top = --bottom;
rect.bottom = rect.top + 1;
UnsafeIntUnionRectWithRgn( obj, &rect );
if (d < 0) /* if nearest pixel is outside ellipse */
{
rect.left--; /* move away from center */
rect.right++;
xd += 2*bsq;
d += xd;
}
yd -= 2*asq;
d += asq - yd;
}
/* Add the inside rectangle */
if (top <= bottom)
{
rect.top = top;
rect.bottom = bottom;
UnsafeIntUnionRectWithRgn( obj, &rect );
}
RGNDATA_UnlockRgn( obj );
return hrgn;
}
BOOL
STDCALL
NtGdiEqualRgn(HRGN hSrcRgn1,
HRGN hSrcRgn2)
{
PROSRGNDATA rgn1, rgn2;
PRECT tRect1, tRect2;
ULONG i;
BOOL bRet = FALSE;
if( !(rgn1 = RGNDATA_LockRgn(hSrcRgn1)))
return ERROR;
if( !(rgn2 = RGNDATA_LockRgn(hSrcRgn2))){
RGNDATA_UnlockRgn( rgn1 );
return ERROR;
}
if(rgn1->rdh.nCount != rgn2->rdh.nCount ||
rgn1->rdh.nCount == 0 ||
rgn1->rdh.rcBound.left != rgn2->rdh.rcBound.left ||
rgn1->rdh.rcBound.right != rgn2->rdh.rcBound.right ||
rgn1->rdh.rcBound.top != rgn2->rdh.rcBound.top ||
rgn1->rdh.rcBound.bottom != rgn2->rdh.rcBound.bottom)
goto exit;
tRect1 = (PRECT)rgn1->Buffer;
tRect2 = (PRECT)rgn2->Buffer;
if( !tRect1 || !tRect2 )
goto exit;
for(i=0; i < rgn1->rdh.nCount; i++)
{
if(tRect1[i].left != tRect2[i].left ||
tRect1[i].right != tRect2[i].right ||
tRect1[i].top != tRect2[i].top ||
tRect1[i].bottom != tRect2[i].bottom)
goto exit;
}
bRet = TRUE;
exit:
RGNDATA_UnlockRgn( rgn1 );
RGNDATA_UnlockRgn( rgn2 );
return bRet;
}
HRGN
STDCALL
NtGdiExtCreateRegion(OPTIONAL LPXFORM Xform,
DWORD Count,
LPRGNDATA RgnData)
{
HRGN hRgn;
PROSRGNDATA Region;
DWORD nCount = 0;
NTSTATUS Status = STATUS_SUCCESS;
if (Count < FIELD_OFFSET(RGNDATA, Buffer))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return NULL;
}
_SEH_TRY
{
ProbeForRead(RgnData,
Count,
1);
nCount = RgnData->rdh.nCount;
if((Count - FIELD_OFFSET(RGNDATA, Buffer)) / sizeof(RECT) < nCount)
{
Status = STATUS_INVALID_PARAMETER;
_SEH_LEAVE;
}
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -