#define LARGE_COORDINATE 0x7fffffff /* FIXME */
#define SMALL_COORDINATE 0x80000000
-/*
- * Check to see if there is enough memory in the present region.
- */
-static __inline INT xmemcheck(PREGION reg, PRECTL *rect, PRECTL *firstrect)
+static
+BOOL
+REGION_bGrowBufferSize(
+ _Inout_ PREGION prgn,
+ _In_ UINT cRects)
{
- if ((reg->rdh.nCount+1) * sizeof(RECT) >= reg->rdh.nRgnSize)
+ ULONG cjNewSize;
+ PVOID pvBuffer;
+ NT_ASSERT(cRects > 0);
+
+ /* Make sure we don't overflow */
+ if (cRects > MAXULONG / sizeof(RECTL))
{
- PRECTL temp;
- DWORD NewSize = 2 * reg->rdh.nRgnSize;
+ return FALSE;
+ }
- if (NewSize < (reg->rdh.nCount + 1) * sizeof(RECT))
- {
- NewSize = (reg->rdh.nCount + 1) * sizeof(RECT);
- }
+ /* Calculate new buffer size */
+ cjNewSize = cRects * sizeof(RECTL);
- temp = ExAllocatePoolWithTag(PagedPool, NewSize, TAG_REGION);
- if (temp == NULL)
- {
- return 0;
- }
+ /* Avoid allocating too often, by duplicating the old buffer size
+ Note: we don't do an overflow check, since the old size will never
+ get that large before running out of memory. */
+ if (2 * prgn->rdh.nRgnSize > cjNewSize)
+ {
+ cjNewSize = 2 * prgn->rdh.nRgnSize;
+ }
+
+ /* Allocate the new buffer */
+ pvBuffer = ExAllocatePoolWithTag(PagedPool, cjNewSize, TAG_REGION);
+ if (pvBuffer == NULL)
+ {
+ return FALSE;
+ }
- /* Copy the rectangles */
- COPY_RECTS(temp, *firstrect, reg->rdh.nCount);
+ /* Copy the rects into the new buffer */
+ COPY_RECTS(pvBuffer, prgn->Buffer, prgn->rdh.nCount);
- reg->rdh.nRgnSize = NewSize;
- if (*firstrect != ®->rdh.rcBound)
- {
- ExFreePoolWithTag(*firstrect, TAG_REGION);
- }
+ /* Free the old buffer */
+ if (prgn->Buffer != &prgn->rdh.rcBound)
+ {
+ ExFreePoolWithTag(prgn->Buffer, TAG_REGION);
+ }
+
+ /* Set the new buffer */
+ prgn->Buffer = pvBuffer;
+ prgn->rdh.nRgnSize = cjNewSize;
- *firstrect = temp;
- *rect = (*firstrect) + reg->rdh.nCount;
+ return TRUE;
+}
+
+static __inline
+BOOL
+REGION_bEnsureBufferSize(
+ _Inout_ PREGION prgn,
+ _In_ UINT cRects)
+{
+ /* Check if the current region size is too small */
+ if (cRects > prgn->rdh.nRgnSize / sizeof(RECTL))
+ {
+ /* Allocate a new buffer */
+ return REGION_bGrowBufferSize(prgn, cRects);
}
- return 1;
+
+ return TRUE;
}
-#define MEMCHECK(reg, rect, firstrect) xmemcheck(reg,&(rect),(PRECTL *)&(firstrect))
+FORCEINLINE
+VOID
+REGION_vAddRect(
+ _Inout_ PREGION prgn,
+ _In_ LONG left,
+ _In_ LONG top,
+ _In_ LONG right,
+ _In_ LONG bottom)
+{
+ PRECTL prcl;
+ NT_ASSERT((prgn->rdh.nCount + 1) * sizeof(RECT) <= prgn->rdh.nRgnSize);
+
+ prcl = &prgn->Buffer[prgn->rdh.nCount];
+ prcl->left = left;
+ prcl->top = top;
+ prcl->right = right;
+ prcl->bottom = bottom;
+ prgn->rdh.nCount++;
+}
+
+static __inline
+BOOL
+REGION_bAddRect(
+ _Inout_ PREGION prgn,
+ _In_ LONG left,
+ _In_ LONG top,
+ _In_ LONG right,
+ _In_ LONG bottom)
+{
+ if (!REGION_bEnsureBufferSize(prgn, prgn->rdh.nCount + 1))
+ {
+ return FALSE;
+ }
+
+ REGION_vAddRect(prgn, left, top, right, bottom);
+ return TRUE;
+}
typedef VOID (FASTCALL *overlapProcp)(PREGION, PRECT, PRECT, PRECT, PRECT, INT, INT);
typedef VOID (FASTCALL *nonOverlapProcp)(PREGION, PRECT, PRECT, INT, INT);
{
PREGION Data;
- Data = RGNOBJAPI_Lock(hRgn, NULL);
+ Data = REGION_LockRgn(hRgn);
if (Data == NULL)
{
DbgPrint("IntDumpRegion called with invalid region!\n");
Data->rdh.rcBound.bottom,
Data->rdh.iType);
- RGNOBJAPI_Unlock(Data);
+ REGION_UnlockRgn(Data);
}
#endif /* Not NDEBUG */
PREGION dst,
PREGION src)
{
- /* Only copy if source and dest are equal */
+ /* Only copy if source and dest are not equal */
if (dst != src)
{
/* Check if we need to increase our buffer */
// FIXME: This function needs review and testing
/***********************************************************************
- * REGION_CropAndOffsetRegion
+ * REGION_CropRegion
*/
INT
FASTCALL
lpr = &rgnSrc->Buffer[i];
/* Make sure the source rect is not retarded */
- ASSERT(lpr->bottom > rect->top);
- ASSERT(lpr->right > rect->left);
+ ASSERT(lpr->bottom > lpr->top);
+ ASSERT(lpr->right > lpr->left);
/* We already checked above, this should hold true */
ASSERT(lpr->bottom > rect->top);
{
rpr = &rgnDst->Buffer[j];
- /* Crop the rect with the intersect rect and add offset */
+ /* Crop the rect with the intersect rect */
rpr->top = max(lpr->top, rect->top);
rpr->bottom = min(lpr->bottom, rect->bottom);
rpr->left = max(lpr->left, rect->left);
rpr->right = min(lpr->right, rect->right);
/* Make sure the resulting rect is not retarded */
- ASSERT(lpr->bottom > rect->top);
- ASSERT(lpr->right > rect->left);
+ ASSERT(rpr->bottom > rpr->top);
+ ASSERT(rpr->right > rpr->left);
/* Track new bounds */
if (rpr->left < left) left = rpr->left;
INT top,
INT bottom)
{
- INT left, right;
- RECTL *pNextRect;
-
- pNextRect = pReg->Buffer + pReg->rdh.nCount;
+ INT left, right;
while ((r1 != r1End) && (r2 != r2End))
{
* right next to each other. Since that should never happen... */
if (left < right)
{
- MEMCHECK(pReg, pNextRect, pReg->Buffer);
- pNextRect->left = left;
- pNextRect->top = top;
- pNextRect->right = right;
- pNextRect->bottom = bottom;
- pReg->rdh.nCount += 1;
- pNextRect++;
+ if (!REGION_bAddRect(pReg, left, top, right, bottom))
+ {
+ return;
+ }
}
/* Need to advance the pointers. Shift the one that extends
INT top,
INT bottom)
{
- RECTL *pNextRect;
+ if (r != rEnd)
+ {
+ if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (rEnd - r)))
+ {
+ return;
+ }
+
+ do
+ {
+ REGION_vAddRect(pReg, r->left, top, r->right, bottom);
+ r++;
+ }
+ while (r != rEnd);
+ }
- pNextRect = pReg->Buffer + pReg->rdh.nCount;
+ return;
+}
- while (r != rEnd)
+static __inline
+BOOL
+REGION_bMergeRect(
+ _Inout_ PREGION prgn,
+ _In_ LONG left,
+ _In_ LONG top,
+ _In_ LONG right,
+ _In_ LONG bottom)
+{
+ if ((prgn->rdh.nCount != 0) &&
+ (prgn->Buffer[prgn->rdh.nCount - 1].top == top) &&
+ (prgn->Buffer[prgn->rdh.nCount - 1].bottom == bottom) &&
+ (prgn->Buffer[prgn->rdh.nCount - 1].right >= left))
+ {
+ if (prgn->Buffer[prgn->rdh.nCount - 1].right < right)
+ {
+ prgn->Buffer[prgn->rdh.nCount - 1].right = right;
+ }
+ }
+ else
{
- MEMCHECK(pReg, pNextRect, pReg->Buffer);
- pNextRect->left = r->left;
- pNextRect->top = top;
- pNextRect->right = r->right;
- pNextRect->bottom = bottom;
- pReg->rdh.nCount += 1;
- pNextRect++;
- r++;
+ if (!REGION_bAddRect(prgn, left, top, right, bottom))
+ {
+ return FALSE;
+ }
}
- return;
+ return TRUE;
}
/*!
INT top,
INT bottom)
{
- RECTL *pNextRect;
-
- pNextRect = pReg->Buffer + pReg->rdh.nCount;
-
-#define MERGERECT(r) \
- if ((pReg->rdh.nCount != 0) && \
- ((pNextRect-1)->top == top) && \
- ((pNextRect-1)->bottom == bottom) && \
- ((pNextRect-1)->right >= r->left)) \
- { \
- if ((pNextRect-1)->right < r->right) \
- { \
- (pNextRect-1)->right = r->right; \
- } \
- } \
- else \
- { \
- MEMCHECK(pReg, pNextRect, pReg->Buffer); \
- pNextRect->top = top; \
- pNextRect->bottom = bottom; \
- pNextRect->left = r->left; \
- pNextRect->right = r->right; \
- pReg->rdh.nCount += 1; \
- pNextRect += 1; \
- } \
- r++;
-
while ((r1 != r1End) && (r2 != r2End))
{
if (r1->left < r2->left)
{
- MERGERECT(r1);
+ REGION_bMergeRect(pReg, r1->left, top, r1->right, bottom);
+ r1++;
}
else
{
- MERGERECT(r2);
+ REGION_bMergeRect(pReg, r2->left, top, r2->right, bottom);
+ r2++;
}
}
{
do
{
- MERGERECT(r1);
+ REGION_bMergeRect(pReg, r1->left, top, r1->right, bottom);
+ r1++;
}
while (r1 != r1End);
}
{
while (r2 != r2End)
{
- MERGERECT(r2);
+ REGION_bMergeRect(pReg, r2->left, top, r2->right, bottom);
+ r2++;
}
}
INT top,
INT bottom)
{
- RECTL *pNextRect;
-
- pNextRect = pReg->Buffer + pReg->rdh.nCount;
-
- while (r != rEnd)
+ if (r != rEnd)
{
- MEMCHECK(pReg, pNextRect, pReg->Buffer);
- pNextRect->left = r->left;
- pNextRect->top = top;
- pNextRect->right = r->right;
- pNextRect->bottom = bottom;
- pReg->rdh.nCount += 1;
- pNextRect++;
- r++;
+ if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (rEnd - r)))
+ {
+ return;
+ }
+
+ do
+ {
+ REGION_vAddRect(pReg, r->left, top, r->right, bottom);
+ r++;
+ }
+ while (r != rEnd);
}
return;
INT top,
INT bottom)
{
- RECTL *pNextRect;
INT left;
left = r1->left;
- pNextRect = pReg->Buffer + pReg->rdh.nCount;
while ((r1 != r1End) && (r2 != r2End))
{
{
/* Left part of subtrahend covers part of minuend: add uncovered
* part of minuend to region and skip to next subtrahend. */
- MEMCHECK(pReg, pNextRect, pReg->Buffer);
- pNextRect->left = left;
- pNextRect->top = top;
- pNextRect->right = r2->left;
- pNextRect->bottom = bottom;
- pReg->rdh.nCount += 1;
- pNextRect++;
+ if (!REGION_bAddRect(pReg, left, top, r2->left, bottom))
+ {
+ return;
+ }
+
left = r2->right;
if (left >= r1->right)
{
/* Minuend used up: add any remaining piece before advancing. */
if (r1->right > left)
{
- MEMCHECK(pReg, pNextRect, pReg->Buffer);
- pNextRect->left = left;
- pNextRect->top = top;
- pNextRect->right = r1->right;
- pNextRect->bottom = bottom;
- pReg->rdh.nCount += 1;
- pNextRect++;
+ if (!REGION_bAddRect(pReg, left, top, r1->right, bottom))
+ {
+ return;
+ }
}
r1++;
}
}
- /* Add remaining minuend rectangles to region. */
- while (r1 != r1End)
+ /* Make sure the buffer is large enough for all remaining operations */
+ if (r1 != r1End)
{
- MEMCHECK(pReg, pNextRect, pReg->Buffer);
- pNextRect->left = left;
- pNextRect->top = top;
- pNextRect->right = r1->right;
- pNextRect->bottom = bottom;
- pReg->rdh.nCount += 1;
- pNextRect++;
- r1++;
- if (r1 != r1End)
+ if (!REGION_bEnsureBufferSize(pReg, pReg->rdh.nCount + (r1End - r1)))
+ {
+ return;
+ }
+
+ /* Add remaining minuend rectangles to region. */
+ do
{
- left = r1->left;
+ REGION_vAddRect(pReg, left, top, r1->right, bottom);
+ r1++;
+ if (r1 != r1End)
+ {
+ left = r1->left;
+ }
}
+ while (r1 != r1End);
}
return;
trb = REGION_AllocRgnWithHandle(srb->rdh.nCount + 1);
if (trb == NULL)
{
- RGNOBJAPI_Unlock(tra);
+ REGION_UnlockRgn(tra);
GreDeleteObject(htra);
return;
}
REGION_SubtractRegion(tra, sra, srb);
REGION_SubtractRegion(trb, srb, sra);
REGION_UnionRegion(dr, tra, trb);
- RGNOBJAPI_Unlock(tra);
- RGNOBJAPI_Unlock(trb);
+ REGION_UnlockRgn(tra);
+ REGION_UnlockRgn(trb);
GreDeleteObject(htra);
GreDeleteObject(htrb);
return REGION_Complexity(prgnDest);
}
+static
BOOL
-FASTCALL
-REGION_CreateSimpleFrameRgn(
- PREGION rgn,
- INT x,
- INT y)
+REGION_bMakeSimpleFrameRgn(
+ _Inout_ PREGION prgn,
+ _In_ PRECTL prclSrc,
+ _In_ INT cx,
+ _In_ INT cy)
{
- RECTL rc[4];
- PRECTL prc;
+ RECTL arcl[4];
+ UINT i;
+
+ NT_ASSERT((cx >= 0) && (cy >= 0));
+ NT_ASSERT((prclSrc->bottom > prclSrc->top) &&
+ (prclSrc->right > prclSrc->left));
- if ((x != 0) || (y != 0))
+ /* Start with an empty region */
+ EMPTY_REGION(prgn);
+
+ /* Check for the case where the frame covers the whole rect */
+ if (((prclSrc->bottom - prclSrc->top) <= cy * 2) ||
+ ((prclSrc->right - prclSrc->left) <= cx * 2))
{
- prc = rc;
+ prgn->rdh.rcBound = *prclSrc;
+ prgn->Buffer[0] = *prclSrc;
+ prgn->rdh.nCount = 1;
+ return TRUE;
+ }
- if ((rgn->rdh.rcBound.bottom - rgn->rdh.rcBound.top > y * 2) &&
- (rgn->rdh.rcBound.right - rgn->rdh.rcBound.left > x * 2))
- {
- if (y != 0)
- {
- /* Top rectangle */
- prc->left = rgn->rdh.rcBound.left;
- prc->top = rgn->rdh.rcBound.top;
- prc->right = rgn->rdh.rcBound.right;
- prc->bottom = prc->top + y;
- prc++;
- }
+ i = 0;
- if (x != 0)
- {
- /* Left rectangle */
- prc->left = rgn->rdh.rcBound.left;
- prc->top = rgn->rdh.rcBound.top + y;
- prc->right = prc->left + x;
- prc->bottom = rgn->rdh.rcBound.bottom - y;
- prc++;
-
- /* Right rectangle */
- prc->left = rgn->rdh.rcBound.right - x;
- prc->top = rgn->rdh.rcBound.top + y;
- prc->right = rgn->rdh.rcBound.right;
- prc->bottom = rgn->rdh.rcBound.bottom - y;
- prc++;
- }
+ if (cy != 0)
+ {
+ /* Top rectangle */
+ arcl[i].left = prclSrc->left;
+ arcl[i].top = prclSrc->top;
+ arcl[i].right = prclSrc->right;
+ arcl[i].bottom = prclSrc->top + cy;
+ i++;
+ }
- if (y != 0)
- {
- /* Bottom rectangle */
- prc->left = rgn->rdh.rcBound.left;
- prc->top = rgn->rdh.rcBound.bottom - y;
- prc->right = rgn->rdh.rcBound.right;
- prc->bottom = rgn->rdh.rcBound.bottom;
- prc++;
- }
- }
+ if (cx != 0)
+ {
+ /* Left rectangle */
+ arcl[i].left = prclSrc->left;
+ arcl[i].top = prclSrc->top + cy;
+ arcl[i].right = prclSrc->left + cx;
+ arcl[i].bottom = prclSrc->bottom - cy;
+ i++;
- if (prc != rc)
- {
- /* The frame results in a complex region. rcBounds remains
- the same, though. */
- rgn->rdh.nCount = (DWORD)(prc - rc);
- ASSERT(rgn->rdh.nCount > 1);
- rgn->rdh.nRgnSize = rgn->rdh.nCount * sizeof(RECT);
- rgn->Buffer = ExAllocatePoolWithTag(PagedPool,
- rgn->rdh.nRgnSize,
- TAG_REGION);
- if (rgn->Buffer == NULL)
- {
- rgn->rdh.nRgnSize = 0;
- return FALSE;
- }
+ /* Right rectangle */
+ arcl[i].left = prclSrc->right - cx;
+ arcl[i].top = prclSrc->top + cy;
+ arcl[i].right = prclSrc->right;
+ arcl[i].bottom = prclSrc->bottom - cy;
+ i++;
+ }
+
+ if (cy != 0)
+ {
+ /* Bottom rectangle */
+ arcl[i].left = prclSrc->left;
+ arcl[i].top = prclSrc->bottom - cy;
+ arcl[i].right = prclSrc->right;
+ arcl[i].bottom = prclSrc->bottom;
+ i++;
+ }
- _PRAGMA_WARNING_SUPPRESS(__WARNING_MAYBE_UNINIT_VAR) // rc is initialized
- COPY_RECTS(rgn->Buffer, rc, rgn->rdh.nCount);
+ if (i != 0)
+ {
+ /* The frame results in a complex region. rcBounds remains
+ the same, though. */
+ prgn->rdh.nCount = i;
+ NT_ASSERT(prgn->rdh.nCount > 1);
+ prgn->rdh.nRgnSize = prgn->rdh.nCount * sizeof(RECT);
+ NT_ASSERT(prgn->Buffer == &prgn->rdh.rcBound);
+ prgn->Buffer = ExAllocatePoolWithTag(PagedPool,
+ prgn->rdh.nRgnSize,
+ TAG_REGION);
+ if (prgn->Buffer == NULL)
+ {
+ prgn->rdh.nRgnSize = 0;
+ return FALSE;
}
+
+ _PRAGMA_WARNING_SUPPRESS(__WARNING_MAYBE_UNINIT_VAR) // arcl is initialized
+ COPY_RECTS(prgn->Buffer, arcl, prgn->rdh.nCount);
}
return TRUE;
}
+static
BOOL
-FASTCALL
-REGION_CreateFrameRgn(
- HRGN hDest,
- HRGN hSrc,
- INT x,
- INT y)
-{
- PREGION srcObj, destObj;
- PRECTL rc;
- ULONG i;
+REGION_bMakeFrameRegion(
+ _Inout_ PREGION prgnDest,
+ _Inout_ PREGION prgnSrc,
+ _In_ INT cx,
+ _In_ INT cy)
+{
+ /* Handle negative cx / cy */
+ cx = abs(cx);
+ cy = abs(cy);
- srcObj = RGNOBJAPI_Lock(hSrc, NULL);
- if (srcObj == NULL)
+ /* Check border size (the cast is necessary to catch cx/cy == INT_MIN!) */
+ if (((UINT)cx > MAX_COORD) || ((UINT)cy > MAX_COORD))
{
return FALSE;
}
- if (!REGION_NOT_EMPTY(srcObj))
+ /* Fail on empty source region */
+ if (!REGION_NOT_EMPTY(prgnSrc))
{
- RGNOBJAPI_Unlock(srcObj);
return FALSE;
}
- destObj = RGNOBJAPI_Lock(hDest, NULL);
- if (destObj == NULL)
+ /* Handle trivial case */
+ if ((cx == 0) && (cy == 0))
{
- RGNOBJAPI_Unlock(srcObj);
- return FALSE;
+ EMPTY_REGION(prgnDest);
+ return TRUE;
}
- EMPTY_REGION(destObj);
- if (!REGION_CopyRegion(destObj, srcObj))
+ /* Handle simple source region */
+ if (REGION_Complexity(prgnSrc) == SIMPLEREGION)
{
- RGNOBJAPI_Unlock(destObj);
- RGNOBJAPI_Unlock(srcObj);
- return FALSE;
+ return REGION_bMakeSimpleFrameRgn(prgnDest, &prgnSrc->rdh.rcBound, cx, cy);
}
- if (REGION_Complexity(srcObj) == SIMPLEREGION)
+ /* Check if we can move the region to create the frame region */
+ if ((prgnSrc->rdh.rcBound.left < (MIN_COORD + cx)) ||
+ (prgnSrc->rdh.rcBound.top < (MIN_COORD + cy)) ||
+ (prgnSrc->rdh.rcBound.right > (MAX_COORD - cx)) ||
+ (prgnSrc->rdh.rcBound.bottom > (MAX_COORD - cy)))
{
- if (!REGION_CreateSimpleFrameRgn(destObj, x, y))
- {
- EMPTY_REGION(destObj);
- RGNOBJAPI_Unlock(destObj);
- RGNOBJAPI_Unlock(srcObj);
- return FALSE;
- }
+ return FALSE;
}
- else
+
+ /* Copy the source region */
+ if (!REGION_CopyRegion(prgnDest, prgnSrc))
{
- /* Original region moved to right */
- rc = srcObj->Buffer;
- for (i = 0; i < srcObj->rdh.nCount; i++)
- {
- rc->left += x;
- rc->right += x;
- rc++;
- }
+ return FALSE;
+ }
- REGION_IntersectRegion(destObj, destObj, srcObj);
+ /* Move the source region to the bottom-right */
+ NT_VERIFY(REGION_bOffsetRgn(prgnSrc, cx, cy));
- /* Original region moved to left */
- rc = srcObj->Buffer;
- for (i = 0; i < srcObj->rdh.nCount; i++)
- {
- rc->left -= 2 * x;
- rc->right -= 2 * x;
- rc++;
- }
+ /* Intersect with the source region (this crops the top-left frame) */
+ REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
- REGION_IntersectRegion(destObj, destObj, srcObj);
+ /* Move the source region to the bottom-left */
+ NT_VERIFY(REGION_bOffsetRgn(prgnSrc, -2 * cx, 0));
- /* Original region moved down */
- rc = srcObj->Buffer;
- for (i = 0; i < srcObj->rdh.nCount; i++)
- {
- rc->left += x;
- rc->right += x;
- rc->top += y;
- rc->bottom += y;
- rc++;
- }
+ /* Intersect with the source region (this crops the top-right frame) */
+ REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
- REGION_IntersectRegion(destObj, destObj, srcObj);
+ /* Move the source region to the top-left */
+ NT_VERIFY(REGION_bOffsetRgn(prgnSrc, 0, -2 * cy));
- /* Original region moved up */
- rc = srcObj->Buffer;
- for (i = 0; i < srcObj->rdh.nCount; i++)
- {
- rc->top -= 2 * y;
- rc->bottom -= 2 * y;
- rc++;
- }
+ /* Intersect with the source region (this crops the bottom-right frame) */
+ REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
- REGION_IntersectRegion(destObj, destObj, srcObj);
+ /* Move the source region to the top-right */
+ NT_VERIFY(REGION_bOffsetRgn(prgnSrc, 2 * cx, 0));
- /* Restore the original region */
- rc = srcObj->Buffer;
- for (i = 0; i < srcObj->rdh.nCount; i++)
- {
- rc->top += y;
- rc->bottom += y;
- rc++;
- }
+ /* Intersect with the source region (this crops the bottom-left frame) */
+ REGION_IntersectRegion(prgnDest, prgnDest, prgnSrc);
- REGION_SubtractRegion(destObj, srcObj, destObj);
- }
+ /* Move the source region back to the original position */
+ NT_VERIFY(REGION_bOffsetRgn(prgnSrc, -cx, cy));
+
+ /* Finally subtract the cropped region from the source */
+ REGION_SubtractRegion(prgnDest, prgnSrc, prgnDest);
- RGNOBJAPI_Unlock(destObj);
- RGNOBJAPI_Unlock(srcObj);
return TRUE;
}
+HRGN
+FASTCALL
+GreCreateFrameRgn(
+ HRGN hrgn,
+ INT cx,
+ INT cy)
+{
+ PREGION prgnFrame, prgnSrc;
+ HRGN hrgnFrame;
+
+ /* Allocate a new region */
+ prgnFrame = REGION_AllocUserRgnWithHandle(1);
+ if (prgnFrame == NULL)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
+ }
+
+ /* Lock the source region */
+ prgnSrc = REGION_LockRgn(hrgn);
+ if (prgnSrc == NULL)
+ {
+ REGION_Delete(prgnFrame);
+ return FALSE;
+ }
+
+ if (REGION_bMakeFrameRegion(prgnFrame, prgnSrc, cx, cy))
+ {
+ hrgnFrame = prgnFrame->BaseObject.hHmgr;
+ REGION_UnlockRgn(prgnFrame);
+ }
+ else
+ {
+ REGION_Delete(prgnFrame);
+ hrgnFrame = NULL;
+ }
+
+ REGION_UnlockRgn(prgnSrc);
+ return hrgnFrame;
+}
-static
BOOL
FASTCALL
-REGION_LPTODP(
- _In_ PDC dc,
- _Inout_ PREGION RgnDest,
- _In_ PREGION RgnSrc)
+REGION_bXformRgn(
+ _Inout_ PREGION prgn,
+ _In_ PMATRIX pmx)
{
- RECTL *pCurRect, *pEndRect;
- RECTL tmpRect;
- PDC_ATTR pdcattr;
+ XFORMOBJ xo;
+ ULONG i, j, cjSize;
+ PPOINT ppt;
+ PULONG pcPoints;
+ RECT rect;
+ BOOL bResult;
- if (dc == NULL)
- return FALSE;
- pdcattr = dc->pdcattr;
+ /* Check for zero rectangles and return TRUE for translation only matrices */
+ if (prgn->rdh.nCount < 1)
+ return (pmx->flAccel & XFORM_UNITY) != 0;
- if (pdcattr->iMapMode == MM_TEXT) // Requires only a translation
+ /* Check if this is a scaling only matrix (off-diagonal elements are 0 */
+ if (pmx->flAccel & XFORM_SCALE)
{
- if (IntGdiCombineRgn(RgnDest, RgnSrc, 0, RGN_COPY) == ERROR)
- return FALSE;
+ /* Check if this is a translation only matrix */
+ if (pmx->flAccel & XFORM_UNITY)
+ {
+ /* Just offset the region */
+ return REGION_bOffsetRgn(prgn, (pmx->fxDx + 8) / 16, (pmx->fxDy + 8) / 16);
+ }
+ else
+ {
+ /* Initialize the xform object */
+ XFORMOBJ_vInit(&xo, pmx);
- IntGdiOffsetRgn(RgnDest,
- pdcattr->ptlViewportOrg.x - pdcattr->ptlWindowOrg.x,
- pdcattr->ptlViewportOrg.y - pdcattr->ptlWindowOrg.y);
- return TRUE;
- }
+ /* Scaling can move the rects out of the coordinate space, so
+ * we first need to check whether we can apply the transformation
+ * on the bounds rect without modifying the region */
+ if (!XFORMOBJ_bApplyXform(&xo, XF_LTOL, 2, &prgn->rdh.rcBound, &rect))
+ {
+ return FALSE;
+ }
+
+ /* Apply the xform to the rects in the region */
+ if (!XFORMOBJ_bApplyXform(&xo,
+ XF_LTOL,
+ prgn->rdh.nCount * 2,
+ prgn->Buffer,
+ prgn->Buffer))
+ {
+ /* This can not happen, since we already checked the bounds! */
+ NT_ASSERT(FALSE);
+ }
+
+ /* Reset bounds */
+ RECTL_vSetEmptyRect(&prgn->rdh.rcBound);
+
+ /* Loop all rects in the region */
+ for (i = 0; i < prgn->rdh.nCount; i++)
+ {
+ /* Make sure the rect is well-ordered after the xform */
+ RECTL_vMakeWellOrdered(&prgn->Buffer[i]);
+
+ /* Update bounds */
+ RECTL_bUnionRect(&prgn->rdh.rcBound,
+ &prgn->rdh.rcBound,
+ &prgn->Buffer[i]);
+ }
- EMPTY_REGION(RgnDest);
+ /* Loop all rects in the region */
+ for (i = 0; i < prgn->rdh.nCount - 1; i++)
+ {
+ for (j = i; i < prgn->rdh.nCount; i++)
+ {
+ NT_ASSERT(prgn->Buffer[i].top < prgn->Buffer[i].bottom);
+ NT_ASSERT(prgn->Buffer[j].top >= prgn->Buffer[i].top);
+ }
+ }
- pEndRect = RgnSrc->Buffer + RgnSrc->rdh.nCount;
- for (pCurRect = RgnSrc->Buffer; pCurRect < pEndRect; pCurRect++)
+ return TRUE;
+ }
+ }
+ else
{
- tmpRect = *pCurRect;
- tmpRect.left = XLPTODP(pdcattr, tmpRect.left);
- tmpRect.top = YLPTODP(pdcattr, tmpRect.top);
- tmpRect.right = XLPTODP(pdcattr, tmpRect.right);
- tmpRect.bottom = YLPTODP(pdcattr, tmpRect.bottom);
+ /* Allocate a buffer for the polygons */
+ cjSize = prgn->rdh.nCount * (4 * sizeof(POINT) + sizeof(ULONG));
+ ppt = ExAllocatePoolWithTag(PagedPool, cjSize, GDITAG_REGION);
+ if (ppt == NULL)
+ {
+ return FALSE;
+ }
- if (tmpRect.left > tmpRect.right)
+ /* Fill the buffer with the rects */
+ pcPoints = (PULONG)&ppt[4 * prgn->rdh.nCount];
+ for (i = 0; i < prgn->rdh.nCount; i++)
{
- INT tmp = tmpRect.left;
- tmpRect.left = tmpRect.right;
- tmpRect.right = tmp;
+ /* Make sure the rect is within the legal range */
+ pcPoints[i] = 4;
+ ppt[4 * i + 0].x = prgn->Buffer[i].left;
+ ppt[4 * i + 0].y = prgn->Buffer[i].top;
+ ppt[4 * i + 1].x = prgn->Buffer[i].right;
+ ppt[4 * i + 1].y = prgn->Buffer[i].top;
+ ppt[4 * i + 2].x = prgn->Buffer[i].right;
+ ppt[4 * i + 2].y = prgn->Buffer[i].bottom;
+ ppt[4 * i + 3].x = prgn->Buffer[i].left;
+ ppt[4 * i + 3].y = prgn->Buffer[i].bottom;
}
- if (tmpRect.top > tmpRect.bottom)
+ /* Initialize the xform object */
+ XFORMOBJ_vInit(&xo, pmx);
+
+ /* Apply the xform to the rects in the buffer */
+ if (!XFORMOBJ_bApplyXform(&xo,
+ XF_LTOL,
+ prgn->rdh.nCount * 2,
+ ppt,
+ ppt))
{
- INT tmp = tmpRect.top;
- tmpRect.top = tmpRect.bottom;
- tmpRect.bottom = tmp;
+ /* This means, there were coordinates that would go outside of
+ the coordinate space after the transformation */
+ ExFreePoolWithTag(ppt, GDITAG_REGION);
+ return FALSE;
}
- REGION_UnionRectWithRgn(RgnDest, &tmpRect);
+ /* Now use the polygons to create a polygon region */
+ bResult = REGION_SetPolyPolygonRgn(prgn,
+ ppt,
+ pcPoints,
+ prgn->rdh.nCount,
+ WINDING);
+
+ /* Free the polygon buffer */
+ ExFreePoolWithTag(ppt, GDITAG_REGION);
+
+ return bResult;
}
- return TRUE;
}
+
PREGION
FASTCALL
REGION_AllocRgnWithHandle(
return NULL;
}
- if (!GDIOBJ_hInsertObject(&pReg->BaseObject, GDI_OBJ_HMGR_POWNED))
- {
- DPRINT1("Could not insert palette into handle table.\n");
- GDIOBJ_vFreeObject(&pReg->BaseObject);
- return NULL;
- }
-
//hReg = pReg->BaseObject.hHmgr;
if ((nReg == 0) || (nReg == 1))
pReg->rdh.nRgnSize = nReg * sizeof(RECT);
pReg->prgnattr = &pReg->rgnattr;
+ /* Initialize the region attribute */
+ pReg->rgnattr.AttrFlags = 0;
+ pReg->rgnattr.iComplexity = SIMPLEREGION;
+ pReg->rgnattr.Rect = pReg->rdh.rcBound;
+
+ /* Finally insert the region into the handle table */
+ if (!GDIOBJ_hInsertObject(&pReg->BaseObject, GDI_OBJ_HMGR_POWNED))
+ {
+ DPRINT1("Could not insert palette into handle table.\n");
+ GDIOBJ_vFreeObject(&pReg->BaseObject);
+ return NULL;
+ }
+
return pReg;
}
PPROCESSINFO ppi;
PRGN_ATTR prgnattr;
+ NT_ASSERT(prgn->prgnattr == &prgn->rgnattr);
+
ppi = PsGetCurrentProcessWin32Process();
ASSERT(ppi);
return FALSE;
}
+ /* Copy the current region attribute */
+ *prgnattr = prgn->rgnattr;
+
/* Set the object attribute in the handle table */
prgn->prgnattr = prgnattr;
GDIOBJ_vSetObjectAttr(&prgn->BaseObject, prgnattr);
return prgn;
}
+static
VOID
-NTAPI
REGION_vSyncRegion(
- PREGION pRgn)
+ _In_ PREGION prgn)
{
- PRGN_ATTR pRgn_Attr = NULL;
+ PRGN_ATTR prgnattr;
+
+ NT_ASSERT(prgn != NULL);
+ NT_ASSERT(prgn->prgnattr != NULL);
+ NT_ASSERT((prgn->prgnattr == &prgn->rgnattr) ||
+ (prgn->prgnattr->AttrFlags & ATTR_RGN_VALID));
- if (pRgn && pRgn->prgnattr != &pRgn->rgnattr)
+ /* Get the region attribute and check if it's dirty (modified) */
+ prgnattr = prgn->prgnattr;
+ if (prgnattr->AttrFlags & ATTR_RGN_DIRTY)
{
- pRgn_Attr = GDIOBJ_pvGetObjectAttr(&pRgn->BaseObject);
+ NT_ASSERT(GreGetObjectOwner(prgn->BaseObject.hHmgr) == GDI_OBJ_HMGR_POWNED);
+ NT_ASSERT(prgnattr != &prgn->rgnattr);
- if ( pRgn_Attr )
+ if (prgnattr->iComplexity == NULLREGION)
{
- _SEH2_TRY
- {
- if ( !(pRgn_Attr->AttrFlags & ATTR_CACHED) )
- {
- if ( pRgn_Attr->AttrFlags & (ATTR_RGN_VALID|ATTR_RGN_DIRTY) )
- {
- switch (pRgn_Attr->iComplexity)
- {
- case NULLREGION:
- EMPTY_REGION( pRgn );
- break;
-
- case SIMPLEREGION:
- REGION_SetRectRgn( pRgn,
- pRgn_Attr->Rect.left,
- pRgn_Attr->Rect.top,
- pRgn_Attr->Rect.right,
- pRgn_Attr->Rect.bottom );
- break;
- }
- pRgn_Attr->AttrFlags &= ~ATTR_RGN_DIRTY;
- }
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- (VOID)0;
- }
- _SEH2_END;
+ EMPTY_REGION(prgn);
}
- }
-
-}
+ else if (prgnattr->iComplexity == SIMPLEREGION)
+ {
+ REGION_SetRectRgn(prgn,
+ prgnattr->Rect.left,
+ prgnattr->Rect.top,
+ prgnattr->Rect.right,
+ prgnattr->Rect.bottom);
+ }
+ else
+ {
+ /* Should not happen, region attribute is corrupted! */
+ DPRINT1("Region attribute is corrupted, ignoring\n");
+ NT_ASSERT(FALSE);
+ }
+ }
+
+ /* Reset the flags */
+ prgnattr->AttrFlags &= ~(ATTR_RGN_DIRTY | ATTR_RGN_VALID);
+}
PREGION
FASTCALL
-RGNOBJAPI_Lock(
- HRGN hRgn,
- PRGN_ATTR *ppRgn_Attr)
+REGION_LockRgn(
+ _In_ HRGN hrgn)
{
- PREGION pRgn;
+ PREGION prgn;
- pRgn = REGION_LockRgn(hRgn);
- if (pRgn == NULL)
+ prgn = GDIOBJ_LockObject(hrgn, GDIObjType_RGN_TYPE);
+ if (prgn == NULL)
return NULL;
- REGION_vSyncRegion(pRgn);
-
- if (ppRgn_Attr)
- *ppRgn_Attr = pRgn->prgnattr;
-
- return pRgn;
+ REGION_vSyncRegion(prgn);
+ return prgn;
}
VOID
FASTCALL
-RGNOBJAPI_Unlock(
- PREGION pRgn)
+REGION_UnlockRgn(
+ _In_ PREGION prgn)
{
- PRGN_ATTR pRgn_Attr;
+ PRGN_ATTR prgnattr;
- if (pRgn && GreGetObjectOwner(pRgn->BaseObject.hHmgr) == GDI_OBJ_HMGR_POWNED)
- {
- pRgn_Attr = GDIOBJ_pvGetObjectAttr(&pRgn->BaseObject);
+ NT_ASSERT(prgn != NULL);
+ NT_ASSERT(prgn->prgnattr != NULL);
- if ( pRgn_Attr )
- {
- _SEH2_TRY
- {
- if ( pRgn_Attr->AttrFlags & ATTR_RGN_VALID )
- {
- pRgn_Attr->iComplexity = REGION_Complexity( pRgn );
- pRgn_Attr->Rect.left = pRgn->rdh.rcBound.left;
- pRgn_Attr->Rect.top = pRgn->rdh.rcBound.top;
- pRgn_Attr->Rect.right = pRgn->rdh.rcBound.right;
- pRgn_Attr->Rect.bottom = pRgn->rdh.rcBound.bottom;
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- (VOID)0;
- }
- _SEH2_END;
- }
+ /* Get the region attribute and check if it's user mode */
+ prgnattr = prgn->prgnattr;
+ if (prgnattr != &prgn->rgnattr)
+ {
+ NT_ASSERT(GreGetObjectOwner(prgn->BaseObject.hHmgr) == GDI_OBJ_HMGR_POWNED);
+ prgnattr->iComplexity = REGION_Complexity(prgn);
+ prgnattr->Rect.left = prgn->rdh.rcBound.left;
+ prgnattr->Rect.top = prgn->rdh.rcBound.top;
+ prgnattr->Rect.right = prgn->rdh.rcBound.right;
+ prgnattr->Rect.bottom = prgn->rdh.rcBound.bottom;
+ prgnattr->AttrFlags |= ATTR_RGN_VALID;
}
- REGION_UnlockRgn(pRgn);
+
+ GDIOBJ_vUnlockObject(&prgn->BaseObject);
}
/*
{
PREGION prgn;
- /* Allocate a region, witout a handle */
+ /* Allocate a region, without a handle */
prgn = (PREGION)GDIOBJ_AllocateObject(GDIObjType_RGN_TYPE, sizeof(REGION), BASEFLAG_LOOKASIDE);
if (prgn == NULL)
{
/* Initialize it */
prgn->Buffer = &prgn->rdh.rcBound;
prgn->prgnattr = &prgn->rgnattr;
+ prgn->prgnattr->AttrFlags = ATTR_RGN_VALID;
REGION_SetRectRgn(prgn, LeftRect, TopRect, RightRect, BottomRect);
return prgn;
GDIOBJ_vDeleteObject(&pRgn->BaseObject);
}
-VOID
-FASTCALL
-IntGdiReleaseRaoRgn(PDC pDC)
-{
- INT Index = GDI_HANDLE_GET_INDEX(pDC->BaseObject.hHmgr);
- PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
- pDC->fs |= DC_FLAG_DIRTY_RAO;
- Entry->Flags |= GDI_ENTRY_VALIDATE_VIS;
- RECTL_vSetEmptyRect(&pDC->erclClip);
- REGION_Delete(pDC->prgnRao);
- pDC->prgnRao = NULL;
-}
-
-VOID
-FASTCALL
-IntGdiReleaseVisRgn(PDC pDC)
-{
- INT Index = GDI_HANDLE_GET_INDEX(pDC->BaseObject.hHmgr);
- PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
- pDC->fs |= DC_FLAG_DIRTY_RAO;
- Entry->Flags |= GDI_ENTRY_VALIDATE_VIS;
- RECTL_vSetEmptyRect(&pDC->erclClip);
- REGION_Delete(pDC->prgnVis);
- pDC->prgnVis = prgnDefault;
-}
-
-VOID
-FASTCALL
-IntUpdateVisRectRgn(PDC pDC, PREGION pRgn)
-{
- INT Index = GDI_HANDLE_GET_INDEX(pDC->BaseObject.hHmgr);
- PGDI_TABLE_ENTRY Entry = &GdiHandleTable->Entries[Index];
- PDC_ATTR pdcattr;
- RECTL rcl;
-
- if (Entry->Flags & GDI_ENTRY_VALIDATE_VIS)
- {
- pdcattr = pDC->pdcattr;
-
- pdcattr->VisRectRegion.iComplexity = REGION_Complexity(pRgn);
-
- if (pRgn && pdcattr->VisRectRegion.iComplexity != NULLREGION)
- {
- rcl.left = pRgn->rdh.rcBound.left;
- rcl.top = pRgn->rdh.rcBound.top;
- rcl.right = pRgn->rdh.rcBound.right;
- rcl.bottom = pRgn->rdh.rcBound.bottom;
-
- rcl.left -= pDC->erclWindow.left;
- rcl.top -= pDC->erclWindow.top;
- rcl.right -= pDC->erclWindow.left;
- rcl.bottom -= pDC->erclWindow.top;
- }
- else
- {
- RECTL_vSetEmptyRect(&rcl);
- }
-
- pdcattr->VisRectRegion.Rect = rcl;
-
- Entry->Flags &= ~GDI_ENTRY_VALIDATE_VIS;
- }
-}
-
BOOL
FASTCALL
IntGdiSetRegionOwner(HRGN hRgn, DWORD OwnerMask)
PRGN_ATTR prgnattr;
PPROCESSINFO ppi;
- prgn = RGNOBJAPI_Lock(hRgn, &prgnattr);
+ prgn = REGION_LockRgn(hRgn);
if (prgn == NULL)
{
return FALSE;
}
+ prgnattr = prgn->prgnattr;
if (prgnattr != &prgn->rgnattr)
{
GDIOBJ_vSetObjectAttr(&prgn->BaseObject, NULL);
GdiPoolFree(ppi->pPoolRgnAttr, prgnattr);
}
- RGNOBJAPI_Unlock(prgn);
+ REGION_UnlockRgn(prgn);
return GreSetObjectOwner(hRgn, OwnerMask);
}
PREGION Rgn;
DWORD ret;
- Rgn = RGNOBJAPI_Lock(hRgn, NULL);
+ Rgn = REGION_LockRgn(hRgn);
if (Rgn == NULL)
{
return ERROR;
}
ret = REGION_GetRgnBox(Rgn, pRect);
- RGNOBJAPI_Unlock(Rgn);
+ REGION_UnlockRgn(Rgn);
return ret;
}
-BOOL
-FASTCALL
-IntGdiPaintRgn(
- PDC dc,
- PREGION Rgn)
-{
- PREGION VisRgn;
- XCLIPOBJ ClipRegion;
- BOOL bRet = FALSE;
- POINTL BrushOrigin;
- SURFACE *psurf;
- PDC_ATTR pdcattr;
-
- if ((dc == NULL) || (Rgn == NULL))
- return FALSE;
-
- pdcattr = dc->pdcattr;
-
- ASSERT(!(pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)));
-
- VisRgn = IntSysCreateRectpRgn(0, 0, 0, 0);
- if (VisRgn == NULL)
- {
- return FALSE;
- }
-
- // Transform region into device co-ords
- if (!REGION_LPTODP(dc, VisRgn, Rgn) ||
- IntGdiOffsetRgn(VisRgn, dc->ptlDCOrig.x, dc->ptlDCOrig.y) == ERROR)
- {
- REGION_Delete(VisRgn);
- return FALSE;
- }
-
- if (dc->prgnRao)
- IntGdiCombineRgn(VisRgn, VisRgn, dc->prgnRao, RGN_AND);
-
- IntEngInitClipObj(&ClipRegion);
- IntEngUpdateClipRegion(&ClipRegion,
- VisRgn->rdh.nCount,
- VisRgn->Buffer,
- &VisRgn->rdh.rcBound );
-
- BrushOrigin.x = pdcattr->ptlBrushOrigin.x;
- BrushOrigin.y = pdcattr->ptlBrushOrigin.y;
- psurf = dc->dclevel.pSurface;
- /* FIXME: Handle psurf == NULL !!!! */
-
- bRet = IntEngPaint(&psurf->SurfObj,
- &ClipRegion.ClipObj,
- &dc->eboFill.BrushObject,
- &BrushOrigin,
- 0xFFFF); // FIXME: Don't know what to put here
-
- REGION_Delete(VisRgn);
- IntEngFreeClipResources(&ClipRegion);
-
- // Fill the region
- return bRet;
-}
BOOL
FASTCALL
}
}
-INT
+BOOL
FASTCALL
-IntGdiOffsetRgn(
- PREGION rgn,
- INT XOffset,
- INT YOffset)
+REGION_bOffsetRgn(
+ _Inout_ PREGION prgn,
+ _In_ INT cx,
+ _In_ INT cy)
{
- if (XOffset || YOffset)
+ PRECTL prcl;
+ UINT i;
+
+ NT_ASSERT(prgn != NULL);
+
+ /* Check for trivial case */
+ if ((cx == 0) && (cy == 0))
+ {
+ return TRUE;
+ }
+
+ /* Check for empty regions, we ignore the offset values here */
+ if (prgn->rdh.nCount == 0)
{
- int nbox = rgn->rdh.nCount;
- PRECTL pbox = rgn->Buffer;
+ return TRUE;
+ }
- if (nbox && pbox)
+ /* Make sure the offset is within the legal range */
+ if ((cx > MAX_COORD) || (cx < MIN_COORD) ||
+ (cy > MAX_COORD) || (cy < MIN_COORD))
+ {
+ return FALSE;
+ }
+
+ /* Are we moving right? */
+ if (cx > 0)
+ {
+ /* Check if we stay inside the bounds on the right side */
+ if (prgn->rdh.rcBound.right > (MAX_COORD - cx))
{
- while (nbox--)
- {
- pbox->left += XOffset;
- pbox->right += XOffset;
- pbox->top += YOffset;
- pbox->bottom += YOffset;
- pbox++;
- }
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* Check if we stay inside the bounds on the left side */
+ if (prgn->rdh.rcBound.left < (MIN_COORD - cx))
+ {
+ return FALSE;
+ }
+ }
- if (rgn->Buffer != &rgn->rdh.rcBound)
- {
- rgn->rdh.rcBound.left += XOffset;
- rgn->rdh.rcBound.right += XOffset;
- rgn->rdh.rcBound.top += YOffset;
- rgn->rdh.rcBound.bottom += YOffset;
- }
+ /* Are we moving down? */
+ if (cy > 0)
+ {
+ /* Check if we stay inside the bounds on the right side */
+ if (prgn->rdh.rcBound.bottom > (MAX_COORD - cy))
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* Check if we stay inside the bounds on the left side */
+ if (prgn->rdh.rcBound.top < (MIN_COORD - cy))
+ {
+ return FALSE;
}
}
- return REGION_Complexity(rgn);
+ /* Loop to move the rects */
+ prcl = prgn->Buffer;
+ for (i = 0; i < prgn->rdh.nCount; i++)
+ {
+ prcl[i].left += cx;
+ prcl[i].right += cx;
+ prcl[i].top += cy;
+ prcl[i].bottom += cy;
+ }
+
+ /* Finally update the bounds rect */
+ if (prgn->Buffer != &prgn->rdh.rcBound)
+ {
+ prgn->rdh.rcBound.left += cx;
+ prgn->rdh.rcBound.right += cx;
+ prgn->rdh.rcBound.top += cy;
+ prgn->rdh.rcBound.bottom += cy;
+ }
+
+ return TRUE;
}
/***********************************************************************
}
/***********************************************************************
- * REGION_CreateEDGE_TABLE
+ * REGION_CreateETandAET
*
* This routine creates the edge table for
* scan converting polygons.
INT iSLLBlock = 0;
INT dy;
- /* Initialize the Active Edge Table */
+ /* Initialize the Active Edge Table */
AET->next = (EDGE_TABLE_ENTRY *)NULL;
AET->back = (EDGE_TABLE_ENTRY *)NULL;
AET->nextWETE = (EDGE_TABLE_ENTRY *)NULL;
BOOL
FASTCALL
-IntSetPolyPolygonRgn(
- POINT *Pts,
- PULONG Count,
- INT nbpolygons,
- INT mode,
- PREGION Rgn)
+REGION_SetPolyPolygonRgn(
+ _Inout_ PREGION prgn,
+ _In_ const POINT *ppt,
+ _In_ const ULONG *pcPoints,
+ _In_ ULONG cPolygons,
+ _In_ INT iMode)
{
EDGE_TABLE_ENTRY *pAET; /* Active Edge Table */
INT y; /* Current scanline */
INT fixWAET = FALSE;
POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
POINTBLOCK *tmpPtBlock;
- INT numFullPtBlocks = 0;
- INT poly, total;
+ UINT numFullPtBlocks = 0;
+ UINT poly, total;
- if (mode == 0 || mode > 2) return 0;
+ /* Check if iMode is valid */
+ if ((iMode != ALTERNATE) && (iMode != WINDING))
+ {
+ DPRINT1("Invalid iMode: %lu\n", iMode);
+ return FALSE;
+ }
/* Special case a rectangle */
- if (((nbpolygons == 1) && ((*Count == 4) ||
- ((*Count == 5) && (Pts[4].x == Pts[0].x) && (Pts[4].y == Pts[0].y)))) &&
- (((Pts[0].y == Pts[1].y) &&
- (Pts[1].x == Pts[2].x) &&
- (Pts[2].y == Pts[3].y) &&
- (Pts[3].x == Pts[0].x)) ||
- ((Pts[0].x == Pts[1].x) &&
- (Pts[1].y == Pts[2].y) &&
- (Pts[2].x == Pts[3].x) &&
- (Pts[3].y == Pts[0].y))))
- {
- REGION_SetRectRgn(Rgn,
- min(Pts[0].x, Pts[2].x),
- min(Pts[0].y, Pts[2].y),
- max(Pts[0].x, Pts[2].x),
- max(Pts[0].y, Pts[2].y));
+ if (((cPolygons == 1) && ((pcPoints[0] == 4) ||
+ ((pcPoints[0] == 5) && (ppt[4].x == ppt[0].x) && (ppt[4].y == ppt[0].y)))) &&
+ (((ppt[0].y == ppt[1].y) &&
+ (ppt[1].x == ppt[2].x) &&
+ (ppt[2].y == ppt[3].y) &&
+ (ppt[3].x == ppt[0].x)) ||
+ ((ppt[0].x == ppt[1].x) &&
+ (ppt[1].y == ppt[2].y) &&
+ (ppt[2].x == ppt[3].x) &&
+ (ppt[3].y == ppt[0].y))))
+ {
+ REGION_SetRectRgn(prgn,
+ min(ppt[0].x, ppt[2].x),
+ min(ppt[0].y, ppt[2].y),
+ max(ppt[0].x, ppt[2].x),
+ max(ppt[0].y, ppt[2].y));
return TRUE;
}
- for (poly = total = 0; poly < nbpolygons; poly++)
- total += Count[poly];
+ for (poly = total = 0; poly < cPolygons; poly++)
+ total += pcPoints[poly];
pETEs = ExAllocatePoolWithTag(PagedPool,
sizeof(EDGE_TABLE_ENTRY) * total,
TAG_REGION);
if (pETEs == NULL)
{
+ DPRINT1("Failed to allocate %lu edge entries\n", total);
return FALSE;
}
pts = FirstPtBlock.pts;
- REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
+ REGION_CreateETandAET(pcPoints, cPolygons, ppt, &ET, &AET, pETEs, &SLLBlock);
pSLL = ET.scanlines.next;
curPtBlock = &FirstPtBlock;
- if (mode != WINDING)
+ if (iMode != WINDING)
{
/* For each scanline */
for (y = ET.ymin; y < ET.ymax; y++)
TAG_REGION);
if (tmpPtBlock == NULL)
{
- DPRINT1("Can't alloc tPB\n");
+ DPRINT1("Can't alloc tmpPtBlock\n");
ExFreePoolWithTag(pETEs, TAG_REGION);
return FALSE;
}
* are in the Winding active edge table. */
if (pWETE == pAET)
{
- pts->x = pAET->bres.minor_axis, pts->y = y;
- pts++, iPts++;
+ pts->x = pAET->bres.minor_axis;
+ pts->y = y;
+ pts++;
+ iPts++;
/* Send out the buffer */
if (iPts == NUMPTSTOBUFFER)
}
REGION_FreeStorage(SLLBlock.next);
- REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, Rgn);
+ REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, prgn);
- for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;)
+ for (curPtBlock = FirstPtBlock.next; numFullPtBlocks-- > 0;)
{
tmpPtBlock = curPtBlock->next;
ExFreePoolWithTag(curPtBlock, TAG_REGION);
return TRUE;
}
+HRGN
+NTAPI
+GreCreatePolyPolygonRgn(
+ _In_ const POINT *ppt,
+ _In_ const ULONG *pcPoints,
+ _In_ ULONG cPolygons,
+ _In_ INT iMode)
+{
+ PREGION prgn;
+ HRGN hrgn;
+
+ /* Allocate a new region */
+ prgn = REGION_AllocUserRgnWithHandle(0);
+ if (prgn == NULL)
+ {
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
+ }
+
+ /* Call the internal function and check for success */
+ if (REGION_SetPolyPolygonRgn(prgn, ppt, pcPoints, cPolygons, iMode))
+ {
+ /* Success, get the handle and unlock the region */
+ hrgn = prgn->BaseObject.hHmgr;
+ REGION_UnlockRgn(prgn);
+ }
+ else
+ {
+ /* Failure, delete the region */
+ REGION_Delete(prgn);
+ hrgn = NULL;
+ }
+
+ return hrgn;
+}
+
BOOL
FASTCALL
IntRectInRegion(
PREGION Rgn;
BOOL Ret;
- Rgn = RGNOBJAPI_Lock(hRgn, NULL);
+ Rgn = REGION_LockRgn(hRgn);
if (Rgn == NULL)
{
return ERROR;
}
Ret = REGION_RectInRegion(Rgn, rc);
- RGNOBJAPI_Unlock(Rgn);
+ REGION_UnlockRgn(Rgn);
return Ret;
}
(hrgnSrc1 == NULL) ||
((iMode != RGN_COPY) && (hrgnSrc2 == NULL)))
{
- DPRINT1("NtGdiCombineRgn: %p, %p, %p, %d\n",
+ DPRINT1("NtGdiCombineRgn invalid parameters: %p, %p, %p, %d\n",
hrgnDst, hrgnSrc1, hrgnSrc2, iMode);
+ EngSetLastError(ERROR_INVALID_HANDLE);
return ERROR;
}
ahrgn[2] = iMode != RGN_COPY ? hrgnSrc2 : NULL;
if (!GDIOBJ_bLockMultipleObjects(3, (HGDIOBJ*)ahrgn, (PVOID*)aprgn, GDIObjType_RGN_TYPE))
{
- DPRINT1("NtGdiCombineRgn: %p, %p, %p, %d\n",
+ DPRINT1("NtGdiCombineRgn failed to lock regions: %p, %p, %p, %d\n",
hrgnDst, hrgnSrc1, hrgnSrc2, iMode);
return ERROR;
}
/* HACK: Sync usermode attributes */
REGION_vSyncRegion(aprgn[0]);
- REGION_vSyncRegion(aprgn[1]);
- if (aprgn[2]) REGION_vSyncRegion(aprgn[2]);
+ if (aprgn[1] != aprgn[0])
+ REGION_vSyncRegion(aprgn[1]);
+ if ((aprgn[2] != NULL) && (aprgn[2] != aprgn[0]) && (aprgn[2] != aprgn[1]))
+ REGION_vSyncRegion(aprgn[2]);
/* Call the internal function */
iResult = IntGdiCombineRgn(aprgn[0], aprgn[1], aprgn[2], iMode);
- /// FIXME: need to sync user attr back
-
- /* Cleanup and return */
+ /* Unlock and return */
REGION_UnlockRgn(aprgn[0]);
REGION_UnlockRgn(aprgn[1]);
- if (aprgn[2])
+ if (aprgn[2] != NULL)
REGION_UnlockRgn(aprgn[2]);
return iResult;
hRgn = pRgn->BaseObject.hHmgr;
REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
- RGNOBJAPI_Unlock(pRgn);
+ REGION_UnlockRgn(pRgn);
DPRINT("Returning %p.\n", hRgn);
REGION_UnionRectWithRgn(obj, &rect);
}
- RGNOBJAPI_Unlock(obj);
+ REGION_UnlockRgn(obj);
return hrgn;
}
HRGN hSrcRgn1,
HRGN hSrcRgn2)
{
+ HRGN ahrgn[2];
+ PREGION aprgn[2];
PREGION rgn1, rgn2;
PRECTL tRect1, tRect2;
ULONG i;
BOOL bRet = FALSE;
- rgn1 = RGNOBJAPI_Lock(hSrcRgn1, NULL);
- if (rgn1 == NULL)
- return ERROR;
+ /* Check if we got 2 regions */
+ if ((hSrcRgn1 == NULL) || (hSrcRgn2 == NULL))
+ {
+ return FALSE;
+ }
- rgn2 = RGNOBJAPI_Lock(hSrcRgn2, NULL);
- if (rgn2 == NULL)
+ /* Check if these are the same regions */
+ if (hSrcRgn1 == hSrcRgn2)
{
- RGNOBJAPI_Unlock(rgn1);
- return ERROR;
+ /* Make sure this region is valid */
+ if ((GDI_HANDLE_GET_TYPE(hSrcRgn1) == GDILoObjType_LO_REGION_TYPE) &&
+ GreIsHandleValid(hSrcRgn1))
+ {
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ /* Lock both regions */
+ ahrgn[0] = hSrcRgn1;
+ ahrgn[1] = hSrcRgn2;
+ if (!GDIOBJ_bLockMultipleObjects(2, (HGDIOBJ*)ahrgn, (PVOID*)aprgn, GDIObjType_RGN_TYPE))
+ {
+ DPRINT1("NtGdiEqualRgn failed to lock regions: %p, %p\n",
+ hSrcRgn1, hSrcRgn2);
+ return FALSE;
}
+ REGION_vSyncRegion(aprgn[0]);
+ REGION_vSyncRegion(aprgn[1]);
+
+ rgn1 = aprgn[0];
+ rgn2 = aprgn[1];
+
if (rgn1->rdh.nCount != rgn2->rdh.nCount)
goto exit;
bRet = TRUE;
exit:
- RGNOBJAPI_Unlock(rgn1);
- RGNOBJAPI_Unlock(rgn2);
+ REGION_UnlockRgn(rgn1);
+ REGION_UnlockRgn(rgn2);
return bRet;
}
if (!NT_SUCCESS(Status))
{
EngSetLastError(ERROR_INVALID_PARAMETER);
- RGNOBJAPI_Unlock(Region);
+ REGION_UnlockRgn(Region);
GreDeleteObject(hRgn);
return NULL;
}
- RGNOBJAPI_Unlock(Region);
+ REGION_UnlockRgn(Region);
return hRgn;
}
-BOOL
-APIENTRY
-NtGdiFillRgn(
- HDC hDC,
- HRGN hRgn,
- HBRUSH hBrush)
-{
- HBRUSH oldhBrush;
- PREGION rgn;
- PRECTL r;
-
- rgn = RGNOBJAPI_Lock(hRgn, NULL);
- if (rgn == NULL)
- {
- return FALSE;
- }
-
- oldhBrush = NtGdiSelectBrush(hDC, hBrush);
- if (oldhBrush == NULL)
- {
- RGNOBJAPI_Unlock(rgn);
- return FALSE;
- }
-
- for (r = rgn->Buffer; r < rgn->Buffer + rgn->rdh.nCount; r++)
- {
- NtGdiPatBlt(hDC, r->left, r->top, r->right - r->left, r->bottom - r->top, PATCOPY);
- }
-
- RGNOBJAPI_Unlock(rgn);
- NtGdiSelectBrush(hDC, oldhBrush);
-
- return TRUE;
-}
-
-BOOL
-APIENTRY
-NtGdiFrameRgn(
- HDC hDC,
- HRGN hRgn,
- HBRUSH hBrush,
- INT Width,
- INT Height)
-{
- HRGN FrameRgn;
- BOOL Ret;
-
- FrameRgn = NtGdiCreateRectRgn(0, 0, 0, 0);
- if (FrameRgn == NULL)
- {
- return FALSE;
- }
-
- if (!REGION_CreateFrameRgn(FrameRgn, hRgn, Width, Height))
- {
- GreDeleteObject(FrameRgn);
- return FALSE;
- }
-
- Ret = NtGdiFillRgn(hDC, FrameRgn, hBrush);
-
- GreDeleteObject(FrameRgn);
- return Ret;
-}
-
-
INT
APIENTRY
NtGdiGetRgnBox(
DWORD ret;
NTSTATUS Status = STATUS_SUCCESS;
- Rgn = RGNOBJAPI_Lock(hRgn, NULL);
+ Rgn = REGION_LockRgn(hRgn);
if (Rgn == NULL)
{
return ERROR;
}
ret = REGION_GetRgnBox(Rgn, &SafeRect);
- RGNOBJAPI_Unlock(Rgn);
+ REGION_UnlockRgn(Rgn);
if (ret == ERROR)
{
return ret;
return ret;
}
-BOOL
-APIENTRY
-NtGdiInvertRgn(
- HDC hDC,
- HRGN hRgn)
-{
- PREGION RgnData;
- ULONG i;
- PRECTL rc;
-
- RgnData = RGNOBJAPI_Lock(hRgn, NULL);
- if (RgnData == NULL)
- {
- EngSetLastError(ERROR_INVALID_HANDLE);
- return FALSE;
- }
-
- rc = RgnData->Buffer;
- for (i = 0; i < RgnData->rdh.nCount; i++)
- {
-
- if (!NtGdiPatBlt(hDC, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, DSTINVERT))
- {
- RGNOBJAPI_Unlock(RgnData);
- return FALSE;
- }
- rc++;
- }
-
- RGNOBJAPI_Unlock(RgnData);
- return TRUE;
-}
-
INT
APIENTRY
NtGdiOffsetRgn(
- HRGN hRgn,
- INT XOffset,
- INT YOffset)
+ _In_ HRGN hrgn,
+ _In_ INT cx,
+ _In_ INT cy)
{
- PREGION rgn;
- INT ret;
+ PREGION prgn;
+ INT iResult;
- DPRINT("NtGdiOffsetRgn: hRgn %p Xoffs %d Yoffs %d rgn %p\n", hRgn, XOffset, YOffset, rgn );
+ DPRINT("NtGdiOffsetRgn: hrgn %p cx %d cy %d\n", hrgn, cx, cy);
- rgn = RGNOBJAPI_Lock(hRgn, NULL);
- if (rgn == NULL)
+ /* Lock the region */
+ prgn = REGION_LockRgn(hrgn);
+ if (prgn == NULL)
{
- DPRINT("NtGdiOffsetRgn: hRgn error\n");
+ DPRINT1("NtGdiOffsetRgn: failed to lock region %p\n", hrgn);
return ERROR;
}
- ret = IntGdiOffsetRgn(rgn, XOffset, YOffset);
+ /* Call the internal function */
+ if (!REGION_bOffsetRgn(prgn, cx, cy))
+ {
+ iResult = ERROR;
+ }
+ else
+ {
+ iResult = REGION_Complexity(prgn);
+ }
- RGNOBJAPI_Unlock(rgn);
- return ret;
+ /* Unlock and return the result */
+ REGION_UnlockRgn(prgn);
+ return iResult;
}
BOOL
APIENTRY
NtGdiPtInRegion(
- HRGN hRgn,
- INT X,
- INT Y)
+ _In_ HRGN hrgn,
+ _In_ INT x,
+ _In_ INT y)
{
PREGION prgn;
- BOOL ret;
+ BOOL bResult;
- prgn = RGNOBJAPI_Lock(hRgn, NULL);
+ /* Lock the region */
+ prgn = REGION_LockRgn(hrgn);
if (prgn == NULL)
+ {
+ DPRINT1("NtGdiPtInRegion: hrgn error\n");
return FALSE;
+ }
- ret = REGION_PtInRegion(prgn, X, Y);
+ /* Call the internal function */
+ bResult = REGION_PtInRegion(prgn, x, y);
- RGNOBJAPI_Unlock(prgn);
- return ret;
+ /* Unlock and return the result */
+ REGION_UnlockRgn(prgn);
+ return bResult;
}
+__kernel_entry
BOOL
APIENTRY
NtGdiRectInRegion(
- HRGN hRgn,
- LPRECTL unsaferc)
+ _In_ HRGN hrgn,
+ _Inout_ LPRECT prclUnsafe)
{
- RECTL rc = { 0 };
- NTSTATUS Status = STATUS_SUCCESS;
+ RECTL rcTemp;
+ /* Probe and copy the rect */
_SEH2_TRY
{
- ProbeForRead(unsaferc, sizeof(RECT), 1);
- rc = *unsaferc;
+ ProbeForRead(prclUnsafe, sizeof(RECT), 1);
+ rcTemp = *prclUnsafe;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- Status = _SEH2_GetExceptionCode();
+ DPRINT1("NtGdiRectInRegion: Exception accessing the rect\n");
+ return FALSE;
}
_SEH2_END;
- if (!NT_SUCCESS(Status))
- {
- SetLastNtError(Status);
- DPRINT1("NtGdiRectInRegion: Bogus rc\n");
- return ERROR;
- }
-
- return IntRectInRegion(hRgn, &rc);
+ /* Call the internal function */
+ return IntRectInRegion(hrgn, &rcTemp);
}
BOOL
APIENTRY
NtGdiSetRectRgn(
- HRGN hRgn,
- INT LeftRect,
- INT TopRect,
- INT RightRect,
- INT BottomRect)
+ _In_ HRGN hrgn,
+ _In_ INT xLeft,
+ _In_ INT yTop,
+ _In_ INT xRight,
+ _In_ INT yBottom)
{
- PREGION rgn;
+ PREGION prgn;
- rgn = RGNOBJAPI_Lock(hRgn, NULL);
- if (rgn == NULL)
+ /* Lock the region */
+ prgn = REGION_LockRgn(hrgn);
+ if (prgn == NULL)
{
- return 0; // Per documentation
+ return FALSE;
}
- REGION_SetRectRgn(rgn, LeftRect, TopRect, RightRect, BottomRect);
+ /* Call the internal API */
+ REGION_SetRectRgn(prgn, xLeft, yTop, xRight, yBottom);
- RGNOBJAPI_Unlock(rgn);
+ /* Unlock the region and return success */
+ REGION_UnlockRgn(prgn);
return TRUE;
}
-HRGN
-APIENTRY
-NtGdiUnionRectWithRgn(
- HRGN hDest,
- const RECTL *UnsafeRect)
-{
- RECTL SafeRect = { 0 };
- PREGION Rgn;
- NTSTATUS Status = STATUS_SUCCESS;
-
- Rgn = RGNOBJAPI_Lock(hDest, NULL);
- if (Rgn == NULL)
- {
- EngSetLastError(ERROR_INVALID_HANDLE);
- return NULL;
- }
-
- _SEH2_TRY
- {
- ProbeForRead(UnsafeRect, sizeof(RECT), 1);
- SafeRect = *UnsafeRect;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END;
-
- if (!NT_SUCCESS(Status))
- {
- RGNOBJAPI_Unlock(Rgn);
- SetLastNtError(Status);
- return NULL;
- }
-
- REGION_UnionRectWithRgn(Rgn, &SafeRect);
- RGNOBJAPI_Unlock(Rgn);
- return hDest;
-}
-
/*!
* MSDN: GetRegionData, Return Values:
*
* If the function fails, the return value is zero."
*/
_Success_(return!=0)
+__kernel_entry
ULONG
APIENTRY
NtGdiGetRegionData(
_In_ HRGN hrgn,
_In_ ULONG cjBuffer,
- _Out_opt_bytecap_(cjBuffer) LPRGNDATA lpRgnData)
+ _Out_writes_bytes_to_opt_(cjBuffer, return) LPRGNDATA lpRgnData)
{
ULONG cjRects, cjSize;
PREGION prgn;
/* Lock the region */
- prgn = RGNOBJAPI_Lock(hrgn, NULL);
+ prgn = REGION_LockRgn(hrgn);
if (prgn == NULL)
{
EngSetLastError(ERROR_INVALID_HANDLE);
RtlCopyMemory(lpRgnData, &prgn->rdh, sizeof(RGNDATAHEADER));
RtlCopyMemory(lpRgnData->Buffer, prgn->Buffer, cjRects);
lpRgnData->rdh.iType = RDH_RECTANGLES;
+ lpRgnData->rdh.nRgnSize = cjRects;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
}
/* Unlock the region and return the size */
- RGNOBJAPI_Unlock(prgn);
+ REGION_UnlockRgn(prgn);
return cjSize;
}