* the y-x-banding that's so nice to have...
*/
-#include <w32k.h>
+#include <win32k.h>
#define NDEBUG
#include <debug.h>
{
ROSRGNDATA *Data;
- Data = REGION_LockRgn(hRgn);
+ Data = RGNOBJAPI_Lock(hRgn, NULL);
if (Data == NULL)
{
DbgPrint("IntDumpRegion called with invalid region!\n");
Data->rdh.rcBound.bottom,
Data->rdh.iType);
- REGION_UnlockRgn(Data);
+ RGNOBJAPI_Unlock(Data);
}
#endif /* not NDEBUG */
else
{
xrect = ExAllocatePoolWithTag(PagedPool, rgnSrc->rdh.nCount * sizeof(RECT), TAG_REGION);
+ if(!xrect)
+ return FALSE;
if (rgnDst->Buffer && rgnDst->Buffer != &rgnDst->rdh.rcBound)
ExFreePoolWithTag(rgnDst->Buffer, TAG_REGION); //free the old buffer. will be assigned to xrect below.
}
- if (xrect)
+ if (rgnDst != rgnSrc)
{
- ULONG i;
-
- if (rgnDst != rgnSrc)
- {
- *rgnDst = *rgnSrc;
- }
+ *rgnDst = *rgnSrc;
+ }
- if (off->x || off->y)
- {
- for (i = 0; i < rgnDst->rdh.nCount; i++)
- {
- xrect[i].left = (rgnSrc->Buffer + i)->left + off->x;
- xrect[i].right = (rgnSrc->Buffer + i)->right + off->x;
- xrect[i].top = (rgnSrc->Buffer + i)->top + off->y;
- xrect[i].bottom = (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
+ if (off->x || off->y)
+ {
+ ULONG i;
+ for (i = 0; i < rgnDst->rdh.nCount; i++)
{
- COPY_RECTS(xrect, rgnSrc->Buffer, rgnDst->rdh.nCount);
+ xrect[i].left = (rgnSrc->Buffer + i)->left + off->x;
+ xrect[i].right = (rgnSrc->Buffer + i)->right + off->x;
+ xrect[i].top = (rgnSrc->Buffer + i)->top + off->y;
+ xrect[i].bottom = (rgnSrc->Buffer + i)->bottom + off->y;
}
-
- rgnDst->Buffer = xrect;
+ 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
- return FALSE;
+ {
+ COPY_RECTS(xrect, rgnSrc->Buffer, rgnDst->rdh.nCount);
+ }
+
+ rgnDst->Buffer = xrect;
}
else if ((rect->left >= rect->right) ||
(rect->top >= rect->bottom) ||
pNextRect++;
}
r1++;
- left = r1->left;
+ if (r1 != r1End)
+ left = r1->left;
}
}
trb = REGION_AllocRgnWithHandle(srb->rdh.nCount + 1);
if (!trb)
{
- REGION_UnlockRgn(tra);
+ RGNOBJAPI_Unlock(tra);
GreDeleteObject(htra);
return;
}
REGION_SubtractRegion(tra, sra, srb);
REGION_SubtractRegion(trb, srb, sra);
REGION_UnionRegion(dr, tra, trb);
- REGION_UnlockRgn(tra);
- REGION_UnlockRgn(trb);
+ RGNOBJAPI_Unlock(tra);
+ RGNOBJAPI_Unlock(trb);
GreDeleteObject(htra);
GreDeleteObject(htrb);
PRECTL rc;
ULONG i;
- if (!(srcObj = REGION_LockRgn(hSrc)))
+ if (!(srcObj = RGNOBJAPI_Lock(hSrc, NULL)))
{
return FALSE;
}
if (!REGION_NOT_EMPTY(srcObj))
{
- REGION_UnlockRgn(srcObj);
+ RGNOBJAPI_Unlock(srcObj);
return FALSE;
}
- if (!(destObj = REGION_LockRgn(hDest)))
+ if (!(destObj = RGNOBJAPI_Lock(hDest, NULL)))
{
- REGION_UnlockRgn(srcObj);
+ RGNOBJAPI_Unlock(srcObj);
return FALSE;
}
EMPTY_REGION(destObj);
if (!REGION_CopyRegion(destObj, srcObj))
{
- REGION_UnlockRgn(destObj);
- REGION_UnlockRgn(srcObj);
+ RGNOBJAPI_Unlock(destObj);
+ RGNOBJAPI_Unlock(srcObj);
return FALSE;
}
if (!REGION_CreateSimpleFrameRgn(destObj, x, y))
{
EMPTY_REGION(destObj);
- REGION_UnlockRgn(destObj);
- REGION_UnlockRgn(srcObj);
+ RGNOBJAPI_Unlock(destObj);
+ RGNOBJAPI_Unlock(srcObj);
return FALSE;
}
}
REGION_SubtractRegion(destObj, srcObj, destObj);
}
- REGION_UnlockRgn(destObj);
- REGION_UnlockRgn(srcObj);
+ RGNOBJAPI_Unlock(destObj);
+ RGNOBJAPI_Unlock(srcObj);
return TRUE;
}
goto done;
}
- if ( !(srcObj = REGION_LockRgn(hSrc)) )
+ if ( !(srcObj = RGNOBJAPI_Lock(hSrc, NULL)) )
goto done;
- if ( !(destObj = REGION_LockRgn(hDest)) )
+ if ( !(destObj = RGNOBJAPI_Lock(hDest, NULL)) )
{
- REGION_UnlockRgn(srcObj);
+ RGNOBJAPI_Unlock(srcObj);
goto done;
}
EMPTY_REGION(destObj);
}
ret = TRUE;
- REGION_UnlockRgn(srcObj);
- REGION_UnlockRgn(destObj);
+ RGNOBJAPI_Unlock(srcObj);
+ RGNOBJAPI_Unlock(destObj);
done:
return ret;
{
HRGN hReg;
PROSRGNDATA pReg;
-
+
pReg = (PROSRGNDATA)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_REGION);
if(!pReg)
{
return NULL;
}
-
+
hReg = pReg->BaseObject.hHmgr;
if (nReg == 0 || nReg == 1)
pReg->Buffer = ExAllocatePoolWithTag(PagedPool, nReg * sizeof(RECT), TAG_REGION);
if (!pReg->Buffer)
{
- REGION_UnlockRgn(pReg);
+ RGNOBJAPI_Unlock(pReg);
GDIOBJ_FreeObjByHandle(hReg, GDI_OBJECT_TYPE_REGION);
return NULL;
}
return pReg;
}
+//
+// Allocate User Space Region Handle.
+//
+PROSRGNDATA
+FASTCALL
+REGION_AllocUserRgnWithHandle(INT nRgn)
+{
+ PROSRGNDATA pRgn;
+ PGDI_TABLE_ENTRY Entry;
+
+ pRgn = REGION_AllocRgnWithHandle(nRgn);
+ if (pRgn)
+ {
+ Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, pRgn->BaseObject.hHmgr);
+ Entry->UserData = AllocateObjectAttr();
+ }
+ return pRgn;
+}
+
+PROSRGNDATA
+FASTCALL
+RGNOBJAPI_Lock(HRGN hRgn, PRGN_ATTR *ppRgn_Attr)
+{
+ PGDI_TABLE_ENTRY Entry;
+ PRGN_ATTR pRgn_Attr;
+ PROSRGNDATA pRgn = NULL;
+
+ pRgn = REGION_LockRgn(hRgn);
+
+ if (pRgn && GDIOBJ_OwnedByCurrentProcess(hRgn))
+ {
+ Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, hRgn);
+ pRgn_Attr = Entry->UserData;
+
+ if ( pRgn_Attr )
+ {
+ _SEH2_TRY
+ {
+ if ( !(pRgn_Attr->AttrFlags & ATTR_CACHED) &&
+ pRgn_Attr->AttrFlags & (ATTR_RGN_VALID|ATTR_RGN_DIRTY) )
+ {
+ switch (pRgn_Attr->Flags)
+ {
+ 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)
+ {
+ }
+ _SEH2_END;
+
+ if (ppRgn_Attr)
+ *ppRgn_Attr = pRgn_Attr;
+ }
+ else
+ {
+ if (ppRgn_Attr)
+ *ppRgn_Attr = NULL;
+ }
+ }
+ return pRgn;
+}
+
+VOID
+FASTCALL
+RGNOBJAPI_Unlock(PROSRGNDATA pRgn)
+{
+ PGDI_TABLE_ENTRY Entry;
+ PRGN_ATTR pRgn_Attr;
+
+ if (pRgn && GDIOBJ_OwnedByCurrentProcess(pRgn->BaseObject.hHmgr))
+ {
+ Entry = GDI_HANDLE_GET_ENTRY(GdiHandleTable, pRgn->BaseObject.hHmgr);
+ pRgn_Attr = Entry->UserData;
+
+ if ( pRgn_Attr )
+ {
+ _SEH2_TRY
+ {
+ if ( pRgn_Attr->AttrFlags & ATTR_RGN_VALID )
+ {
+ pRgn_Attr->Flags = 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)
+ {
+ }
+ _SEH2_END;
+ }
+ }
+ REGION_UnlockRgn(pRgn);
+}
+
+/*
+ System Regions:
+ These regions do not use attribute sections and when allocated, use gdiobj
+ level functions.
+*/
+//
+// System Region Functions
+//
+PROSRGNDATA
+FASTCALL
+IntSysCreateRectpRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
+{
+ PROSRGNDATA pRgn;
+
+ pRgn = (PROSRGNDATA)GDIOBJ_AllocObjWithHandle(GDI_OBJECT_TYPE_REGION);
+ if (!pRgn)
+ {
+ return NULL;
+ }
+ pRgn->Buffer = &pRgn->rdh.rcBound;
+ REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
+ REGION_UnlockRgn(pRgn);
+ return pRgn;
+}
+
+HRGN
+FASTCALL
+IntSysCreateRectRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
+{
+ PROSRGNDATA pRgn = IntSysCreateRectpRgn(LeftRect,TopRect,RightRect,BottomRect);
+ return (pRgn ? pRgn->BaseObject.hHmgr : NULL);
+}
+
BOOL INTERNAL_CALL
REGION_Cleanup(PVOID ObjectBody)
{
PROSRGNDATA pRgn = (PROSRGNDATA)ObjectBody;
if (pRgn->Buffer && pRgn->Buffer != &pRgn->rdh.rcBound)
- ExFreePool(pRgn->Buffer);
+ ExFreePoolWithTag(pRgn->Buffer, TAG_REGION);
return TRUE;
}
+// use REGION_FreeRgnByHandle(hRgn); for systems regions.
VOID FASTCALL
REGION_Delete(PROSRGNDATA pRgn)
{
REGION_FreeRgn(pRgn);
}
-
VOID FASTCALL
IntGdiReleaseRaoRgn(PDC pDC)
{
RECTL_vSetEmptyRect(&pDC->erclClip);
}
-
VOID FASTCALL
IntGdiReleaseVisRgn(PDC pDC)
{
}
else if (src2Rgn == NULL)
{
- DPRINT1("IntGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode);
+ DPRINT1("IntGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode);
+ EngSetLastError(ERROR_INVALID_HANDLE);
}
}
}
+ else
+ {
+ DPRINT("IntGdiCombineRgn: hSrc1 unavailable\n");
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ }
}
else
{
DPRINT("IntGdiCombineRgn: hDest unavailable\n");
- result = ERROR;
+ EngSetLastError(ERROR_INVALID_HANDLE);
}
return result;
}
-
-// NtGdi Exported Functions
-INT
-APIENTRY
-NtGdiCombineRgn(HRGN hDest,
- HRGN hSrc1,
- HRGN hSrc2,
- INT CombineMode)
+INT FASTCALL
+REGION_GetRgnBox(
+ PROSRGNDATA Rgn,
+ PRECTL pRect
+)
{
- INT result = ERROR;
- PROSRGNDATA destRgn, src1Rgn, src2Rgn;
+ DWORD ret;
- destRgn = REGION_LockRgn(hDest);
- if (destRgn)
+ if (Rgn)
{
- src1Rgn = REGION_LockRgn(hSrc1);
- if (src1Rgn)
- {
- if (CombineMode == RGN_COPY)
- {
- if ( !REGION_CopyRegion(destRgn, src1Rgn) )
- return ERROR;
- result = REGION_Complexity(destRgn);
- }
- else
- {
- src2Rgn = REGION_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;
- }
- REGION_UnlockRgn(src2Rgn);
- result = REGION_Complexity(destRgn);
- }
- else if (hSrc2 == NULL)
- {
- DPRINT1("NtGdiCombineRgn requires hSrc2 != NULL for combine mode %d!\n", CombineMode);
- }
- }
-
- REGION_UnlockRgn(src1Rgn);
- }
+ *pRect = Rgn->rdh.rcBound;
+ ret = REGION_Complexity(Rgn);
- REGION_UnlockRgn(destRgn);
- }
- else
- {
- DPRINT("NtGdiCombineRgn: hDest unavailable\n");
- result = ERROR;
+ return ret;
}
-
- return result;
+ return 0; //if invalid region return zero
}
-HRGN
-APIENTRY
-NtGdiCreateEllipticRgn(
- INT Left,
- INT Top,
- INT Right,
- INT Bottom
+INT APIENTRY
+IntGdiGetRgnBox(
+ HRGN hRgn,
+ PRECTL pRect
)
{
- return NtGdiCreateRoundRectRgn(Left, Top, Right, Bottom,
- Right - Left, Bottom - Top);
-}
-
-PROSRGNDATA
-FASTCALL
-IntGdiCreateRectRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
-{
- PROSRGNDATA pRgn;
-
- if (!(pRgn = REGION_AllocRgnWithHandle(1))) return NULL;
-
- REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
- REGION_UnlockRgn(pRgn);
- // Return pointer with Share locks.
- pRgn = GDIOBJ_ShareLockObj(pRgn->BaseObject.hHmgr, GDI_OBJECT_TYPE_REGION);
-
- return pRgn;
-}
-
-
-HRGN APIENTRY
-NtGdiCreateRectRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
-{
- PROSRGNDATA pRgn;
- HRGN hRgn;
+ PROSRGNDATA Rgn;
+ DWORD ret;
- /* Allocate region data structure with space for 1 RECTL */
- if (!(pRgn = REGION_AllocRgnWithHandle(1)))
+ if (!(Rgn = RGNOBJAPI_Lock(hRgn, NULL)))
{
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- return NULL;
+ return ERROR;
}
- hRgn = pRgn->BaseObject.hHmgr;
- REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
- REGION_UnlockRgn(pRgn);
+ ret = REGION_GetRgnBox(Rgn, pRect);
+ RGNOBJAPI_Unlock(Rgn);
- return hRgn;
+ return ret;
}
-
-HRGN
-APIENTRY
-NtGdiCreateRoundRectRgn(
- INT left,
- INT top,
- INT right,
- INT bottom,
- INT ellipse_width,
- INT ellipse_height
+BOOL
+FASTCALL
+IntGdiPaintRgn(
+ PDC dc,
+ HRGN hRgn
)
{
- PROSRGNDATA obj;
- HRGN hrgn;
- int asq, bsq, d, xd, yd;
- RECTL rect;
+ HRGN tmpVisRgn;
+ PROSRGNDATA visrgn;
+ CLIPOBJ* ClipRegion;
+ BOOL bRet = FALSE;
+ POINTL BrushOrigin;
+ SURFACE *psurf;
+ PDC_ATTR pdcattr;
- /* Make the dimensions sensible */
+ if (!dc) return FALSE;
+ pdcattr = dc->pdcattr;
- if (left > right)
- {
- INT tmp = left;
- left = right;
- right = tmp;
- }
- if (top > bottom)
+ ASSERT(!(pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)));
+
+ if (!(tmpVisRgn = IntSysCreateRectRgn(0, 0, 0, 0))) return FALSE;
+
+ // Transform region into device co-ords
+ if (!REGION_LPTODP(dc, tmpVisRgn, hRgn) ||
+ NtGdiOffsetRgn(tmpVisRgn, dc->ptlDCOrig.x, dc->ptlDCOrig.y) == ERROR)
{
- INT tmp = top;
- top = bottom;
- bottom = tmp;
+ REGION_FreeRgnByHandle(tmpVisRgn);
+ return FALSE;
}
- ellipse_width = abs(ellipse_width);
- ellipse_height = abs(ellipse_height);
+ NtGdiCombineRgn(tmpVisRgn, tmpVisRgn, dc->rosdc.hGCClipRgn, RGN_AND);
- /* Check parameters */
+ visrgn = RGNOBJAPI_Lock(tmpVisRgn, NULL);
+ if (visrgn == NULL)
+ {
+ REGION_FreeRgnByHandle(tmpVisRgn);
+ return FALSE;
+ }
- if (ellipse_width > right-left) ellipse_width = right-left;
- if (ellipse_height > bottom-top) ellipse_height = bottom-top;
+ ClipRegion = IntEngCreateClipRegion(visrgn->rdh.nCount,
+ visrgn->Buffer,
+ &visrgn->rdh.rcBound );
+ ASSERT(ClipRegion);
- /* Check if we can do a normal rectangle instead */
+ BrushOrigin.x = pdcattr->ptlBrushOrigin.x;
+ BrushOrigin.y = pdcattr->ptlBrushOrigin.y;
+ psurf = dc->dclevel.pSurface;
+ /* FIXME - Handle psurf == NULL !!!! */
- if ((ellipse_width < 2) || (ellipse_height < 2))
- return NtGdiCreateRectRgn(left, top, right, bottom);
+ bRet = IntEngPaint(&psurf->SurfObj,
+ ClipRegion,
+ &dc->eboFill.BrushObject,
+ &BrushOrigin,
+ 0xFFFF);//FIXME:don't know what to put here
- /* Create region */
+ RGNOBJAPI_Unlock(visrgn);
+ REGION_FreeRgnByHandle(tmpVisRgn);
- d = (ellipse_height < 128) ? ((3 * ellipse_height) >> 2) : 64;
- if (!(obj = REGION_AllocRgnWithHandle(d))) 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 */
-
- 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;
- REGION_UnionRectWithRgn(obj, &rect);
- rect.top = --bottom;
- rect.bottom = rect.top + 1;
- REGION_UnionRectWithRgn(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;
- REGION_UnionRectWithRgn(obj, &rect);
- rect.top = --bottom;
- rect.bottom = rect.top + 1;
- REGION_UnionRectWithRgn(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;
- REGION_UnionRectWithRgn(obj, &rect);
- }
-
- REGION_UnlockRgn(obj);
- return hrgn;
-}
+ // Fill the region
+ return bRet;
+}
BOOL
-APIENTRY
-NtGdiEqualRgn(
- HRGN hSrcRgn1,
- HRGN hSrcRgn2
+FASTCALL
+REGION_RectInRegion(
+ PROSRGNDATA Rgn,
+ const RECTL *rect
)
{
- PROSRGNDATA rgn1, rgn2;
- PRECTL tRect1, tRect2;
- ULONG i;
- BOOL bRet = FALSE;
+ PRECTL pCurRect, pRectEnd;
+ RECT rc;
- if ( !(rgn1 = REGION_LockRgn(hSrcRgn1)) )
- return ERROR;
+ /* swap the coordinates to make right >= left and bottom >= top */
+ /* (region building rectangles are normalized the same way) */
+ if( rect->top > rect->bottom) {
+ rc.top = rect->bottom;
+ rc.bottom = rect->top;
+ } else {
+ rc.top = rect->top;
+ rc.bottom = rect->bottom;
+ }
+ if( rect->right < rect->left) {
+ rc.right = rect->left;
+ rc.left = rect->right;
+ } else {
+ rc.right = rect->right;
+ rc.left = rect->left;
+ }
- if ( !(rgn2 = REGION_LockRgn(hSrcRgn2)) )
+ /* this is (just) a useful optimization */
+ if ((Rgn->rdh.nCount > 0) && EXTENTCHECK(&Rgn->rdh.rcBound, &rc))
{
- REGION_UnlockRgn(rgn1);
- return ERROR;
- }
+ for (pCurRect = Rgn->Buffer, pRectEnd = pCurRect +
+ Rgn->rdh.nCount; pCurRect < pRectEnd; pCurRect++)
+ {
+ if (pCurRect->bottom <= rc.top)
+ continue; /* not far enough down yet */
- 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;
+ if (pCurRect->top >= rc.bottom)
+ break; /* too far down */
- tRect1 = rgn1->Buffer;
- tRect2 = rgn2->Buffer;
+ if (pCurRect->right <= rc.left)
+ continue; /* not far enough over yet */
- if (!tRect1 || !tRect2)
- goto exit;
+ if (pCurRect->left >= rc.right) {
+ continue;
+ }
- 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;
+ return TRUE;
+ }
}
- bRet = TRUE;
-
-exit:
- REGION_UnlockRgn(rgn1);
- REGION_UnlockRgn(rgn2);
- return bRet;
+ return FALSE;
}
-HRGN
-APIENTRY
-NtGdiExtCreateRegion(
- OPTIONAL LPXFORM Xform,
- DWORD Count,
- LPRGNDATA RgnData
+VOID
+FASTCALL
+REGION_SetRectRgn(
+ PROSRGNDATA rgn,
+ INT LeftRect,
+ INT TopRect,
+ INT RightRect,
+ INT BottomRect
)
{
- HRGN hRgn;
- PROSRGNDATA Region;
- DWORD nCount = 0;
- DWORD iType = 0;
- DWORD dwSize = 0;
- NTSTATUS Status = STATUS_SUCCESS;
- MATRIX matrix;
+ PRECTL firstRect;
- DPRINT("NtGdiExtCreateRegion\n");
- _SEH2_TRY
- {
- ProbeForRead(RgnData, Count, 1);
- nCount = RgnData->rdh.nCount;
- iType = RgnData->rdh.iType;
- dwSize = RgnData->rdh.dwSize;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ if (LeftRect > RightRect)
{
- Status = _SEH2_GetExceptionCode();
+ INT tmp = LeftRect;
+ LeftRect = RightRect;
+ RightRect = tmp;
}
- _SEH2_END;
- if (!NT_SUCCESS(Status))
+ if (TopRect > BottomRect)
{
- SetLastNtError(Status);
- return NULL;
+ INT tmp = TopRect;
+ TopRect = BottomRect;
+ BottomRect = tmp;
}
- /* Check parameters, but don't set last error here */
- if (Count < sizeof(RGNDATAHEADER) + nCount * sizeof(RECT) ||
- iType != RDH_RECTANGLES ||
- dwSize != sizeof(RGNDATAHEADER))
+ if ((LeftRect != RightRect) && (TopRect != BottomRect))
{
- return NULL;
+ firstRect = rgn->Buffer;
+ ASSERT(firstRect);
+ firstRect->left = rgn->rdh.rcBound.left = LeftRect;
+ firstRect->top = rgn->rdh.rcBound.top = TopRect;
+ firstRect->right = rgn->rdh.rcBound.right = RightRect;
+ firstRect->bottom = rgn->rdh.rcBound.bottom = BottomRect;
+ rgn->rdh.nCount = 1;
+ rgn->rdh.iType = RDH_RECTANGLES;
}
-
- Region = REGION_AllocRgnWithHandle(nCount);
-
- if (Region == NULL)
+ else
{
- SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
- return FALSE;
+ EMPTY_REGION(rgn);
}
- hRgn = Region->BaseObject.hHmgr;
+}
- _SEH2_TRY
+INT
+FASTCALL
+IntGdiOffsetRgn(
+ PROSRGNDATA rgn,
+ INT XOffset,
+ INT YOffset )
+{
+ if (XOffset || YOffset)
{
- if (Xform)
- {
- ULONG ret;
-
- /* Init the XFORMOBJ from the Xform struct */
- Status = STATUS_INVALID_PARAMETER;
- ret = XFORMOBJ_iSetXform((XFORMOBJ*)&matrix, (XFORML*)Xform);
+ int nbox = rgn->rdh.nCount;
+ PRECTL pbox = rgn->Buffer;
- /* Check for error, also no scale and shear allowed */
- if (ret != DDI_ERROR && ret != GX_GENERAL)
+ if (nbox && pbox)
+ {
+ while (nbox--)
{
- /* Apply the coordinate transformation on the rects */
- if (XFORMOBJ_bApplyXform((XFORMOBJ*)&matrix,
- XF_LTOL,
- nCount * 2,
- RgnData->Buffer,
- Region->Buffer))
- {
- Status = STATUS_SUCCESS;
- }
+ pbox->left += XOffset;
+ pbox->right += XOffset;
+ pbox->top += YOffset;
+ pbox->bottom += YOffset;
+ pbox++;
+ }
+ 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;
}
}
- else
- {
- /* Copy rect coordinates */
- RtlCopyMemory(Region->Buffer,
- RgnData->Buffer,
- nCount * sizeof(RECT));
- }
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
- {
- Status = _SEH2_GetExceptionCode();
- }
- _SEH2_END;
- if (!NT_SUCCESS(Status))
- {
- SetLastWin32Error(ERROR_INVALID_PARAMETER);
- REGION_UnlockRgn(Region);
- GreDeleteObject(hRgn);
- return NULL;
}
-
- REGION_UnlockRgn(Region);
-
- return hRgn;
+ return REGION_Complexity(rgn);
}
-BOOL
-APIENTRY
-NtGdiFillRgn(
- HDC hDC,
- HRGN hRgn,
- HBRUSH hBrush
+/***********************************************************************
+ * REGION_InsertEdgeInET
+ *
+ * Insert the given edge into the edge table.
+ * First we must find the correct bucket in the
+ * Edge table, then find the right slot in the
+ * bucket. Finally, we can insert it.
+ *
+ */
+static void FASTCALL
+REGION_InsertEdgeInET(
+ EdgeTable *ET,
+ EdgeTableEntry *ETE,
+ INT scanline,
+ ScanLineListBlock **SLLBlock,
+ INT *iSLLBlock
)
{
- HBRUSH oldhBrush;
- PROSRGNDATA rgn;
- PRECTL r;
+ EdgeTableEntry *start, *prev;
+ ScanLineList *pSLL, *pPrevSLL;
+ ScanLineListBlock *tmpSLLBlock;
- if (NULL == (rgn = REGION_LockRgn(hRgn)))
+ /*
+ * find the right bucket to put the edge into
+ */
+ pPrevSLL = &ET->scanlines;
+ pSLL = pPrevSLL->next;
+ while (pSLL && (pSLL->scanline < scanline))
{
- return FALSE;
+ pPrevSLL = pSLL;
+ pSLL = pSLL->next;
}
- if (NULL == (oldhBrush = NtGdiSelectBrush(hDC, hBrush)))
+ /*
+ * reassign pSLL (pointer to ScanLineList) if necessary
+ */
+ if ((!pSLL) || (pSLL->scanline > scanline))
{
- REGION_UnlockRgn(rgn);
- return FALSE;
+ if (*iSLLBlock > SLLSPERBLOCK-1)
+ {
+ tmpSLLBlock = ExAllocatePoolWithTag(PagedPool, sizeof(ScanLineListBlock), TAG_REGION);
+ if (!tmpSLLBlock)
+ {
+ DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
+ /* FIXME - free resources? */
+ return;
+ }
+ (*SLLBlock)->next = tmpSLLBlock;
+ tmpSLLBlock->next = (ScanLineListBlock *)NULL;
+ *SLLBlock = tmpSLLBlock;
+ *iSLLBlock = 0;
+ }
+ pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
+
+ pSLL->next = pPrevSLL->next;
+ pSLL->edgelist = (EdgeTableEntry *)NULL;
+ pPrevSLL->next = pSLL;
}
+ pSLL->scanline = scanline;
- for (r = rgn->Buffer; r < rgn->Buffer + rgn->rdh.nCount; r++)
+ /*
+ * now insert the edge in the right bucket
+ */
+ prev = (EdgeTableEntry *)NULL;
+ start = pSLL->edgelist;
+ while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
{
- NtGdiPatBlt(hDC, r->left, r->top, r->right - r->left, r->bottom - r->top, PATCOPY);
+ prev = start;
+ start = start->next;
}
+ ETE->next = start;
- REGION_UnlockRgn(rgn);
- NtGdiSelectBrush(hDC, oldhBrush);
-
- return TRUE;
+ if (prev)
+ prev->next = ETE;
+ else
+ pSLL->edgelist = ETE;
}
-BOOL
-APIENTRY
-NtGdiFrameRgn(
- HDC hDC,
- HRGN hRgn,
- HBRUSH hBrush,
- INT Width,
- INT Height
+/***********************************************************************
+ * REGION_loadAET
+ *
+ * This routine moves EdgeTableEntries from the
+ * EdgeTable into the Active Edge Table,
+ * leaving them sorted by smaller x coordinate.
+ *
+ */
+static void FASTCALL
+REGION_loadAET(
+ EdgeTableEntry *AET,
+ EdgeTableEntry *ETEs
)
{
- HRGN FrameRgn;
- BOOL Ret;
+ EdgeTableEntry *pPrevAET;
+ EdgeTableEntry *tmp;
- if (!(FrameRgn = NtGdiCreateRectRgn(0, 0, 0, 0)))
- {
- return FALSE;
- }
- if (!REGION_CreateFrameRgn(FrameRgn, hRgn, Width, Height))
+ pPrevAET = AET;
+ AET = AET->next;
+ while (ETEs)
{
- GreDeleteObject(FrameRgn);
- return FALSE;
- }
-
- Ret = NtGdiFillRgn(hDC, FrameRgn, hBrush);
+ while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
+ {
+ pPrevAET = AET;
+ AET = AET->next;
+ }
+ tmp = ETEs->next;
+ ETEs->next = AET;
+ if (AET)
+ AET->back = ETEs;
+ ETEs->back = pPrevAET;
+ pPrevAET->next = ETEs;
+ pPrevAET = ETEs;
- GreDeleteObject(FrameRgn);
- return Ret;
+ ETEs = tmp;
+ }
}
-INT FASTCALL
-REGION_GetRgnBox(
- PROSRGNDATA Rgn,
- PRECTL pRect
-)
+/***********************************************************************
+ * REGION_computeWAET
+ *
+ * This routine links the AET by the
+ * nextWETE (winding EdgeTableEntry) link for
+ * use by the winding number rule. The final
+ * Active Edge Table (AET) might look something
+ * like:
+ *
+ * AET
+ * ---------- --------- ---------
+ * |ymax | |ymax | |ymax |
+ * | ... | |... | |... |
+ * |next |->|next |->|next |->...
+ * |nextWETE| |nextWETE| |nextWETE|
+ * --------- --------- ^--------
+ * | | |
+ * V-------------------> V---> ...
+ *
+ */
+static void FASTCALL
+REGION_computeWAET(EdgeTableEntry *AET)
{
- DWORD ret;
+ register EdgeTableEntry *pWETE;
+ register int inside = 1;
+ register int isInside = 0;
- if (Rgn)
+ AET->nextWETE = (EdgeTableEntry *)NULL;
+ pWETE = AET;
+ AET = AET->next;
+ while (AET)
{
- *pRect = Rgn->rdh.rcBound;
- ret = REGION_Complexity(Rgn);
+ if (AET->ClockWise)
+ isInside++;
+ else
+ isInside--;
- return ret;
+ if ( (!inside && !isInside) ||
+ ( inside && isInside) )
+ {
+ pWETE->nextWETE = AET;
+ pWETE = AET;
+ inside = !inside;
+ }
+ AET = AET->next;
}
- return 0; //if invalid region return zero
+ pWETE->nextWETE = (EdgeTableEntry *)NULL;
}
-
-/* See wine, msdn, osr and Feng Yuan - Windows Graphics Programming Win32 Gdi And Directdraw
-
- 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
-
- The intersection of the clip with the meta region is not Rao it's API!
- Go back and read 7.2 Clipping pages 418-19:
- Rao = API & Vis:
- 1) The Rao region is the intersection of the API region and the system region,
- named after the Microsoft engineer who initially proposed it.
- 2) The Rao region can be calculated from the API region and the system region.
-
- API:
- API region is the intersection of the meta region and the clipping region,
- clearly named after the fact that it is controlled by GDI API calls.
-*/
-INT APIENTRY
-NtGdiGetRandomRgn(
- HDC hDC,
- HRGN hDest,
- INT iCode
-)
+/***********************************************************************
+ * REGION_InsertionSort
+ *
+ * Just a simple insertion sort using
+ * pointers and back pointers to sort the Active
+ * Edge Table.
+ *
+ */
+static BOOL FASTCALL
+REGION_InsertionSort(EdgeTableEntry *AET)
{
- INT ret = 0;
- PDC pDC;
- HRGN hSrc = NULL;
- POINT org;
-
- pDC = DC_LockDc(hDC);
- if (pDC == NULL)
- {
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return -1;
- }
-
- switch (iCode)
- {
- case CLIPRGN:
- hSrc = pDC->rosdc.hClipRgn;
-// if (pDC->dclevel.prgnClip) hSrc = ((PROSRGNDATA)pDC->dclevel.prgnClip)->BaseObject.hHmgr;
- break;
- case METARGN:
- if (pDC->dclevel.prgnMeta) hSrc = ((PROSRGNDATA)pDC->dclevel.prgnMeta)->BaseObject.hHmgr;
- break;
- case APIRGN:
- hSrc = pDC->rosdc.hClipRgn;
-// if (pDC->prgnAPI) hSrc = ((PROSRGNDATA)pDC->prgnAPI)->BaseObject.hHmgr;
-// else if (pDC->dclevel.prgnClip) hSrc = ((PROSRGNDATA)pDC->dclevel.prgnClip)->BaseObject.hHmgr;
-// else if (pDC->dclevel.prgnMeta) hSrc = ((PROSRGNDATA)pDC->dclevel.prgnMeta)->BaseObject.hHmgr;
- break;
- case SYSRGN:
- hSrc = pDC->rosdc.hVisRgn;
-// if (pDC->prgnVis) hSrc = ((PROSRGNDATA)pDC->prgnVis)->BaseObject.hHmgr;
- break;
- default:
- hSrc = 0;
- }
- if (hSrc)
+ EdgeTableEntry *pETEchase;
+ EdgeTableEntry *pETEinsert;
+ EdgeTableEntry *pETEchaseBackTMP;
+ BOOL changed = FALSE;
+
+ AET = AET->next;
+ while (AET)
{
- if (NtGdiCombineRgn(hDest, hSrc, 0, RGN_COPY) == ERROR)
- {
- ret = -1;
- }
- else
+ pETEinsert = AET;
+ pETEchase = AET;
+ while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
+ pETEchase = pETEchase->back;
+
+ AET = AET->next;
+ if (pETEchase != pETEinsert)
{
- ret = 1;
+ pETEchaseBackTMP = pETEchase->back;
+ pETEinsert->back->next = AET;
+ if (AET)
+ AET->back = pETEinsert->back;
+ pETEinsert->next = pETEchase;
+ pETEchase->back->next = pETEinsert;
+ pETEchase->back = pETEinsert;
+ pETEinsert->back = pETEchaseBackTMP;
+ changed = TRUE;
}
}
- if (iCode == SYSRGN)
- {
- IntGdiGetDCOrg(pDC, &org);
- NtGdiOffsetRgn(hDest, org.x, org.y );
- }
-
- DC_UnlockDc(pDC);
-
- return ret;
+ return changed;
}
-INT APIENTRY
-IntGdiGetRgnBox(
- HRGN hRgn,
- PRECTL pRect
-)
+/***********************************************************************
+ * REGION_FreeStorage
+ *
+ * Clean up our act.
+ */
+static void FASTCALL
+REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
{
- PROSRGNDATA Rgn;
- DWORD ret;
+ ScanLineListBlock *tmpSLLBlock;
- if (!(Rgn = REGION_LockRgn(hRgn)))
+ while (pSLLBlock)
{
- return ERROR;
+ tmpSLLBlock = pSLLBlock->next;
+ ExFreePool(pSLLBlock);
+ pSLLBlock = tmpSLLBlock;
}
-
- ret = REGION_GetRgnBox(Rgn, pRect);
- REGION_UnlockRgn(Rgn);
-
- return ret;
}
-INT APIENTRY
-NtGdiGetRgnBox(
- HRGN hRgn,
- PRECTL pRect
-)
+/***********************************************************************
+ * REGION_PtsToRegion
+ *
+ * Create an array of rectangles from a list of points.
+ */
+static int FASTCALL
+REGION_PtsToRegion(
+ int numFullPtBlocks,
+ int iCurPtBlock,
+ POINTBLOCK *FirstPtBlock,
+ ROSRGNDATA *reg)
{
- PROSRGNDATA Rgn;
- RECTL SafeRect;
- DWORD ret;
- NTSTATUS Status = STATUS_SUCCESS;
+ RECTL *rects;
+ POINT *pts;
+ POINTBLOCK *CurPtBlock;
+ int i;
+ RECTL *extents, *temp;
+ INT numRects;
- if (!(Rgn = REGION_LockRgn(hRgn)))
- {
- return ERROR;
- }
+ extents = ®->rdh.rcBound;
- ret = REGION_GetRgnBox(Rgn, &SafeRect);
- REGION_UnlockRgn(Rgn);
- if (ERROR == ret)
- {
- return ret;
- }
+ numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
- _SEH2_TRY
- {
- ProbeForWrite(pRect, sizeof(RECT), 1);
- *pRect = SafeRect;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ if (!(temp = ExAllocatePoolWithTag(PagedPool, numRects * sizeof(RECT), TAG_REGION)))
{
- Status = _SEH2_GetExceptionCode();
+ return 0;
}
- _SEH2_END;
- if (!NT_SUCCESS(Status))
+ if (reg->Buffer != NULL)
{
- return ERROR;
+ COPY_RECTS(temp, reg->Buffer, reg->rdh.nCount);
+ if (reg->Buffer != ®->rdh.rcBound)
+ ExFreePoolWithTag(reg->Buffer, TAG_REGION);
}
+ reg->Buffer = temp;
- return ret;
-}
-
-BOOL
-APIENTRY
-NtGdiInvertRgn(
- HDC hDC,
- HRGN hRgn
-)
-{
- PROSRGNDATA RgnData;
- ULONG i;
- PRECTL rc;
+ reg->rdh.nCount = numRects;
+ CurPtBlock = FirstPtBlock;
+ rects = reg->Buffer - 1;
+ numRects = 0;
+ extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
- if (!(RgnData = REGION_LockRgn(hRgn)))
+ for ( ; numFullPtBlocks >= 0; numFullPtBlocks--)
{
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return FALSE;
+ /* the loop uses 2 points per iteration */
+ i = NUMPTSTOBUFFER >> 1;
+ if (!numFullPtBlocks)
+ i = iCurPtBlock >> 1;
+ for (pts = CurPtBlock->pts; i--; pts += 2)
+ {
+ if (pts->x == pts[1].x)
+ continue;
+ if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
+ pts[1].x == rects->right &&
+ (numRects == 1 || rects[-1].top != rects->top) &&
+ (i && pts[2].y > pts[1].y))
+ {
+ rects->bottom = pts[1].y + 1;
+ continue;
+ }
+ numRects++;
+ rects++;
+ rects->left = pts->x;
+ rects->top = pts->y;
+ rects->right = pts[1].x;
+ rects->bottom = pts[1].y + 1;
+ if (rects->left < extents->left)
+ extents->left = rects->left;
+ if (rects->right > extents->right)
+ extents->right = rects->right;
+ }
+ CurPtBlock = CurPtBlock->next;
}
- rc = RgnData->Buffer;
- for (i = 0; i < RgnData->rdh.nCount; i++)
+ if (numRects)
{
-
- if (!NtGdiPatBlt(hDC, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, DSTINVERT))
- {
- REGION_UnlockRgn(RgnData);
- return FALSE;
- }
- rc++;
+ extents->top = reg->Buffer->top;
+ extents->bottom = rects->bottom;
+ }
+ else
+ {
+ extents->left = 0;
+ extents->top = 0;
+ extents->right = 0;
+ extents->bottom = 0;
}
+ reg->rdh.nCount = numRects;
- REGION_UnlockRgn(RgnData);
- return TRUE;
+ return(TRUE);
}
-INT
-APIENTRY
-NtGdiOffsetRgn(
- HRGN hRgn,
- INT XOffset,
- INT YOffset
+/***********************************************************************
+ * REGION_CreateEdgeTable
+ *
+ * This routine creates the edge table for
+ * scan converting polygons.
+ * The Edge Table (ET) looks like:
+ *
+ * EdgeTable
+ * --------
+ * | ymax | ScanLineLists
+ * |scanline|-->------------>-------------->...
+ * -------- |scanline| |scanline|
+ * |edgelist| |edgelist|
+ * --------- ---------
+ * | |
+ * | |
+ * V V
+ * list of ETEs list of ETEs
+ *
+ * where ETE is an EdgeTableEntry data structure,
+ * and there is one ScanLineList per scanline at
+ * which an edge is initially entered.
+ *
+ */
+static void FASTCALL
+REGION_CreateETandAET(
+ const ULONG *Count,
+ INT nbpolygons,
+ const POINT *pts,
+ EdgeTable *ET,
+ EdgeTableEntry *AET,
+ EdgeTableEntry *pETEs,
+ ScanLineListBlock *pSLLBlock
)
{
- PROSRGNDATA rgn = REGION_LockRgn(hRgn);
- INT ret;
+ const POINT *top, *bottom;
+ const POINT *PrevPt, *CurrPt, *EndPt;
+ INT poly, count;
+ int iSLLBlock = 0;
+ int dy;
- DPRINT("NtGdiOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn, XOffset, YOffset, rgn );
- if (!rgn)
- {
- DPRINT("NtGdiOffsetRgn: hRgn error\n");
- return ERROR;
- }
+ /*
+ * initialize the Active Edge Table
+ */
+ AET->next = (EdgeTableEntry *)NULL;
+ AET->back = (EdgeTableEntry *)NULL;
+ AET->nextWETE = (EdgeTableEntry *)NULL;
+ AET->bres.minor_axis = SMALL_COORDINATE;
- if (XOffset || YOffset)
+ /*
+ * initialize the Edge Table.
+ */
+ ET->scanlines.next = (ScanLineList *)NULL;
+ ET->ymax = SMALL_COORDINATE;
+ ET->ymin = LARGE_COORDINATE;
+ pSLLBlock->next = (ScanLineListBlock *)NULL;
+
+ EndPt = pts - 1;
+ for (poly = 0; poly < nbpolygons; poly++)
{
- int nbox = rgn->rdh.nCount;
- PRECTL pbox = rgn->Buffer;
+ count = Count[poly];
+ EndPt += count;
+ if (count < 2)
+ continue;
- if (nbox && pbox)
+ PrevPt = EndPt;
+
+ /*
+ * for each vertex in the array of points.
+ * In this loop we are dealing with two vertices at
+ * a time -- these make up one edge of the polygon.
+ */
+ while (count--)
{
- while (nbox--)
+ CurrPt = pts++;
+
+ /*
+ * find out which point is above and which is below.
+ */
+ if (PrevPt->y > CurrPt->y)
{
- pbox->left += XOffset;
- pbox->right += XOffset;
- pbox->top += YOffset;
- pbox->bottom += YOffset;
- pbox++;
+ bottom = PrevPt, top = CurrPt;
+ pETEs->ClockWise = 0;
}
- if (rgn->Buffer != &rgn->rdh.rcBound)
+ else
{
- rgn->rdh.rcBound.left += XOffset;
- rgn->rdh.rcBound.right += XOffset;
- rgn->rdh.rcBound.top += YOffset;
- rgn->rdh.rcBound.bottom += YOffset;
+ bottom = CurrPt, top = PrevPt;
+ pETEs->ClockWise = 1;
+ }
+
+ /*
+ * don't add horizontal edges to the Edge table.
+ */
+ if (bottom->y != top->y)
+ {
+ pETEs->ymax = bottom->y-1;
+ /* -1 so we don't get last scanline */
+
+ /*
+ * initialize integer edge algorithm
+ */
+ dy = bottom->y - top->y;
+ BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
+
+ REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
+ &iSLLBlock);
+
+ if (PrevPt->y > ET->ymax)
+ ET->ymax = PrevPt->y;
+ if (PrevPt->y < ET->ymin)
+ ET->ymin = PrevPt->y;
+ pETEs++;
}
+
+ PrevPt = CurrPt;
}
}
- ret = REGION_Complexity(rgn);
- REGION_UnlockRgn(rgn);
- return ret;
}
-BOOL
-FASTCALL
-IntGdiPaintRgn(
- PDC dc,
- HRGN hRgn
+HRGN FASTCALL
+IntCreatePolyPolygonRgn(
+ POINT *Pts,
+ PULONG Count,
+ INT nbpolygons,
+ INT mode
)
{
- HRGN tmpVisRgn;
- PROSRGNDATA visrgn;
- CLIPOBJ* ClipRegion;
- BOOL bRet = FALSE;
- POINTL BrushOrigin;
- SURFACE *psurf;
- PDC_ATTR pdcattr;
+ HRGN hrgn;
+ ROSRGNDATA *region;
+ EdgeTableEntry *pAET; /* Active Edge Table */
+ INT y; /* current scanline */
+ int iPts = 0; /* number of pts in buffer */
+ EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
+ ScanLineList *pSLL; /* current scanLineList */
+ POINT *pts; /* output buffer */
+ EdgeTableEntry *pPrevAET; /* ptr to previous AET */
+ EdgeTable ET; /* header node for ET */
+ EdgeTableEntry AET; /* header node for AET */
+ EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
+ ScanLineListBlock SLLBlock; /* header for scanlinelist */
+ int fixWAET = FALSE;
+ POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
+ POINTBLOCK *tmpPtBlock;
+ int numFullPtBlocks = 0;
+ INT poly, total;
- if (!dc) return FALSE;
- pdcattr = dc->pdcattr;
+ if (mode == 0 || mode > 2) return 0;
- ASSERT(!(pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY)));
+ if (!(region = REGION_AllocUserRgnWithHandle(nbpolygons)))
+ return 0;
+ hrgn = region->BaseObject.hHmgr;
- if (!(tmpVisRgn = NtGdiCreateRectRgn(0, 0, 0, 0))) return FALSE;
+ /* special case a rectangle */
- // Transform region into device co-ords
- if (!REGION_LPTODP(dc, tmpVisRgn, hRgn) ||
- NtGdiOffsetRgn(tmpVisRgn, dc->ptlDCOrig.x, dc->ptlDCOrig.y) == ERROR)
+ 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))))
{
- GreDeleteObject(tmpVisRgn);
- return FALSE;
+ RGNOBJAPI_Unlock(region);
+ NtGdiSetRectRgn(hrgn, 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));
+ return hrgn;
}
- NtGdiCombineRgn(tmpVisRgn, tmpVisRgn, dc->rosdc.hGCClipRgn, RGN_AND);
-
- visrgn = REGION_LockRgn(tmpVisRgn);
- if (visrgn == NULL)
+ for (poly = total = 0; poly < nbpolygons; poly++)
+ total += Count[poly];
+ if (! (pETEs = ExAllocatePoolWithTag(PagedPool, sizeof(EdgeTableEntry) * total, TAG_REGION)) )
{
- GreDeleteObject(tmpVisRgn);
- return FALSE;
+ GreDeleteObject(hrgn);
+ return 0;
}
+ pts = FirstPtBlock.pts;
+ REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
+ pSLL = ET.scanlines.next;
+ curPtBlock = &FirstPtBlock;
- ClipRegion = IntEngCreateClipRegion(visrgn->rdh.nCount,
- visrgn->Buffer,
- &visrgn->rdh.rcBound );
- ASSERT(ClipRegion);
-
- BrushOrigin.x = pdcattr->ptlBrushOrigin.x;
- BrushOrigin.y = pdcattr->ptlBrushOrigin.y;
- psurf = dc->dclevel.pSurface;
- /* FIXME - Handle psurf == NULL !!!! */
-
- bRet = IntEngPaint(&psurf->SurfObj,
- ClipRegion,
- &dc->eboFill.BrushObject,
- &BrushOrigin,
- 0xFFFF);//FIXME:don't know what to put here
+ if (mode != WINDING)
+ {
+ /*
+ * for each scanline
+ */
+ for (y = ET.ymin; y < ET.ymax; y++)
+ {
+ /*
+ * Add a new edge to the active edge table when we
+ * get to the next edge.
+ */
+ if (pSLL != NULL && y == pSLL->scanline)
+ {
+ REGION_loadAET(&AET, pSLL->edgelist);
+ pSLL = pSLL->next;
+ }
+ pPrevAET = &AET;
+ pAET = AET.next;
- REGION_UnlockRgn(visrgn);
- GreDeleteObject(tmpVisRgn);
+ /*
+ * for each active edge
+ */
+ while (pAET)
+ {
+ pts->x = pAET->bres.minor_axis, pts->y = y;
+ pts++, iPts++;
- // Fill the region
- return TRUE;
-}
+ /*
+ * send out the buffer
+ */
+ if (iPts == NUMPTSTOBUFFER)
+ {
+ tmpPtBlock = ExAllocatePoolWithTag(PagedPool, sizeof(POINTBLOCK), TAG_REGION);
+ if (!tmpPtBlock)
+ {
+ DPRINT1("Can't alloc tPB\n");
+ ExFreePoolWithTag(pETEs, TAG_REGION);
+ return 0;
+ }
+ curPtBlock->next = tmpPtBlock;
+ curPtBlock = tmpPtBlock;
+ pts = curPtBlock->pts;
+ numFullPtBlocks++;
+ iPts = 0;
+ }
+ EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
+ }
+ REGION_InsertionSort(&AET);
+ }
+ }
+ else
+ {
+ /*
+ * for each scanline
+ */
+ for (y = ET.ymin; y < ET.ymax; y++)
+ {
+ /*
+ * Add a new edge to the active edge table when we
+ * get to the next edge.
+ */
+ if (pSLL != NULL && y == pSLL->scanline)
+ {
+ REGION_loadAET(&AET, pSLL->edgelist);
+ REGION_computeWAET(&AET);
+ pSLL = pSLL->next;
+ }
+ pPrevAET = &AET;
+ pAET = AET.next;
+ pWETE = pAET;
-BOOL
-APIENTRY
-NtGdiPtInRegion(
- HRGN hRgn,
- INT X,
- INT Y
-)
-{
- PROSRGNDATA rgn;
- ULONG i;
- PRECTL r;
+ /*
+ * for each active edge
+ */
+ while (pAET)
+ {
+ /*
+ * add to the buffer only those edges that
+ * are in the Winding active edge table.
+ */
+ if (pWETE == pAET)
+ {
+ pts->x = pAET->bres.minor_axis, pts->y = y;
+ pts++, iPts++;
- if (!(rgn = REGION_LockRgn(hRgn) ) )
- return FALSE;
+ /*
+ * send out the buffer
+ */
+ if (iPts == NUMPTSTOBUFFER)
+ {
+ tmpPtBlock = ExAllocatePoolWithTag(PagedPool,
+ sizeof(POINTBLOCK), TAG_REGION);
+ if (!tmpPtBlock)
+ {
+ DPRINT1("Can't alloc tPB\n");
+ ExFreePoolWithTag(pETEs, TAG_REGION);
+ GreDeleteObject(hrgn);
+ return 0;
+ }
+ curPtBlock->next = tmpPtBlock;
+ curPtBlock = tmpPtBlock;
+ pts = curPtBlock->pts;
+ numFullPtBlocks++;
+ iPts = 0;
+ }
+ pWETE = pWETE->nextWETE;
+ }
+ EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
+ }
- if (rgn->rdh.nCount > 0 && INRECT(rgn->rdh.rcBound, X, Y))
- {
- r = rgn->Buffer;
- for (i = 0; i < rgn->rdh.nCount; i++)
- {
- if (INRECT(*r, X, Y))
+ /*
+ * recompute the winding active edge table if
+ * we just resorted or have exited an edge.
+ */
+ if (REGION_InsertionSort(&AET) || fixWAET)
{
- REGION_UnlockRgn(rgn);
- return TRUE;
+ REGION_computeWAET(&AET);
+ fixWAET = FALSE;
}
- r++;
}
}
- REGION_UnlockRgn(rgn);
- return FALSE;
+ REGION_FreeStorage(SLLBlock.next);
+ REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
+
+ for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;)
+ {
+ tmpPtBlock = curPtBlock->next;
+ ExFreePoolWithTag(curPtBlock, TAG_REGION);
+ curPtBlock = tmpPtBlock;
+ }
+ ExFreePoolWithTag(pETEs, TAG_REGION);
+ RGNOBJAPI_Unlock(region);
+ return hrgn;
}
BOOL
FASTCALL
-REGION_RectInRegion(
- PROSRGNDATA Rgn,
- const RECTL *rect
+IntRectInRegion(
+ HRGN hRgn,
+ LPRECTL rc
)
{
- PRECTL pCurRect, pRectEnd;
- RECT rc;
+ PROSRGNDATA Rgn;
+ BOOL Ret;
- /* swap the coordinates to make right >= left and bottom >= top */
- /* (region building rectangles are normalized the same way) */
- if( rect->top > rect->bottom) {
- rc.top = rect->bottom;
- rc.bottom = rect->top;
- } else {
- rc.top = rect->top;
- rc.bottom = rect->bottom;
- }
- if( rect->right < rect->left) {
- rc.right = rect->left;
- rc.left = rect->right;
- } else {
- rc.right = rect->right;
- rc.left = rect->left;
+ if (!(Rgn = RGNOBJAPI_Lock(hRgn, NULL)))
+ {
+ return ERROR;
}
- /* this is (just) a useful optimization */
- if ((Rgn->rdh.nCount > 0) && EXTENTCHECK(&Rgn->rdh.rcBound, &rc))
- {
- for (pCurRect = Rgn->Buffer, pRectEnd = pCurRect +
- Rgn->rdh.nCount; pCurRect < pRectEnd; pCurRect++)
- {
- if (pCurRect->bottom <= rc.top)
- continue; /* not far enough down yet */
+ Ret = REGION_RectInRegion(Rgn, rc);
+ RGNOBJAPI_Unlock(Rgn);
+ return Ret;
+}
- if (pCurRect->top >= rc.bottom)
- break; /* too far down */
- if (pCurRect->right <= rc.left)
- continue; /* not far enough over yet */
+//
+// NtGdi Exported Functions
+//
+INT
+APIENTRY
+NtGdiCombineRgn(HRGN hDest,
+ HRGN hSrc1,
+ HRGN hSrc2,
+ INT CombineMode)
+{
+ INT result = ERROR;
+ PROSRGNDATA destRgn, src1Rgn, src2Rgn = NULL;
- if (pCurRect->left >= rc.right) {
- continue;
- }
+ if ( CombineMode > RGN_COPY && CombineMode < RGN_AND)
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ return ERROR;
+ }
- return TRUE;
- }
- }
- return FALSE;
+ destRgn = RGNOBJAPI_Lock(hDest, NULL);
+ if (!destRgn)
+ {
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ return ERROR;
+ }
+
+ src1Rgn = RGNOBJAPI_Lock(hSrc1, NULL);
+ if (!src1Rgn)
+ {
+ RGNOBJAPI_Unlock(destRgn);
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ return ERROR;
+ }
+
+ if (hSrc2)
+ src2Rgn = RGNOBJAPI_Lock(hSrc2, NULL);
+
+ result = IntGdiCombineRgn( destRgn, src1Rgn, src2Rgn, CombineMode);
+
+ if (src2Rgn)
+ RGNOBJAPI_Unlock(src2Rgn);
+ RGNOBJAPI_Unlock(src1Rgn);
+ RGNOBJAPI_Unlock(destRgn);
+
+ return result;
}
-BOOL
+HRGN
APIENTRY
-NtGdiRectInRegion(
- HRGN hRgn,
- LPRECTL unsaferc
+NtGdiCreateEllipticRgn(
+ INT Left,
+ INT Top,
+ INT Right,
+ INT Bottom
)
{
- PROSRGNDATA Rgn;
- RECTL rc = {0};
- BOOL Ret;
- NTSTATUS Status = STATUS_SUCCESS;
+ return NtGdiCreateRoundRectRgn(Left, Top, Right, Bottom,
+ Right - Left, Bottom - Top);
+}
- if (!(Rgn = REGION_LockRgn(hRgn)))
- {
- return ERROR;
- }
+HRGN APIENTRY
+NtGdiCreateRectRgn(INT LeftRect, INT TopRect, INT RightRect, INT BottomRect)
+{
+ PROSRGNDATA pRgn;
+ HRGN hRgn;
- _SEH2_TRY
- {
- ProbeForRead(unsaferc, sizeof(RECT), 1);
- rc = *unsaferc;
- }
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ /* Allocate region data structure with space for 1 RECTL */
+ if (!(pRgn = REGION_AllocUserRgnWithHandle(1)))
{
- Status = _SEH2_GetExceptionCode();
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
}
- _SEH2_END;
+ hRgn = pRgn->BaseObject.hHmgr;
- if (!NT_SUCCESS(Status))
- {
- REGION_UnlockRgn(Rgn);
- SetLastNtError(Status);
- DPRINT1("NtGdiRectInRegion: bogus rc\n");
- return ERROR;
- }
+ REGION_SetRectRgn(pRgn, LeftRect, TopRect, RightRect, BottomRect);
+ RGNOBJAPI_Unlock(pRgn);
- Ret = REGION_RectInRegion(Rgn, &rc);
- REGION_UnlockRgn(Rgn);
- return Ret;
+ return hRgn;
}
-VOID
-FASTCALL
-REGION_SetRectRgn(
- PROSRGNDATA rgn,
- INT LeftRect,
- INT TopRect,
- INT RightRect,
- INT BottomRect
+HRGN
+APIENTRY
+NtGdiCreateRoundRectRgn(
+ INT left,
+ INT top,
+ INT right,
+ INT bottom,
+ INT ellipse_width,
+ INT ellipse_height
)
{
- PRECTL firstRect;
+ PROSRGNDATA obj;
+ HRGN hrgn;
+ int asq, bsq, d, xd, yd;
+ RECTL rect;
- if (LeftRect > RightRect)
+ /* Make the dimensions sensible */
+
+ if (left > right)
{
- INT tmp = LeftRect;
- LeftRect = RightRect;
- RightRect = tmp;
+ INT tmp = left;
+ left = right;
+ right = tmp;
}
- if (TopRect > BottomRect)
+ if (top > bottom)
{
- INT tmp = TopRect;
- TopRect = BottomRect;
- BottomRect = tmp;
+ INT tmp = top;
+ top = bottom;
+ bottom = tmp;
}
- if ((LeftRect != RightRect) && (TopRect != BottomRect))
- {
- firstRect = rgn->Buffer;
- ASSERT(firstRect);
- firstRect->left = rgn->rdh.rcBound.left = LeftRect;
- firstRect->top = rgn->rdh.rcBound.top = TopRect;
- firstRect->right = rgn->rdh.rcBound.right = RightRect;
- firstRect->bottom = rgn->rdh.rcBound.bottom = BottomRect;
- rgn->rdh.nCount = 1;
- rgn->rdh.iType = RDH_RECTANGLES;
- }
- else
- EMPTY_REGION(rgn);
-}
+ ellipse_width = abs(ellipse_width);
+ ellipse_height = abs(ellipse_height);
-BOOL
-APIENTRY
-NtGdiSetRectRgn(
- HRGN hRgn,
- INT LeftRect,
- INT TopRect,
- INT RightRect,
- INT BottomRect
-)
-{
- PROSRGNDATA rgn;
+ /* Check parameters */
- if ( !(rgn = REGION_LockRgn(hRgn)) )
- {
- return 0; //per documentation
- }
+ if (ellipse_width > right-left) ellipse_width = right-left;
+ if (ellipse_height > bottom-top) ellipse_height = bottom-top;
- REGION_SetRectRgn(rgn, LeftRect, TopRect, RightRect, BottomRect);
+ /* Check if we can do a normal rectangle instead */
- REGION_UnlockRgn(rgn);
- return TRUE;
-}
+ if ((ellipse_width < 2) || (ellipse_height < 2))
+ return NtGdiCreateRectRgn(left, top, right, bottom);
-HRGN APIENTRY
-NtGdiUnionRectWithRgn(
- HRGN hDest,
- const RECTL *UnsafeRect
-)
-{
- RECTL SafeRect = {0};
- PROSRGNDATA Rgn;
- NTSTATUS Status = STATUS_SUCCESS;
+ /* Create region */
- if (!(Rgn = REGION_LockRgn(hDest)))
- {
- SetLastWin32Error(ERROR_INVALID_HANDLE);
- return NULL;
- }
+ d = (ellipse_height < 128) ? ((3 * ellipse_height) >> 2) : 64;
+ if (!(obj = REGION_AllocUserRgnWithHandle(d))) return 0;
+ hrgn = obj->BaseObject.hHmgr;
- _SEH2_TRY
+ /* 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)
{
- ProbeForRead(UnsafeRect, sizeof(RECT), 1);
- SafeRect = *UnsafeRect;
+ if (d > 0) /* if nearest pixel is toward the center */
+ {
+ /* 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;
+ }
+ rect.left--; /* next horiz point */
+ rect.right++;
+ xd += 2*bsq;
+ d += bsq + xd;
}
- _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ /* Loop to draw second half of quadrant */
+
+ d += (3 * (asq-bsq) / 2 - (xd+yd)) / 2;
+ while (yd >= 0)
{
- Status = _SEH2_GetExceptionCode();
+ /* 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 (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;
}
- _SEH2_END;
+ /* Add the inside rectangle */
- if (! NT_SUCCESS(Status))
+ if (top <= bottom)
{
- REGION_UnlockRgn(Rgn);
- SetLastNtError(Status);
- return NULL;
+ rect.top = top;
+ rect.bottom = bottom;
+ REGION_UnionRectWithRgn(obj, &rect);
}
- REGION_UnionRectWithRgn(Rgn, &SafeRect);
- REGION_UnlockRgn(Rgn);
- return hDest;
+ RGNOBJAPI_Unlock(obj);
+ return hrgn;
}
-/*!
- * MSDN: GetRegionData, Return Values:
- *
- * "If the function succeeds and dwCount specifies an adequate number of bytes,
- * the return value is always dwCount. If dwCount is too small or the function
- * fails, the return value is 0. If lpRgnData is NULL, the return value is the
- * required number of bytes.
- *
- * If the function fails, the return value is zero."
- */
-DWORD APIENTRY
-NtGdiGetRegionData(
- HRGN hrgn,
- DWORD count,
- LPRGNDATA rgndata
+BOOL
+APIENTRY
+NtGdiEqualRgn(
+ HRGN hSrcRgn1,
+ HRGN hSrcRgn2
)
{
- DWORD size;
- PROSRGNDATA obj = REGION_LockRgn(hrgn);
- NTSTATUS Status = STATUS_SUCCESS;
+ PROSRGNDATA rgn1, rgn2;
+ PRECTL tRect1, tRect2;
+ ULONG i;
+ BOOL bRet = FALSE;
- if (!obj)
- return 0;
+ if ( !(rgn1 = RGNOBJAPI_Lock(hSrcRgn1, NULL)) )
+ return ERROR;
- size = obj->rdh.nCount * sizeof(RECT);
- if (count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
+ if ( !(rgn2 = RGNOBJAPI_Lock(hSrcRgn2, NULL)) )
{
- REGION_UnlockRgn(obj);
- if (rgndata) /* buffer is too small, signal it by return 0 */
- return 0;
- else /* user requested buffer size with rgndata NULL */
- return size + sizeof(RGNDATAHEADER);
+ RGNOBJAPI_Unlock(rgn1);
+ return ERROR;
+ }
+
+ if ( rgn1->rdh.nCount != rgn2->rdh.nCount ) goto exit;
+
+ if ( rgn1->rdh.nCount == 0 )
+ {
+ bRet = TRUE;
+ goto exit;
+ }
+
+ if ( 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 = rgn1->Buffer;
+ tRect2 = 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:
+ RGNOBJAPI_Unlock(rgn1);
+ RGNOBJAPI_Unlock(rgn2);
+ return bRet;
+}
+
+HRGN
+APIENTRY
+NtGdiExtCreateRegion(
+ OPTIONAL LPXFORM Xform,
+ DWORD Count,
+ LPRGNDATA RgnData
+)
+{
+ HRGN hRgn;
+ PROSRGNDATA Region;
+ DWORD nCount = 0;
+ DWORD iType = 0;
+ DWORD dwSize = 0;
+ NTSTATUS Status = STATUS_SUCCESS;
+ MATRIX matrix;
+ XFORMOBJ xo;
+ DPRINT("NtGdiExtCreateRegion\n");
_SEH2_TRY
{
- ProbeForWrite(rgndata, count, 1);
- RtlCopyMemory(rgndata, &obj->rdh, sizeof(RGNDATAHEADER));
- RtlCopyMemory(rgndata->Buffer, obj->Buffer, size);
+ ProbeForRead(RgnData, Count, 1);
+ nCount = RgnData->rdh.nCount;
+ iType = RgnData->rdh.iType;
+ dwSize = RgnData->rdh.dwSize;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END;
-
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
- REGION_UnlockRgn(obj);
- return 0;
+ return NULL;
}
- REGION_UnlockRgn(obj);
- return size + sizeof(RGNDATAHEADER);
-}
-
+ /* Check parameters, but don't set last error here */
+ if (Count < sizeof(RGNDATAHEADER) + nCount * sizeof(RECT) ||
+ iType != RDH_RECTANGLES ||
+ dwSize != sizeof(RGNDATAHEADER))
+ {
+ return NULL;
+ }
-/***********************************************************************
- * REGION_InsertEdgeInET
- *
- * Insert the given edge into the edge table.
- * First we must find the correct bucket in the
- * Edge table, then find the right slot in the
- * bucket. Finally, we can insert it.
- *
- */
-static void FASTCALL
-REGION_InsertEdgeInET(
- EdgeTable *ET,
- EdgeTableEntry *ETE,
- INT scanline,
- ScanLineListBlock **SLLBlock,
- INT *iSLLBlock
-)
-{
- EdgeTableEntry *start, *prev;
- ScanLineList *pSLL, *pPrevSLL;
- ScanLineListBlock *tmpSLLBlock;
+ Region = REGION_AllocUserRgnWithHandle(nCount);
- /*
- * find the right bucket to put the edge into
- */
- pPrevSLL = &ET->scanlines;
- pSLL = pPrevSLL->next;
- while (pSLL && (pSLL->scanline < scanline))
+ if (Region == NULL)
{
- pPrevSLL = pSLL;
- pSLL = pSLL->next;
+ EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
}
+ hRgn = Region->BaseObject.hHmgr;
- /*
- * reassign pSLL (pointer to ScanLineList) if necessary
- */
- if ((!pSLL) || (pSLL->scanline > scanline))
+ _SEH2_TRY
{
- if (*iSLLBlock > SLLSPERBLOCK-1)
+ if (Xform)
{
- tmpSLLBlock = ExAllocatePoolWithTag(PagedPool, sizeof(ScanLineListBlock), TAG_REGION);
- if (!tmpSLLBlock)
+ ULONG ret;
+
+ /* Init the XFORMOBJ from the Xform struct */
+ Status = STATUS_INVALID_PARAMETER;
+ XFORMOBJ_vInit(&xo, &matrix);
+ ret = XFORMOBJ_iSetXform(&xo, (XFORML*)Xform);
+
+ /* Check for error, also no scale and shear allowed */
+ if (ret != DDI_ERROR && ret != GX_GENERAL)
{
- DPRINT1("REGION_InsertEdgeInETL(): Can't alloc SLLB\n");
- /* FIXME - free resources? */
- return;
+ /* Apply the coordinate transformation on the rects */
+ if (XFORMOBJ_bApplyXform(&xo,
+ XF_LTOL,
+ nCount * 2,
+ RgnData->Buffer,
+ Region->Buffer))
+ {
+ Status = STATUS_SUCCESS;
+ }
}
- (*SLLBlock)->next = tmpSLLBlock;
- tmpSLLBlock->next = (ScanLineListBlock *)NULL;
- *SLLBlock = tmpSLLBlock;
- *iSLLBlock = 0;
}
- pSLL = &((*SLLBlock)->SLLs[(*iSLLBlock)++]);
-
- pSLL->next = pPrevSLL->next;
- pSLL->edgelist = (EdgeTableEntry *)NULL;
- pPrevSLL->next = pSLL;
+ else
+ {
+ /* Copy rect coordinates */
+ RtlCopyMemory(Region->Buffer,
+ RgnData->Buffer,
+ nCount * sizeof(RECT));
+ }
}
- pSLL->scanline = scanline;
-
- /*
- * now insert the edge in the right bucket
- */
- prev = (EdgeTableEntry *)NULL;
- start = pSLL->edgelist;
- while (start && (start->bres.minor_axis < ETE->bres.minor_axis))
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- prev = start;
- start = start->next;
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status))
+ {
+ EngSetLastError(ERROR_INVALID_PARAMETER);
+ RGNOBJAPI_Unlock(Region);
+ GreDeleteObject(hRgn);
+ return NULL;
}
- ETE->next = start;
- if (prev)
- prev->next = ETE;
- else
- pSLL->edgelist = ETE;
+ RGNOBJAPI_Unlock(Region);
+
+ return hRgn;
}
-/***********************************************************************
- * REGION_loadAET
- *
- * This routine moves EdgeTableEntries from the
- * EdgeTable into the Active Edge Table,
- * leaving them sorted by smaller x coordinate.
- *
- */
-static void FASTCALL
-REGION_loadAET(
- EdgeTableEntry *AET,
- EdgeTableEntry *ETEs
+BOOL
+APIENTRY
+NtGdiFillRgn(
+ HDC hDC,
+ HRGN hRgn,
+ HBRUSH hBrush
)
{
- EdgeTableEntry *pPrevAET;
- EdgeTableEntry *tmp;
+ HBRUSH oldhBrush;
+ PROSRGNDATA rgn;
+ PRECTL r;
- pPrevAET = AET;
- AET = AET->next;
- while (ETEs)
+ if (NULL == (rgn = RGNOBJAPI_Lock(hRgn, NULL)))
{
- while (AET && (AET->bres.minor_axis < ETEs->bres.minor_axis))
- {
- pPrevAET = AET;
- AET = AET->next;
- }
- tmp = ETEs->next;
- ETEs->next = AET;
- if (AET)
- AET->back = ETEs;
- ETEs->back = pPrevAET;
- pPrevAET->next = ETEs;
- pPrevAET = ETEs;
+ return FALSE;
+ }
- ETEs = tmp;
+ if (NULL == (oldhBrush = NtGdiSelectBrush(hDC, hBrush)))
+ {
+ 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;
}
-/***********************************************************************
- * REGION_computeWAET
- *
- * This routine links the AET by the
- * nextWETE (winding EdgeTableEntry) link for
- * use by the winding number rule. The final
- * Active Edge Table (AET) might look something
- * like:
- *
- * AET
- * ---------- --------- ---------
- * |ymax | |ymax | |ymax |
- * | ... | |... | |... |
- * |next |->|next |->|next |->...
- * |nextWETE| |nextWETE| |nextWETE|
- * --------- --------- ^--------
- * | | |
- * V-------------------> V---> ...
- *
- */
-static void FASTCALL
-REGION_computeWAET(EdgeTableEntry *AET)
+BOOL
+APIENTRY
+NtGdiFrameRgn(
+ HDC hDC,
+ HRGN hRgn,
+ HBRUSH hBrush,
+ INT Width,
+ INT Height
+)
{
- register EdgeTableEntry *pWETE;
- register int inside = 1;
- register int isInside = 0;
+ HRGN FrameRgn;
+ BOOL Ret;
- AET->nextWETE = (EdgeTableEntry *)NULL;
- pWETE = AET;
- AET = AET->next;
- while (AET)
+ if (!(FrameRgn = IntSysCreateRectRgn(0, 0, 0, 0)))
{
- if (AET->ClockWise)
- isInside++;
- else
- isInside--;
-
- if ( (!inside && !isInside) ||
- ( inside && isInside) )
- {
- pWETE->nextWETE = AET;
- pWETE = AET;
- inside = !inside;
- }
- AET = AET->next;
+ return FALSE;
}
- pWETE->nextWETE = (EdgeTableEntry *)NULL;
+ if (!REGION_CreateFrameRgn(FrameRgn, hRgn, Width, Height))
+ {
+ REGION_FreeRgnByHandle(FrameRgn);
+ return FALSE;
+ }
+
+ Ret = NtGdiFillRgn(hDC, FrameRgn, hBrush);
+
+ REGION_FreeRgnByHandle(FrameRgn);
+ return Ret;
}
-/***********************************************************************
- * REGION_InsertionSort
- *
- * Just a simple insertion sort using
- * pointers and back pointers to sort the Active
- * Edge Table.
- *
- */
-static BOOL FASTCALL
-REGION_InsertionSort(EdgeTableEntry *AET)
+
+INT APIENTRY
+NtGdiGetRgnBox(
+ HRGN hRgn,
+ PRECTL pRect
+)
{
- EdgeTableEntry *pETEchase;
- EdgeTableEntry *pETEinsert;
- EdgeTableEntry *pETEchaseBackTMP;
- BOOL changed = FALSE;
+ PROSRGNDATA Rgn;
+ RECTL SafeRect;
+ DWORD ret;
+ NTSTATUS Status = STATUS_SUCCESS;
- AET = AET->next;
- while (AET)
+ if (!(Rgn = RGNOBJAPI_Lock(hRgn, NULL)))
{
- pETEinsert = AET;
- pETEchase = AET;
- while (pETEchase->back->bres.minor_axis > AET->bres.minor_axis)
- pETEchase = pETEchase->back;
+ return ERROR;
+ }
- AET = AET->next;
- if (pETEchase != pETEinsert)
- {
- pETEchaseBackTMP = pETEchase->back;
- pETEinsert->back->next = AET;
- if (AET)
- AET->back = pETEinsert->back;
- pETEinsert->next = pETEchase;
- pETEchase->back->next = pETEinsert;
- pETEchase->back = pETEinsert;
- pETEinsert->back = pETEchaseBackTMP;
- changed = TRUE;
- }
+ ret = REGION_GetRgnBox(Rgn, &SafeRect);
+ RGNOBJAPI_Unlock(Rgn);
+ if (ERROR == ret)
+ {
+ return ret;
}
- return changed;
+
+ _SEH2_TRY
+ {
+ ProbeForWrite(pRect, sizeof(RECT), 1);
+ *pRect = SafeRect;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+ if (!NT_SUCCESS(Status))
+ {
+ return ERROR;
+ }
+
+ return ret;
}
-/***********************************************************************
- * REGION_FreeStorage
- *
- * Clean up our act.
- */
-static void FASTCALL
-REGION_FreeStorage(ScanLineListBlock *pSLLBlock)
+BOOL
+APIENTRY
+NtGdiInvertRgn(
+ HDC hDC,
+ HRGN hRgn
+)
{
- ScanLineListBlock *tmpSLLBlock;
+ PROSRGNDATA RgnData;
+ ULONG i;
+ PRECTL rc;
- while (pSLLBlock)
+ if (!(RgnData = RGNOBJAPI_Lock(hRgn, NULL)))
{
- tmpSLLBlock = pSLLBlock->next;
- ExFreePool(pSLLBlock);
- pSLLBlock = tmpSLLBlock;
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
}
-}
+ rc = RgnData->Buffer;
+ for (i = 0; i < RgnData->rdh.nCount; i++)
+ {
-/***********************************************************************
- * REGION_PtsToRegion
- *
- * Create an array of rectangles from a list of points.
- */
-static int FASTCALL
-REGION_PtsToRegion(
- int numFullPtBlocks,
- int iCurPtBlock,
- POINTBLOCK *FirstPtBlock,
- ROSRGNDATA *reg)
-{
- RECTL *rects;
- POINT *pts;
- POINTBLOCK *CurPtBlock;
- int i;
- RECTL *extents, *temp;
- INT numRects;
+ if (!NtGdiPatBlt(hDC, rc->left, rc->top, rc->right - rc->left, rc->bottom - rc->top, DSTINVERT))
+ {
+ RGNOBJAPI_Unlock(RgnData);
+ return FALSE;
+ }
+ rc++;
+ }
- extents = ®->rdh.rcBound;
+ RGNOBJAPI_Unlock(RgnData);
+ return TRUE;
+}
- numRects = ((numFullPtBlocks * NUMPTSTOBUFFER) + iCurPtBlock) >> 1;
+INT
+APIENTRY
+NtGdiOffsetRgn(
+ HRGN hRgn,
+ INT XOffset,
+ INT YOffset
+)
+{
+ PROSRGNDATA rgn = RGNOBJAPI_Lock(hRgn, NULL);
+ INT ret;
- if (!(temp = ExAllocatePoolWithTag(PagedPool, numRects * sizeof(RECT), TAG_REGION)))
- {
- return 0;
- }
- if (reg->Buffer != NULL)
+ DPRINT("NtGdiOffsetRgn: hRgn %d Xoffs %d Yoffs %d rgn %x\n", hRgn, XOffset, YOffset, rgn );
+
+ if (!rgn)
{
- COPY_RECTS(temp, reg->Buffer, reg->rdh.nCount);
- if (reg->Buffer != ®->rdh.rcBound)
- ExFreePoolWithTag(reg->Buffer, TAG_REGION);
+ DPRINT("NtGdiOffsetRgn: hRgn error\n");
+ return ERROR;
}
- reg->Buffer = temp;
- reg->rdh.nCount = numRects;
- CurPtBlock = FirstPtBlock;
- rects = reg->Buffer - 1;
- numRects = 0;
- extents->left = LARGE_COORDINATE, extents->right = SMALL_COORDINATE;
+ ret = IntGdiOffsetRgn(rgn, XOffset, YOffset);
- for ( ; numFullPtBlocks >= 0; numFullPtBlocks--)
+ RGNOBJAPI_Unlock(rgn);
+ return ret;
+}
+
+BOOL
+APIENTRY
+NtGdiPtInRegion(
+ HRGN hRgn,
+ INT X,
+ INT Y
+)
+{
+ PROSRGNDATA rgn;
+ ULONG i;
+ PRECTL r;
+
+ if (!(rgn = RGNOBJAPI_Lock(hRgn, NULL) ) )
+ return FALSE;
+
+ if (rgn->rdh.nCount > 0 && INRECT(rgn->rdh.rcBound, X, Y))
{
- /* the loop uses 2 points per iteration */
- i = NUMPTSTOBUFFER >> 1;
- if (!numFullPtBlocks)
- i = iCurPtBlock >> 1;
- for (pts = CurPtBlock->pts; i--; pts += 2)
+ r = rgn->Buffer;
+ for (i = 0; i < rgn->rdh.nCount; i++)
{
- if (pts->x == pts[1].x)
- continue;
- if (numRects && pts->x == rects->left && pts->y == rects->bottom &&
- pts[1].x == rects->right &&
- (numRects == 1 || rects[-1].top != rects->top) &&
- (i && pts[2].y > pts[1].y))
+ if (INRECT(*r, X, Y))
{
- rects->bottom = pts[1].y + 1;
- continue;
+ RGNOBJAPI_Unlock(rgn);
+ return TRUE;
}
- numRects++;
- rects++;
- rects->left = pts->x;
- rects->top = pts->y;
- rects->right = pts[1].x;
- rects->bottom = pts[1].y + 1;
- if (rects->left < extents->left)
- extents->left = rects->left;
- if (rects->right > extents->right)
- extents->right = rects->right;
+ r++;
}
- CurPtBlock = CurPtBlock->next;
}
+ RGNOBJAPI_Unlock(rgn);
+ return FALSE;
+}
- if (numRects)
- {
- extents->top = reg->Buffer->top;
- extents->bottom = rects->bottom;
- }
- else
- {
- extents->left = 0;
- extents->top = 0;
- extents->right = 0;
- extents->bottom = 0;
+BOOL
+APIENTRY
+NtGdiRectInRegion(
+ HRGN hRgn,
+ LPRECTL unsaferc
+)
+{
+ RECTL rc = {0};
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ _SEH2_TRY
+ {
+ ProbeForRead(unsaferc, sizeof(RECT), 1);
+ rc = *unsaferc;
}
- reg->rdh.nCount = numRects;
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
- return(TRUE);
+ if (!NT_SUCCESS(Status))
+ {
+ SetLastNtError(Status);
+ DPRINT1("NtGdiRectInRegion: bogus rc\n");
+ return ERROR;
+ }
+
+ return IntRectInRegion(hRgn, &rc);
}
-/***********************************************************************
- * REGION_CreateEdgeTable
- *
- * This routine creates the edge table for
- * scan converting polygons.
- * The Edge Table (ET) looks like:
- *
- * EdgeTable
- * --------
- * | ymax | ScanLineLists
- * |scanline|-->------------>-------------->...
- * -------- |scanline| |scanline|
- * |edgelist| |edgelist|
- * --------- ---------
- * | |
- * | |
- * V V
- * list of ETEs list of ETEs
- *
- * where ETE is an EdgeTableEntry data structure,
- * and there is one ScanLineList per scanline at
- * which an edge is initially entered.
- *
- */
-static void FASTCALL
-REGION_CreateETandAET(
- const ULONG *Count,
- INT nbpolygons,
- const POINT *pts,
- EdgeTable *ET,
- EdgeTableEntry *AET,
- EdgeTableEntry *pETEs,
- ScanLineListBlock *pSLLBlock
+BOOL
+APIENTRY
+NtGdiSetRectRgn(
+ HRGN hRgn,
+ INT LeftRect,
+ INT TopRect,
+ INT RightRect,
+ INT BottomRect
)
{
- const POINT *top, *bottom;
- const POINT *PrevPt, *CurrPt, *EndPt;
- INT poly, count;
- int iSLLBlock = 0;
- int dy;
-
-
- /*
- * initialize the Active Edge Table
- */
- AET->next = (EdgeTableEntry *)NULL;
- AET->back = (EdgeTableEntry *)NULL;
- AET->nextWETE = (EdgeTableEntry *)NULL;
- AET->bres.minor_axis = SMALL_COORDINATE;
-
- /*
- * initialize the Edge Table.
- */
- ET->scanlines.next = (ScanLineList *)NULL;
- ET->ymax = SMALL_COORDINATE;
- ET->ymin = LARGE_COORDINATE;
- pSLLBlock->next = (ScanLineListBlock *)NULL;
+ PROSRGNDATA rgn;
- EndPt = pts - 1;
- for (poly = 0; poly < nbpolygons; poly++)
+ if ( !(rgn = RGNOBJAPI_Lock(hRgn, NULL)) )
{
- count = Count[poly];
- EndPt += count;
- if (count < 2)
- continue;
-
- PrevPt = EndPt;
-
- /*
- * for each vertex in the array of points.
- * In this loop we are dealing with two vertices at
- * a time -- these make up one edge of the polygon.
- */
- while (count--)
- {
- CurrPt = pts++;
+ return 0; //per documentation
+ }
- /*
- * find out which point is above and which is below.
- */
- if (PrevPt->y > CurrPt->y)
- {
- bottom = PrevPt, top = CurrPt;
- pETEs->ClockWise = 0;
- }
- else
- {
- bottom = CurrPt, top = PrevPt;
- pETEs->ClockWise = 1;
- }
+ REGION_SetRectRgn(rgn, LeftRect, TopRect, RightRect, BottomRect);
- /*
- * don't add horizontal edges to the Edge table.
- */
- if (bottom->y != top->y)
- {
- pETEs->ymax = bottom->y-1;
- /* -1 so we don't get last scanline */
+ RGNOBJAPI_Unlock(rgn);
+ return TRUE;
+}
- /*
- * initialize integer edge algorithm
- */
- dy = bottom->y - top->y;
- BRESINITPGONSTRUCT(dy, top->x, bottom->x, pETEs->bres);
+HRGN APIENTRY
+NtGdiUnionRectWithRgn(
+ HRGN hDest,
+ const RECTL *UnsafeRect
+)
+{
+ RECTL SafeRect = {0};
+ PROSRGNDATA Rgn;
+ NTSTATUS Status = STATUS_SUCCESS;
- REGION_InsertEdgeInET(ET, pETEs, top->y, &pSLLBlock,
- &iSLLBlock);
+ if (!(Rgn = RGNOBJAPI_Lock(hDest, NULL)))
+ {
+ EngSetLastError(ERROR_INVALID_HANDLE);
+ return NULL;
+ }
- if (PrevPt->y > ET->ymax)
- ET->ymax = PrevPt->y;
- if (PrevPt->y < ET->ymin)
- ET->ymin = PrevPt->y;
- pETEs++;
- }
+ _SEH2_TRY
+ {
+ ProbeForRead(UnsafeRect, sizeof(RECT), 1);
+ SafeRect = *UnsafeRect;
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
- PrevPt = CurrPt;
- }
+ if (! NT_SUCCESS(Status))
+ {
+ RGNOBJAPI_Unlock(Rgn);
+ SetLastNtError(Status);
+ return NULL;
}
+
+ REGION_UnionRectWithRgn(Rgn, &SafeRect);
+ RGNOBJAPI_Unlock(Rgn);
+ return hDest;
}
-HRGN FASTCALL
-IntCreatePolyPolygonRgn(
- POINT *Pts,
- PULONG Count,
- INT nbpolygons,
- INT mode
+/*!
+ * MSDN: GetRegionData, Return Values:
+ *
+ * "If the function succeeds and dwCount specifies an adequate number of bytes,
+ * the return value is always dwCount. If dwCount is too small or the function
+ * fails, the return value is 0. If lpRgnData is NULL, the return value is the
+ * required number of bytes.
+ *
+ * If the function fails, the return value is zero."
+ */
+DWORD APIENTRY
+NtGdiGetRegionData(
+ HRGN hrgn,
+ DWORD count,
+ LPRGNDATA rgndata
)
{
- HRGN hrgn;
- ROSRGNDATA *region;
- EdgeTableEntry *pAET; /* Active Edge Table */
- INT y; /* current scanline */
- int iPts = 0; /* number of pts in buffer */
- EdgeTableEntry *pWETE; /* Winding Edge Table Entry*/
- ScanLineList *pSLL; /* current scanLineList */
- POINT *pts; /* output buffer */
- EdgeTableEntry *pPrevAET; /* ptr to previous AET */
- EdgeTable ET; /* header node for ET */
- EdgeTableEntry AET; /* header node for AET */
- EdgeTableEntry *pETEs; /* EdgeTableEntries pool */
- ScanLineListBlock SLLBlock; /* header for scanlinelist */
- int fixWAET = FALSE;
- POINTBLOCK FirstPtBlock, *curPtBlock; /* PtBlock buffers */
- POINTBLOCK *tmpPtBlock;
- int numFullPtBlocks = 0;
- INT poly, total;
-
- if (mode == 0 || mode > 2) return 0;
+ DWORD size;
+ PROSRGNDATA obj = RGNOBJAPI_Lock(hrgn, NULL);
+ NTSTATUS Status = STATUS_SUCCESS;
- if (!(region = REGION_AllocRgnWithHandle(nbpolygons)))
+ if (!obj)
return 0;
- hrgn = region->BaseObject.hHmgr;
-
- /* 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_UnlockRgn(region);
- NtGdiSetRectRgn(hrgn, 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));
- return hrgn;
- }
- for (poly = total = 0; poly < nbpolygons; poly++)
- total += Count[poly];
- if (! (pETEs = ExAllocatePoolWithTag(PagedPool, sizeof(EdgeTableEntry) * total, TAG_REGION)) )
+ size = obj->rdh.nCount * sizeof(RECT);
+ if (count < (size + sizeof(RGNDATAHEADER)) || rgndata == NULL)
{
- GreDeleteObject(hrgn);
- return 0;
+ RGNOBJAPI_Unlock(obj);
+ if (rgndata) /* buffer is too small, signal it by return 0 */
+ return 0;
+ else /* user requested buffer size with rgndata NULL */
+ return size + sizeof(RGNDATAHEADER);
}
- pts = FirstPtBlock.pts;
- REGION_CreateETandAET(Count, nbpolygons, Pts, &ET, &AET, pETEs, &SLLBlock);
- pSLL = ET.scanlines.next;
- curPtBlock = &FirstPtBlock;
- if (mode != WINDING)
+ _SEH2_TRY
{
- /*
- * for each scanline
- */
- for (y = ET.ymin; y < ET.ymax; y++)
- {
- /*
- * Add a new edge to the active edge table when we
- * get to the next edge.
- */
- if (pSLL != NULL && y == pSLL->scanline)
- {
- REGION_loadAET(&AET, pSLL->edgelist);
- pSLL = pSLL->next;
- }
- pPrevAET = &AET;
- pAET = AET.next;
-
- /*
- * for each active edge
- */
- while (pAET)
- {
- pts->x = pAET->bres.minor_axis, pts->y = y;
- pts++, iPts++;
-
- /*
- * send out the buffer
- */
- if (iPts == NUMPTSTOBUFFER)
- {
- tmpPtBlock = ExAllocatePoolWithTag(PagedPool, sizeof(POINTBLOCK), TAG_REGION);
- if (!tmpPtBlock)
- {
- DPRINT1("Can't alloc tPB\n");
- ExFreePoolWithTag(pETEs, TAG_REGION);
- return 0;
- }
- curPtBlock->next = tmpPtBlock;
- curPtBlock = tmpPtBlock;
- pts = curPtBlock->pts;
- numFullPtBlocks++;
- iPts = 0;
- }
- EVALUATEEDGEEVENODD(pAET, pPrevAET, y);
- }
- REGION_InsertionSort(&AET);
- }
+ ProbeForWrite(rgndata, count, 1);
+ RtlCopyMemory(rgndata, &obj->rdh, sizeof(RGNDATAHEADER));
+ RtlCopyMemory(rgndata->Buffer, obj->Buffer, size);
}
- else
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
- /*
- * for each scanline
- */
- for (y = ET.ymin; y < ET.ymax; y++)
- {
- /*
- * Add a new edge to the active edge table when we
- * get to the next edge.
- */
- if (pSLL != NULL && y == pSLL->scanline)
- {
- REGION_loadAET(&AET, pSLL->edgelist);
- REGION_computeWAET(&AET);
- pSLL = pSLL->next;
- }
- pPrevAET = &AET;
- pAET = AET.next;
- pWETE = pAET;
-
- /*
- * for each active edge
- */
- while (pAET)
- {
- /*
- * add to the buffer only those edges that
- * are in the Winding active edge table.
- */
- if (pWETE == pAET)
- {
- pts->x = pAET->bres.minor_axis, pts->y = y;
- pts++, iPts++;
-
- /*
- * send out the buffer
- */
- if (iPts == NUMPTSTOBUFFER)
- {
- tmpPtBlock = ExAllocatePoolWithTag(PagedPool,
- sizeof(POINTBLOCK), TAG_REGION);
- if (!tmpPtBlock)
- {
- DPRINT1("Can't alloc tPB\n");
- ExFreePoolWithTag(pETEs, TAG_REGION);
- GreDeleteObject(hrgn);
- return 0;
- }
- curPtBlock->next = tmpPtBlock;
- curPtBlock = tmpPtBlock;
- pts = curPtBlock->pts;
- numFullPtBlocks++;
- iPts = 0;
- }
- pWETE = pWETE->nextWETE;
- }
- EVALUATEEDGEWINDING(pAET, pPrevAET, y, fixWAET);
- }
-
- /*
- * recompute the winding active edge table if
- * we just resorted or have exited an edge.
- */
- if (REGION_InsertionSort(&AET) || fixWAET)
- {
- REGION_computeWAET(&AET);
- fixWAET = FALSE;
- }
- }
+ Status = _SEH2_GetExceptionCode();
}
- REGION_FreeStorage(SLLBlock.next);
- REGION_PtsToRegion(numFullPtBlocks, iPts, &FirstPtBlock, region);
+ _SEH2_END;
- for (curPtBlock = FirstPtBlock.next; --numFullPtBlocks >= 0;)
+ if (!NT_SUCCESS(Status))
{
- tmpPtBlock = curPtBlock->next;
- ExFreePoolWithTag(curPtBlock, TAG_REGION);
- curPtBlock = tmpPtBlock;
+ SetLastNtError(Status);
+ RGNOBJAPI_Unlock(obj);
+ return 0;
}
- ExFreePoolWithTag(pETEs, TAG_REGION);
- REGION_UnlockRgn(region);
- return hrgn;
+
+ RGNOBJAPI_Unlock(obj);
+ return size + sizeof(RGNDATAHEADER);
}
/* EOF */