- rewrite NtGdiPolyPolyDraw, optimizing it and making it more windows compatible

- Make PolyCounts ULONGs, not DWORDS or INTs.
- Remove GdiCreatePolyPolygonRgn and use IntCreatePolyPolygonRgn instead to get rid of code-duplication.
- IntGdiPolygon: rename UnsafePoints to Points

svn path=/trunk/; revision=36686
This commit is contained in:
Timo Kreuzer 2008-10-07 23:02:41 +00:00
parent 8a8e0aaae0
commit 419b09b96a
6 changed files with 142 additions and 309 deletions

View file

@ -93,7 +93,7 @@ IntGdiPolyBezierTo(DC *dc,
BOOL FASTCALL
IntGdiPolyPolyline(DC *dc,
LPPOINT pt,
LPDWORD PolyPoints,
PULONG PolyPoints,
DWORD Count);
BOOL FASTCALL
@ -125,7 +125,7 @@ IntGdiPolygon(PDC dc,
BOOL FASTCALL
IntGdiPolyPolygon(DC *dc,
LPPOINT Points,
LPINT PolyCounts,
PULONG PolyCounts,
int Count);
BOOL FASTCALL IntGdiGradientFill(DC *dc,

View file

@ -43,7 +43,7 @@ VOID FASTCALL IntGdiReleaseVisRgn(PDC);
INT STDCALL IntGdiGetRgnBox(HRGN, LPRECT);
BOOL FASTCALL IntGdiPaintRgn(PDC, HRGN );
HRGN FASTCALL GdiCreatePolyPolygonRgn(CONST PPOINT, CONST PINT, INT, INT );
HRGN FASTCALL IntCreatePolyPolygonRgn(PPOINT, PULONG, INT, INT);
INT FASTCALL IntGdiCombineRgn(PROSRGNDATA, PROSRGNDATA, PROSRGNDATA, INT);
INT FASTCALL REGION_Complexity(PROSRGNDATA);

View file

@ -51,7 +51,7 @@ BOOL FASTCALL IntDrawRoundRect( PDC dc, INT Left, INT Top, INT Right, INT Bottom
BOOL FASTCALL
IntGdiPolygon(PDC dc,
PPOINT UnsafePoints,
PPOINT Points,
int Count)
{
BITMAPOBJ *BitmapObj;
@ -64,7 +64,7 @@ IntGdiPolygon(PDC dc,
ASSERT(dc); // caller's responsibility to pass a valid dc
if ( NULL == UnsafePoints || Count < 2 )
if (!Points || Count < 2 )
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE;
@ -74,25 +74,25 @@ IntGdiPolygon(PDC dc,
if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
/* Convert to screen coordinates */
IntLPtoDP(dc, UnsafePoints, Count);
IntLPtoDP(dc, Points, Count);
for (CurrentPoint = 0; CurrentPoint < Count; CurrentPoint++)
{
UnsafePoints[CurrentPoint].x += dc->ptlDCOrig.x;
UnsafePoints[CurrentPoint].y += dc->ptlDCOrig.y;
Points[CurrentPoint].x += dc->ptlDCOrig.x;
Points[CurrentPoint].y += dc->ptlDCOrig.y;
}
// No need to have path here.
{
DestRect.left = UnsafePoints[0].x;
DestRect.right = UnsafePoints[0].x;
DestRect.top = UnsafePoints[0].y;
DestRect.bottom = UnsafePoints[0].y;
DestRect.left = Points[0].x;
DestRect.right = Points[0].x;
DestRect.top = Points[0].y;
DestRect.bottom = Points[0].y;
for (CurrentPoint = 1; CurrentPoint < Count; ++CurrentPoint)
{
DestRect.left = min(DestRect.left, UnsafePoints[CurrentPoint].x);
DestRect.right = max(DestRect.right, UnsafePoints[CurrentPoint].x);
DestRect.top = min(DestRect.top, UnsafePoints[CurrentPoint].y);
DestRect.bottom = max(DestRect.bottom, UnsafePoints[CurrentPoint].y);
DestRect.left = min(DestRect.left, Points[CurrentPoint].x);
DestRect.right = max(DestRect.right, Points[CurrentPoint].x);
DestRect.top = min(DestRect.top, Points[CurrentPoint].y);
DestRect.bottom = max(DestRect.bottom, Points[CurrentPoint].y);
}
/* Special locking order to avoid lock-ups */
@ -106,7 +106,7 @@ IntGdiPolygon(PDC dc,
if (FillBrushObj && !(FillBrushObj->flAttrs & GDIBRUSH_IS_NULL))
{
IntGdiInitBrushInstance(&FillBrushInst, FillBrushObj, dc->XlateBrush);
ret = FillPolygon ( dc, BitmapObj, &FillBrushInst.BrushObject, ROP2_TO_MIX(Dc_Attr->jROP2), UnsafePoints, Count, DestRect );
ret = FillPolygon ( dc, BitmapObj, &FillBrushInst.BrushObject, ROP2_TO_MIX(Dc_Attr->jROP2), Points, Count, DestRect );
}
if (FillBrushObj)
BRUSHOBJ_UnlockBrush(FillBrushObj);
@ -122,16 +122,16 @@ IntGdiPolygon(PDC dc,
{
// DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
// UnsafePoints[0].x, UnsafePoints[0].y,
// UnsafePoints[1].x, UnsafePoints[1].y );
// Points[0].x, Points[0].y,
// Points[1].x, Points[1].y );
ret = IntEngLineTo(&BitmapObj->SurfObj,
dc->CombinedClip,
&PenBrushInst.BrushObject,
UnsafePoints[i].x, /* From */
UnsafePoints[i].y,
UnsafePoints[i+1].x, /* To */
UnsafePoints[i+1].y,
Points[i].x, /* From */
Points[i].y,
Points[i+1].x, /* To */
Points[i+1].y,
&DestRect,
ROP2_TO_MIX(Dc_Attr->jROP2)); /* MIX */
if (!ret) break;
@ -142,10 +142,10 @@ IntGdiPolygon(PDC dc,
ret = IntEngLineTo(&BitmapObj->SurfObj,
dc->CombinedClip,
&PenBrushInst.BrushObject,
UnsafePoints[Count-1].x, /* From */
UnsafePoints[Count-1].y,
UnsafePoints[0].x, /* To */
UnsafePoints[0].y,
Points[Count-1].x, /* From */
Points[Count-1].y,
Points[0].x, /* To */
Points[0].y,
&DestRect,
ROP2_TO_MIX(Dc_Attr->jROP2)); /* MIX */
}
@ -161,11 +161,11 @@ IntGdiPolygon(PDC dc,
BOOL FASTCALL
IntGdiPolyPolygon(DC *dc,
LPPOINT Points,
LPINT PolyCounts,
PULONG PolyCounts,
int Count)
{
if (PATH_IsPathOpen(dc->DcLevel))
return PATH_PolyPolygon ( dc, Points, PolyCounts, Count);
return PATH_PolyPolygon ( dc, Points, (PINT)PolyCounts, Count);
while (--Count >=0)
{
@ -336,185 +336,152 @@ extern BOOL FillPolygon(PDC dc,
ULONG_PTR
STDCALL
NtGdiPolyPolyDraw( IN HDC hDC,
IN PPOINT Points,
IN PULONG PolyCounts,
IN PPOINT UnsafePoints,
IN PULONG UnsafeCounts,
IN ULONG Count,
IN INT iFunc )
{
DC *dc;
LPPOINT Safept;
LPINT SafePolyPoints;
PVOID pTemp;
LPPOINT SafePoints;
PULONG SafeCounts;
NTSTATUS Status = STATUS_SUCCESS;
BOOL Ret = TRUE;
INT nPoints, nEmpty, nInvalid, i;
INT nPoints = 0, nMaxPoints = 0, nInvalid = 0, i;
if (iFunc == GdiPolyPolyRgn)
if (!UnsafePoints || !UnsafeCounts ||
Count == 0 || iFunc == 0 || iFunc > GdiPolyPolyRgn)
{
return (ULONG_PTR) GdiCreatePolyPolygonRgn((CONST PPOINT) Points,
(CONST PINT) PolyCounts,
Count,
(INT) hDC);
}
dc = DC_LockDc(hDC);
if (!dc)
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
/* Windows doesn't set last error */
return FALSE;
}
if (dc->DC_Type == DC_TYPE_INFO)
_SEH_TRY
{
DC_UnlockDc(dc);
/* Yes, Windows really returns TRUE in this case */
return TRUE;
}
ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1);
ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1);
if (Count > 0)
{
_SEH_TRY
{
ProbeForRead(Points,
Count * sizeof(POINT),
1);
ProbeForRead(PolyCounts,
Count * sizeof(INT),
1);
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
DC_UnlockDc(dc);
SetLastNtError(Status);
return FALSE;
}
SafePolyPoints = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_SHAPE);
if (!SafePolyPoints)
{
DC_UnlockDc(dc);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
_SEH_TRY
{
/* pointers already probed! */
RtlCopyMemory(SafePolyPoints,
PolyCounts,
Count * sizeof(INT));
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
DC_UnlockDc(dc);
ExFreePool(SafePolyPoints);
SetLastNtError(Status);
return FALSE;
}
/* validate poligons */
nPoints = 0;
nEmpty = 0;
nInvalid = 0;
/* Count points and validate poligons */
for (i = 0; i < Count; i++)
{
if (SafePolyPoints[i] == 0)
{
nEmpty++;
}
if (SafePolyPoints[i] == 1)
if (UnsafeCounts[i] < 2)
{
nInvalid++;
}
nPoints += SafePolyPoints[i];
}
if (nEmpty == Count)
{
/* if all polygon counts are zero, return without setting a last error code. */
ExFreePool(SafePolyPoints);
return FALSE;
}
if (nInvalid != 0)
{
/* if at least one poly count is 1, fail */
ExFreePool(SafePolyPoints);
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE;
}
Safept = ExAllocatePoolWithTag(PagedPool, nPoints * sizeof(POINT), TAG_SHAPE);
if (!Safept)
{
DC_UnlockDc(dc);
ExFreePool(SafePolyPoints);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
_SEH_TRY
{
/* pointers already probed! */
RtlCopyMemory(Safept,
Points,
nPoints * sizeof(POINT));
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
DC_UnlockDc(dc);
ExFreePool(SafePolyPoints);
ExFreePool(Safept);
SetLastNtError(Status);
return FALSE;
nPoints += UnsafeCounts[i];
nMaxPoints = max(nMaxPoints, UnsafeCounts[i]);
}
}
else
_SEH_HANDLE
{
DC_UnlockDc(dc);
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
/* Windows doesn't set last error */
return FALSE;
}
if (nPoints == 0 || nPoints < nMaxPoints)
{
/* If all polygon counts are zero, or we have overflow,
return without setting a last error code. */
return FALSE;
}
if (nInvalid != 0)
{
/* If at least one poly count is 0 or 1, fail */
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE;
}
/* Allocate one buffer for both counts and points */
pTemp = ExAllocatePoolWithTag(PagedPool,
Count * sizeof(ULONG) + nPoints * sizeof(POINT),
TAG_SHAPE);
if (!pTemp)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return FALSE;
}
SafeCounts = pTemp;
SafePoints = (PVOID)(SafeCounts + Count);
_SEH_TRY
{
/* Pointers already probed! */
RtlCopyMemory(SafeCounts, UnsafeCounts, Count * sizeof(ULONG));
RtlCopyMemory(SafePoints, UnsafePoints, nPoints * sizeof(POINT));
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
ExFreePool(pTemp);
return FALSE;
}
/* Special handling for GdiPolyPolyRgn */
if (iFunc == GdiPolyPolyRgn)
{
HRGN hRgn;
hRgn = IntCreatePolyPolygonRgn(SafePoints, SafeCounts, Count, (INT_PTR)hDC);
ExFreePool(pTemp);
return (ULONG_PTR)hRgn;
}
dc = DC_LockDc(hDC);
if (!dc)
{
SetLastWin32Error(ERROR_INVALID_HANDLE);
ExFreePool(pTemp);
return FALSE;
}
if (dc->DC_Type == DC_TYPE_INFO)
{
DC_UnlockDc(dc);
ExFreePool(pTemp);
/* Yes, Windows really returns TRUE in this case */
return TRUE;
}
/* Perform the actual work */
switch (iFunc)
{
case GdiPolyPolygon:
Ret = IntGdiPolyPolygon(dc, Safept, SafePolyPoints, Count);
Ret = IntGdiPolyPolygon(dc, SafePoints, SafeCounts, Count);
break;
case GdiPolyPolyLine:
Ret = IntGdiPolyPolyline(dc, Safept, (LPDWORD) SafePolyPoints, Count);
Ret = IntGdiPolyPolyline(dc, SafePoints, SafeCounts, Count);
break;
case GdiPolyBezier:
Ret = IntGdiPolyBezier(dc, Safept, *PolyCounts);
Ret = IntGdiPolyBezier(dc, SafePoints, *SafeCounts);
break;
case GdiPolyLineTo:
Ret = IntGdiPolylineTo(dc, Safept, *PolyCounts);
Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts);
break;
case GdiPolyBezierTo:
Ret = IntGdiPolyBezierTo(dc, Safept, *PolyCounts);
Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts);
break;
default:
SetLastWin32Error(ERROR_INVALID_PARAMETER);
Ret = FALSE;
}
ExFreePool(SafePolyPoints);
ExFreePool(Safept);
DC_UnlockDc(dc);
return (ULONG_PTR) Ret;
/* Cleanup and return */
DC_UnlockDc(dc);
ExFreePool(pTemp);
return (ULONG_PTR)Ret;
}

View file

@ -350,12 +350,12 @@ IntGdiPolylineTo(DC *dc,
BOOL FASTCALL
IntGdiPolyPolyline(DC *dc,
LPPOINT pt,
LPDWORD PolyPoints,
PULONG PolyPoints,
DWORD Count)
{
int i;
LPPOINT pts;
LPDWORD pc;
PULONG pc;
BOOL ret = FALSE; // default to failure
pts = pt;
pc = PolyPoints;

View file

@ -1028,7 +1028,6 @@ PATH_FlattenPath(PPATH pPath)
}
HRGN FASTCALL IntCreatePolyPolygonRgn(POINT *Pts, INT *Count, INT nbpolygons,INT mode);
/* PATH_PathToRegion
*
* Creates a region from the specified path using the specified polygon
@ -1042,7 +1041,7 @@ FASTCALL
PATH_PathToRegion ( PPATH pPath, INT nPolyFillMode, HRGN *pHrgn )
{
int numStrokes, iStroke, i;
INT *pNumPointsInStroke;
PULONG pNumPointsInStroke;
HRGN hrgn = 0;
ASSERT(pPath!=NULL);
@ -1060,7 +1059,7 @@ PATH_PathToRegion ( PPATH pPath, INT nPolyFillMode, HRGN *pHrgn )
numStrokes++;
/* Allocate memory for number-of-points-in-stroke array */
pNumPointsInStroke=(int *)ExAllocatePoolWithTag(PagedPool, sizeof(int) * numStrokes, TAG_PATH);
pNumPointsInStroke = ExAllocatePoolWithTag(PagedPool, sizeof(ULONG) * numStrokes, TAG_PATH);
if(!pNumPointsInStroke)
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);

View file

@ -3560,7 +3560,7 @@ REGION_PtsToRegion(
*/
static void FASTCALL
REGION_CreateETandAET(
const INT *Count,
const ULONG *Count,
INT nbpolygons,
const POINT *pts,
EdgeTable *ET,
@ -3657,7 +3657,7 @@ REGION_CreateETandAET(
HRGN FASTCALL
IntCreatePolyPolygonRgn(
POINT *Pts,
INT *Count,
PULONG Count,
INT nbpolygons,
INT mode
)
@ -3681,6 +3681,8 @@ IntCreatePolyPolygonRgn(
int numFullPtBlocks = 0;
INT poly, total;
if (mode == 0 || mode > 2) return 0;
if (!(region = REGION_AllocRgnWithHandle(nbpolygons)))
return 0;
hrgn = region->BaseObject.hHmgr;
@ -3851,139 +3853,4 @@ IntCreatePolyPolygonRgn(
return hrgn;
}
HRGN
FASTCALL
GdiCreatePolyPolygonRgn(
CONST PPOINT pt,
CONST PINT PolyCounts,
INT Count,
INT PolyFillMode
)
{
POINT *Safept;
INT *SafePolyCounts;
INT nPoints, nEmpty, nInvalid, i;
HRGN hRgn;
NTSTATUS Status = STATUS_SUCCESS;
if (pt == NULL || PolyCounts == NULL || Count == 0 ||
(PolyFillMode != WINDING && PolyFillMode != ALTERNATE))
{
/* Windows doesn't set a last error here */
return (HRGN)0;
}
_SEH_TRY
{
ProbeForRead(PolyCounts, Count * sizeof(INT), 1);
/* just probe one point for now, we don't know the length of the array yet */
ProbeForRead(pt, sizeof(POINT), 1);
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
SetLastNtError(Status);
return (HRGN)0;
}
if (!(SafePolyCounts = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_REGION)))
{
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return (HRGN)0;
}
_SEH_TRY
{
/* pointers were already probed! */
RtlCopyMemory(SafePolyCounts,
PolyCounts,
Count * sizeof(INT));
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
ExFreePool(SafePolyCounts);
SetLastNtError(Status);
return (HRGN)0;
}
/* validate poligons */
nPoints = 0;
nEmpty = 0;
nInvalid = 0;
for (i = 0; i < Count; i++)
{
if (SafePolyCounts[i] == 0)
{
nEmpty++;
}
if (SafePolyCounts[i] == 1)
{
nInvalid++;
}
nPoints += SafePolyCounts[i];
}
if (nEmpty == Count)
{
/* if all polygon counts are zero, return without setting a last error code. */
ExFreePool(SafePolyCounts);
return (HRGN)0;
}
if (nInvalid != 0)
{
/* if at least one poly count is 1, fail */
ExFreePool(SafePolyCounts);
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return (HRGN)0;
}
/* copy points */
if (!(Safept = ExAllocatePoolWithTag(PagedPool, nPoints * sizeof(POINT), TAG_REGION)))
{
ExFreePool(SafePolyCounts);
SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
return (HRGN)0;
}
_SEH_TRY
{
ProbeForRead(pt, nPoints * sizeof(POINT), 1);
/* pointers were already probed! */
RtlCopyMemory(Safept,
pt,
nPoints * sizeof(POINT));
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
ExFreePool(Safept);
ExFreePool(SafePolyCounts);
SetLastNtError(Status);
return (HRGN)0;
}
/* now we're ready to calculate the region safely */
hRgn = IntCreatePolyPolygonRgn(Safept, SafePolyCounts, Count, PolyFillMode);
ExFreePool(Safept);
ExFreePool(SafePolyCounts);
return hRgn;
}
/* EOF */