diff --git a/win32ss/gdi/ntgdi/region.c b/win32ss/gdi/ntgdi/region.c index 79712182c71..1456602852d 100644 --- a/win32ss/gdi/ntgdi/region.c +++ b/win32ss/gdi/ntgdi/region.c @@ -113,6 +113,14 @@ SOFTWARE. * the y-x-banding that's so nice to have... */ +// X11 sources for ReactOS region processing. +// +// libX11/src/PolyReg.c +// libX11/src/Region.c +// +// + + #include #include @@ -402,8 +410,8 @@ typedef struct _SCANLINE_LISTBLOCK * *************************************************************************/ -#define LARGE_COORDINATE 0x7fffffff /* FIXME */ -#define SMALL_COORDINATE 0x80000000 +#define LARGE_COORDINATE INT_MAX +#define SMALL_COORDINATE INT_MIN static BOOL @@ -509,8 +517,8 @@ REGION_bAddRect( return TRUE; } -typedef VOID (FASTCALL *overlapProcp)(PREGION, PRECT, PRECT, PRECT, PRECT, INT, INT); -typedef VOID (FASTCALL *nonOverlapProcp)(PREGION, PRECT, PRECT, INT, INT); +typedef BOOL (FASTCALL *overlapProcp)(PREGION, PRECT, PRECT, PRECT, PRECT, INT, INT); +typedef BOOL (FASTCALL *nonOverlapProcp)(PREGION, PRECT, PRECT, INT, INT); // Number of points to buffer before sending them off to scanlines() : Must be an even number #define NUMPTSTOBUFFER 200 @@ -947,7 +955,7 @@ REGION_Coalesce( * */ static -VOID +BOOL FASTCALL REGION_RegionOp( PREGION newReg, /* Place to store result */ @@ -1001,7 +1009,7 @@ REGION_RegionOp( if (newReg->Buffer == NULL) { newReg->rdh.nRgnSize = 0; - return; + return FALSE; } /* Initialize ybot and ytop. @@ -1062,7 +1070,7 @@ REGION_RegionOp( if ((top != bot) && (nonOverlap1Func != NULL)) { - (*nonOverlap1Func)(newReg, r1, r1BandEnd, top, bot); + if (!(*nonOverlap1Func)(newReg, r1, r1BandEnd, top, bot)) return FALSE; } ytop = r2->top; @@ -1074,7 +1082,7 @@ REGION_RegionOp( if ((top != bot) && (nonOverlap2Func != NULL)) { - (*nonOverlap2Func)(newReg, r2, r2BandEnd, top, bot); + if (!(*nonOverlap2Func)(newReg, r2, r2BandEnd, top, bot) ) return FALSE; } ytop = r1->top; @@ -1099,7 +1107,7 @@ REGION_RegionOp( curBand = newReg->rdh.nCount; if (ybot > ytop) { - (*overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot); + if (!(*overlapFunc)(newReg, r1, r1BandEnd, r2, r2BandEnd, ytop, ybot)) return FALSE; } if (newReg->rdh.nCount != curBand) @@ -1134,11 +1142,12 @@ REGION_RegionOp( r1BandEnd++; } - (*nonOverlap1Func)(newReg, + if (!(*nonOverlap1Func)(newReg, r1, r1BandEnd, max(r1->top,ybot), - r1->bottom); + r1->bottom)) + return FALSE; r1 = r1BandEnd; } while (r1 != r1End); @@ -1154,11 +1163,12 @@ REGION_RegionOp( r2BandEnd++; } - (*nonOverlap2Func)(newReg, + if (!(*nonOverlap2Func)(newReg, r2, r2BandEnd, max(r2->top,ybot), - r2->bottom); + r2->bottom)) + return FALSE; r2 = r2BandEnd; } while (r2 != r2End); @@ -1216,7 +1226,7 @@ REGION_RegionOp( if (oldRects != &newReg->rdh.rcBound) ExFreePoolWithTag(oldRects, TAG_REGION); - return; + return TRUE; } /*********************************************************************** @@ -1235,7 +1245,7 @@ REGION_RegionOp( * */ static -VOID +BOOL FASTCALL REGION_IntersectO( PREGION pReg, @@ -1262,7 +1272,7 @@ REGION_IntersectO( { if (!REGION_bAddRect(pReg, left, top, right, bottom)) { - return; + return FALSE; } } @@ -1284,14 +1294,14 @@ REGION_IntersectO( } } - return; + return TRUE; } /*********************************************************************** * REGION_IntersectRegion */ static -VOID +BOOL FASTCALL REGION_IntersectRegion( PREGION newReg, @@ -1307,12 +1317,13 @@ REGION_IntersectRegion( } else { - REGION_RegionOp(newReg, + if (!REGION_RegionOp(newReg, reg1, reg2, REGION_IntersectO, NULL, - NULL); + NULL)) + return FALSE; } /* Can't alter newReg's extents before we call miRegionOp because @@ -1321,6 +1332,7 @@ REGION_IntersectRegion( * way there's no checking against rectangles that will be nuked * due to coalescing, so we have to examine fewer rectangles. */ REGION_SetExtents(newReg); + return TRUE; } /*********************************************************************** @@ -1341,7 +1353,7 @@ REGION_IntersectRegion( * */ static -VOID +BOOL FASTCALL REGION_UnionNonO( PREGION pReg, @@ -1354,7 +1366,7 @@ REGION_UnionNonO( { if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (rEnd - r))) { - return; + return FALSE; } do @@ -1365,7 +1377,7 @@ REGION_UnionNonO( while (r != rEnd); } - return; + return TRUE; } static __inline @@ -1411,7 +1423,7 @@ REGION_bMergeRect( * */ static -VOID +BOOL FASTCALL REGION_UnionO ( PREGION pReg, @@ -1426,12 +1438,12 @@ REGION_UnionO ( { if (r1->left < r2->left) { - REGION_bMergeRect(pReg, r1->left, top, r1->right, bottom); + if (!REGION_bMergeRect(pReg, r1->left, top, r1->right, bottom)) return FALSE; r1++; } else { - REGION_bMergeRect(pReg, r2->left, top, r2->right, bottom); + if (!REGION_bMergeRect(pReg, r2->left, top, r2->right, bottom)) return FALSE; r2++; } } @@ -1440,7 +1452,7 @@ REGION_UnionO ( { do { - REGION_bMergeRect(pReg, r1->left, top, r1->right, bottom); + if (!REGION_bMergeRect(pReg, r1->left, top, r1->right, bottom)) return FALSE; r1++; } while (r1 != r1End); @@ -1449,25 +1461,27 @@ REGION_UnionO ( { while (r2 != r2End) { - REGION_bMergeRect(pReg, r2->left, top, r2->right, bottom); + if (!REGION_bMergeRect(pReg, r2->left, top, r2->right, bottom)) return FALSE; r2++; } } - return; + return TRUE; } /*********************************************************************** * REGION_UnionRegion */ static -VOID +BOOL FASTCALL REGION_UnionRegion( PREGION newReg, PREGION reg1, PREGION reg2) { + BOOL ret = TRUE; + /* Checks all the simple cases * Region 1 and 2 are the same or region 1 is empty */ if ((reg1 == reg2) || (reg1->rdh.nCount == 0) || @@ -1476,10 +1490,10 @@ REGION_UnionRegion( { if (newReg != reg2) { - REGION_CopyRegion(newReg, reg2); + ret = REGION_CopyRegion(newReg, reg2); } - return; + return ret; } /* If nothing to union (region 2 empty) */ @@ -1489,10 +1503,10 @@ REGION_UnionRegion( { if (newReg != reg1) { - REGION_CopyRegion(newReg, reg1); + ret = REGION_CopyRegion(newReg, reg1); } - return; + return ret; } /* Region 1 completely subsumes region 2 */ @@ -1504,10 +1518,10 @@ REGION_UnionRegion( { if (newReg != reg1) { - REGION_CopyRegion(newReg, reg1); + ret = REGION_CopyRegion(newReg, reg1); } - return; + return ret; } /* Region 2 completely subsumes region 1 */ @@ -1519,23 +1533,25 @@ REGION_UnionRegion( { if (newReg != reg2) { - REGION_CopyRegion(newReg, reg2); + ret = REGION_CopyRegion(newReg, reg2); } - return; + return ret; } - REGION_RegionOp(newReg, + if ((ret = REGION_RegionOp(newReg, reg1, reg2, REGION_UnionO, REGION_UnionNonO, - REGION_UnionNonO); - + REGION_UnionNonO))) + { newReg->rdh.rcBound.left = min(reg1->rdh.rcBound.left, reg2->rdh.rcBound.left); newReg->rdh.rcBound.top = min(reg1->rdh.rcBound.top, reg2->rdh.rcBound.top); newReg->rdh.rcBound.right = max(reg1->rdh.rcBound.right, reg2->rdh.rcBound.right); newReg->rdh.rcBound.bottom = max(reg1->rdh.rcBound.bottom, reg2->rdh.rcBound.bottom); + } + return ret; } /*********************************************************************** @@ -1554,7 +1570,7 @@ REGION_UnionRegion( * */ static -VOID +BOOL FASTCALL REGION_SubtractNonO1( PREGION pReg, @@ -1567,7 +1583,7 @@ REGION_SubtractNonO1( { if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (rEnd - r))) { - return; + return FALSE; } do @@ -1578,7 +1594,7 @@ REGION_SubtractNonO1( while (r != rEnd); } - return; + return TRUE; } @@ -1594,7 +1610,7 @@ REGION_SubtractNonO1( * */ static -VOID +BOOL FASTCALL REGION_SubtractO( PREGION pReg, @@ -1641,7 +1657,7 @@ REGION_SubtractO( * part of minuend to region and skip to next subtrahend. */ if (!REGION_bAddRect(pReg, left, top, r2->left, bottom)) { - return; + return FALSE; } left = r2->right; @@ -1665,7 +1681,7 @@ REGION_SubtractO( { if (!REGION_bAddRect(pReg, left, top, r1->right, bottom)) { - return; + return FALSE; } } @@ -1680,7 +1696,7 @@ REGION_SubtractO( { if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (r1End - r1))) { - return; + return FALSE; } /* Add remaining minuend rectangles to region. */ @@ -1696,7 +1712,7 @@ REGION_SubtractO( while (r1 != r1End); } - return; + return TRUE; } /*! @@ -1711,7 +1727,7 @@ REGION_SubtractO( * */ static -VOID +BOOL FASTCALL REGION_SubtractRegion( PREGION regD, @@ -1723,16 +1739,16 @@ REGION_SubtractRegion( (regS->rdh.nCount == 0) || (EXTENTCHECK(®M->rdh.rcBound, ®S->rdh.rcBound) == 0)) { - REGION_CopyRegion(regD, regM); - return; + return REGION_CopyRegion(regD, regM); } - REGION_RegionOp(regD, + if (!REGION_RegionOp(regD, regM, regS, REGION_SubtractO, REGION_SubtractNonO1, - NULL); + NULL)) + return FALSE; /* Can't alter newReg's extents before we call miRegionOp because * it might be one of the source regions and miRegionOp depends @@ -1740,13 +1756,14 @@ REGION_SubtractRegion( * way there's no checking against rectangles that will be nuked * due to coalescing, so we have to examine fewer rectangles. */ REGION_SetExtents(regD); + return TRUE; } /*********************************************************************** * REGION_XorRegion */ static -VOID +BOOL FASTCALL REGION_XorRegion( PREGION dr, @@ -1755,12 +1772,13 @@ REGION_XorRegion( { HRGN htra, htrb; PREGION tra, trb; + BOOL ret; // FIXME: Don't use a handle tra = REGION_AllocRgnWithHandle(sra->rdh.nCount + 1); if (tra == NULL) { - return; + return FALSE; } htra = tra->BaseObject.hHmgr; @@ -1770,26 +1788,26 @@ REGION_XorRegion( { REGION_UnlockRgn(tra); GreDeleteObject(htra); - return; + return FALSE; } htrb = trb->BaseObject.hHmgr; - REGION_SubtractRegion(tra, sra, srb); - REGION_SubtractRegion(trb, srb, sra); - REGION_UnionRegion(dr, tra, trb); + ret = REGION_SubtractRegion(tra, sra, srb) && + REGION_SubtractRegion(trb, srb, sra) && + REGION_UnionRegion(dr, tra, trb); REGION_UnlockRgn(tra); REGION_UnlockRgn(trb); GreDeleteObject(htra); GreDeleteObject(htrb); - return; + return ret; } /*! * Adds a rectangle to a REGION */ -VOID +BOOL FASTCALL REGION_UnionRectWithRgn( PREGION rgn, @@ -1801,7 +1819,7 @@ REGION_UnionRectWithRgn( region.rdh.nCount = 1; region.rdh.nRgnSize = sizeof(RECT); region.rdh.rcBound = *rect; - REGION_UnionRegion(rgn, rgn, ®ion); + return REGION_UnionRegion(rgn, rgn, ®ion); } INT @@ -1821,6 +1839,27 @@ REGION_SubtractRectFromRgn( return REGION_Complexity(prgnDest); } +BOOL +FASTCALL +REGION_bCopy( + PREGION dst, + PREGION src) +{ + if ( !dst || !src ) return FALSE; + return REGION_CopyRegion( dst, src); +} + +BOOL +FASTCALL +REGION_bIntersectRegion( + PREGION newReg, + PREGION reg1, + PREGION reg2) +{ + if ( !newReg || !reg1 || !reg2 ) return FALSE; + return REGION_IntersectRegion( newReg, reg1, reg2); +} + static BOOL REGION_bMakeSimpleFrameRgn( @@ -2098,9 +2137,13 @@ REGION_bXformRgn( RECTL_vMakeWellOrdered(&prgn->Buffer[i]); /* Update bounds */ - RECTL_bUnionRect(&prgn->rdh.rcBound, + if (!RECTL_bUnionRect(&prgn->rdh.rcBound, &prgn->rdh.rcBound, - &prgn->Buffer[i]); + &prgn->Buffer[i])) + { + DPRINT1("NULL Set in Union Rects\n"); + return FALSE; + } } /* Loop all rects in the region */ @@ -2469,6 +2512,7 @@ IntGdiCombineRgn( PREGION prgnSrc2, INT iCombineMode) { + BOOL Ret = TRUE; if (prgnDest == NULL) { @@ -2500,20 +2544,20 @@ IntGdiCombineRgn( switch (iCombineMode) { case RGN_AND: - REGION_IntersectRegion(prgnDest, prgnSrc1, prgnSrc2); + Ret = REGION_IntersectRegion(prgnDest, prgnSrc1, prgnSrc2); break; case RGN_OR: - REGION_UnionRegion(prgnDest, prgnSrc1, prgnSrc2); + Ret = REGION_UnionRegion(prgnDest, prgnSrc1, prgnSrc2); break; case RGN_XOR: - REGION_XorRegion(prgnDest, prgnSrc1, prgnSrc2); + Ret = REGION_XorRegion(prgnDest, prgnSrc1, prgnSrc2); break; case RGN_DIFF: - REGION_SubtractRegion(prgnDest, prgnSrc1, prgnSrc2); + Ret = REGION_SubtractRegion(prgnDest, prgnSrc1, prgnSrc2); break; } - return REGION_Complexity(prgnDest); + return Ret ? REGION_Complexity(prgnDest) : ERROR; } INT @@ -3600,8 +3644,9 @@ NtGdiCreateRoundRectRgn( { PREGION obj; HRGN hrgn; - INT asq, bsq, d, xd, yd; - RECTL rect; + int a, b, i, x, y; + INT64 asq, bsq, dx, dy, err; + RECT *rects; /* Make the dimensions sensible */ if (left > right) @@ -3618,95 +3663,75 @@ NtGdiCreateRoundRectRgn( bottom = tmp; } - ellipse_width = abs(ellipse_width); - ellipse_height = abs(ellipse_height); + /* the region is for the rectangle interior, but only at right and bottom for some reason */ + right--; + bottom--; - /* Check parameters */ - if (ellipse_width > right-left) - ellipse_width = right-left; - if (ellipse_height > bottom-top) - ellipse_height = bottom-top; + ellipse_width = min( right - left, abs( ellipse_width )); + ellipse_height = min( bottom - top, abs( ellipse_height )); /* 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; - obj = REGION_AllocUserRgnWithHandle(d); + obj = REGION_AllocUserRgnWithHandle( ellipse_height ); if (obj == NULL) return 0; hrgn = obj->BaseObject.hHmgr; - /* 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 */ + obj->rdh.rcBound.left = left; + obj->rdh.rcBound.top = top; + obj->rdh.rcBound.right = right; + obj->rdh.rcBound.bottom = bottom; + rects = obj->Buffer; - rect.left = left + ellipse_width / 2; - rect.right = right - ellipse_width / 2; + /* based on an algorithm by Alois Zingl */ - /* Loop to draw first half of quadrant */ - while (xd < yd) + a = ellipse_width - 1; + b = ellipse_height - 1; + asq = (INT64)8 * a * a; + bsq = (INT64)8 * b * b; + dx = (INT64)4 * b * b * (1 - a); + dy = (INT64)4 * a * a * (1 + (b % 2)); + err = dx + dy + a * a * (b % 2); + + x = 0; + y = ellipse_height / 2; + + rects[y].left = left; + rects[y].right = right; + + while (x <= ellipse_width / 2) { - /* If nearest pixel is toward the center */ - if (d > 0) + INT64 e2 = 2 * err; + if (e2 >= dx) { - /* Move toward center */ - rect.top = top++; - rect.bottom = rect.top + 1; - REGION_UnionRectWithRgn(obj, &rect); - rect.top = --bottom; - rect.bottom = rect.top + 1; - REGION_UnionRectWithRgn(obj, &rect); - yd -= 2*asq; - d -= yd; + x++; + err += dx += bsq; } - - /* Next horiz point */ - rect.left--; - 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; - REGION_UnionRectWithRgn(obj, &rect); - rect.top = --bottom; - rect.bottom = rect.top + 1; - REGION_UnionRectWithRgn(obj, &rect); - - /* If nearest pixel is outside ellipse */ - if (d < 0) + if (e2 <= dy) { - /* Move away from center */ - rect.left--; - rect.right++; - xd += 2*bsq; - d += xd; + y++; + err += dy += asq; + rects[y].left = left + x; + rects[y].right = right - x; } - - yd -= 2*asq; - d += asq - yd; } - - /* Add the inside rectangle */ - if (top <= bottom) + for (i = 0; i < ellipse_height / 2; i++) { - rect.top = top; - rect.bottom = bottom; - REGION_UnionRectWithRgn(obj, &rect); + rects[i].left = rects[b - i].left; + rects[i].right = rects[b - i].right; + rects[i].top = top + i; + rects[i].bottom = rects[i].top + 1; } + for (; i < ellipse_height; i++) + { + rects[i].top = bottom - ellipse_height + i; + rects[i].bottom = rects[i].top + 1; + } + rects[ellipse_height / 2].top = top + ellipse_height / 2; /* extend to top of rectangle */ REGION_UnlockRgn(obj); return hrgn; @@ -3860,7 +3885,13 @@ NtGdiExtCreateRegion( { if ( rects[i].left < rects[i].right && rects[i].top < rects[i].bottom ) { - REGION_UnionRectWithRgn(Region, &rects[i]); + if (!REGION_UnionRectWithRgn(Region, &rects[i])) + { + REGION_UnlockRgn(Region); + GreDeleteObject(hRgn); + hRgn = NULL; + _SEH2_LEAVE; + } } } @@ -3901,7 +3932,7 @@ NtGdiExtCreateRegion( return NULL; } - REGION_UnlockRgn(Region); + if (hRgn) REGION_UnlockRgn(Region); return hRgn; } diff --git a/win32ss/gdi/ntgdi/region.h b/win32ss/gdi/ntgdi/region.h index 0d4f454daa3..39badd8e305 100644 --- a/win32ss/gdi/ntgdi/region.h +++ b/win32ss/gdi/ntgdi/region.h @@ -25,7 +25,7 @@ extern HRGN hrgnDefault; PREGION FASTCALL REGION_AllocRgnWithHandle(INT n); PREGION FASTCALL REGION_AllocUserRgnWithHandle(INT n); -VOID FASTCALL REGION_UnionRectWithRgn(PREGION rgn, const RECTL *rect); +BOOL FASTCALL REGION_UnionRectWithRgn(PREGION rgn, const RECTL *rect); INT FASTCALL REGION_SubtractRectFromRgn(PREGION prgnDest, PREGION prgnSrc, const RECTL *prcl); INT FASTCALL REGION_GetRgnBox(PREGION Rgn, RECTL *pRect); BOOL FASTCALL REGION_RectInRegion(PREGION Rgn, const RECTL *rc); @@ -93,6 +93,12 @@ GreCreateFrameRgn( #define IntSysCreateRectpRgnIndirect(prc) \ IntSysCreateRectpRgn((prc)->left, (prc)->top, (prc)->right, (prc)->bottom) +#define GreCreateRectRgnIndirect(prc) \ + NtGdiCreateRectRgn((prc)->left, (prc)->top, (prc)->right, (prc)->bottom) + +#define GreSetRectRgnIndirect(hRgn, prc) \ + NtGdiSetRectRgn(hRgn, (prc)->left, (prc)->top, (prc)->right, (prc)->bottom); + PREGION FASTCALL IntSysCreateRectpRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect); diff --git a/win32ss/user/ntuser/painting.h b/win32ss/user/ntuser/painting.h index 8ab6a66c1ae..48d8406424c 100644 --- a/win32ss/user/ntuser/painting.h +++ b/win32ss/user/ntuser/painting.h @@ -15,12 +15,6 @@ #define RDW_CLIPCHILDREN 4096 #define RDW_NOUPDATEDIRTY 32768 -#define GreCreateRectRgnIndirect(prc) \ - NtGdiCreateRectRgn((prc)->left, (prc)->top, (prc)->right, (prc)->bottom) - -#define GreSetRectRgnIndirect(hRgn, prc) \ - NtGdiSetRectRgn(hRgn, (prc)->left, (prc)->top, (prc)->right, (prc)->bottom); - BOOL FASTCALL co_UserRedrawWindow(PWND Wnd, const RECTL* UpdateRect, PREGION UpdateRgn, ULONG Flags); VOID FASTCALL IntInvalidateWindows(PWND Window, PREGION Rgn, ULONG Flags); BOOL FASTCALL IntGetPaintMessage(PWND Window, UINT MsgFilterMin, UINT MsgFilterMax, PTHREADINFO Thread, MSG *Message, BOOL Remove);