mirror of
https://github.com/reactos/reactos.git
synced 2024-11-18 13:01:40 +00:00
94b4b5c127
Fix results from tests, add (last one) gdi batch support for ExtSelectClipRgn. Left commented out test code in tree this time. Pass Katayama Hirofumi MZ SelectClipRgn tests. After commit will plug in the last batch. After 12 years. See CORE-13817 and CORE-15906.
661 lines
17 KiB
C
661 lines
17 KiB
C
/*
|
|
* PROJECT: ReactOS Win32k Subsystem
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: win32ss/gdi/ntgdi/line.c
|
|
* PURPOSE: Line functions
|
|
* PROGRAMMERS: ...
|
|
*/
|
|
|
|
#include <win32k.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
// Some code from the WINE project source (www.winehq.com)
|
|
|
|
VOID FASTCALL
|
|
AddPenLinesBounds(PDC dc, int count, POINT *points)
|
|
{
|
|
DWORD join, endcap;
|
|
RECTL bounds, rect;
|
|
LONG lWidth;
|
|
PBRUSH pbrLine;
|
|
|
|
/* Get BRUSH from current pen. */
|
|
pbrLine = dc->dclevel.pbrLine;
|
|
ASSERT(pbrLine);
|
|
|
|
lWidth = pbrLine->lWidth;
|
|
|
|
// Setup bounds
|
|
bounds.left = bounds.top = INT_MAX;
|
|
bounds.right = bounds.bottom = INT_MIN;
|
|
|
|
if (((pbrLine->ulPenStyle & PS_TYPE_MASK) & PS_GEOMETRIC) || lWidth > 1)
|
|
{
|
|
/* Windows uses some heuristics to estimate the distance from the point that will be painted */
|
|
lWidth = lWidth + 2;
|
|
endcap = (PS_ENDCAP_MASK & pbrLine->ulPenStyle);
|
|
join = (PS_JOIN_MASK & pbrLine->ulPenStyle);
|
|
if (join == PS_JOIN_MITER)
|
|
{
|
|
lWidth *= 5;
|
|
if (endcap == PS_ENDCAP_SQUARE) lWidth = (lWidth * 3 + 1) / 2;
|
|
}
|
|
else
|
|
{
|
|
if (endcap == PS_ENDCAP_SQUARE) lWidth -= lWidth / 4;
|
|
else lWidth = (lWidth + 1) / 2;
|
|
}
|
|
}
|
|
|
|
while (count-- > 0)
|
|
{
|
|
rect.left = points->x - lWidth;
|
|
rect.top = points->y - lWidth;
|
|
rect.right = points->x + lWidth + 1;
|
|
rect.bottom = points->y + lWidth + 1;
|
|
RECTL_bUnionRect(&bounds, &bounds, &rect);
|
|
points++;
|
|
}
|
|
|
|
DPRINT("APLB dc %p l %d t %d\n",dc,rect.left,rect.top);
|
|
DPRINT(" r %d b %d\n",rect.right,rect.bottom);
|
|
|
|
{
|
|
RECTL rcRgn = dc->erclClip; // Use the clip box for now.
|
|
|
|
if (RECTL_bIntersectRect( &rcRgn, &rcRgn, &bounds ))
|
|
IntUpdateBoundsRect(dc, &rcRgn);
|
|
else
|
|
IntUpdateBoundsRect(dc, &bounds);
|
|
}
|
|
}
|
|
|
|
// Should use Fx in Point
|
|
//
|
|
BOOL FASTCALL
|
|
IntGdiMoveToEx(DC *dc,
|
|
int X,
|
|
int Y,
|
|
LPPOINT Point)
|
|
{
|
|
PDC_ATTR pdcattr = dc->pdcattr;
|
|
if ( Point )
|
|
{
|
|
if ( pdcattr->ulDirty_ & DIRTY_PTLCURRENT ) // Double hit!
|
|
{
|
|
Point->x = pdcattr->ptfxCurrent.x; // ret prev before change.
|
|
Point->y = pdcattr->ptfxCurrent.y;
|
|
IntDPtoLP ( dc, Point, 1); // Reconvert back.
|
|
}
|
|
else
|
|
{
|
|
Point->x = pdcattr->ptlCurrent.x;
|
|
Point->y = pdcattr->ptlCurrent.y;
|
|
}
|
|
}
|
|
pdcattr->ptlCurrent.x = X;
|
|
pdcattr->ptlCurrent.y = Y;
|
|
pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
|
|
CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
|
|
pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
GreMoveTo( HDC hdc,
|
|
INT x,
|
|
INT y,
|
|
LPPOINT pptOut)
|
|
{
|
|
BOOL Ret;
|
|
PDC dc;
|
|
if (!(dc = DC_LockDc(hdc)))
|
|
{
|
|
EngSetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
Ret = IntGdiMoveToEx(dc, x, y, pptOut);
|
|
DC_UnlockDc(dc);
|
|
return Ret;
|
|
}
|
|
|
|
// Should use Fx in pt
|
|
//
|
|
VOID FASTCALL
|
|
IntGetCurrentPositionEx(PDC dc, LPPOINT pt)
|
|
{
|
|
PDC_ATTR pdcattr = dc->pdcattr;
|
|
|
|
if ( pt )
|
|
{
|
|
if (pdcattr->ulDirty_ & DIRTY_PTFXCURRENT)
|
|
{
|
|
pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
|
|
CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
|
|
pdcattr->ulDirty_ &= ~(DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
|
|
}
|
|
pt->x = pdcattr->ptlCurrent.x;
|
|
pt->y = pdcattr->ptlCurrent.y;
|
|
}
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
IntGdiLineTo(DC *dc,
|
|
int XEnd,
|
|
int YEnd)
|
|
{
|
|
SURFACE *psurf;
|
|
BOOL Ret = TRUE;
|
|
PBRUSH pbrLine;
|
|
RECTL Bounds;
|
|
POINT Points[2];
|
|
PDC_ATTR pdcattr = dc->pdcattr;
|
|
ASSERT_DC_PREPARED(dc);
|
|
|
|
if (PATH_IsPathOpen(dc->dclevel))
|
|
{
|
|
Ret = PATH_LineTo(dc, XEnd, YEnd);
|
|
}
|
|
else
|
|
{
|
|
psurf = dc->dclevel.pSurface;
|
|
if (NULL == psurf)
|
|
{
|
|
EngSetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
Points[0].x = pdcattr->ptlCurrent.x;
|
|
Points[0].y = pdcattr->ptlCurrent.y;
|
|
Points[1].x = XEnd;
|
|
Points[1].y = YEnd;
|
|
|
|
IntLPtoDP(dc, Points, 2);
|
|
|
|
/* The DCOrg is in device coordinates */
|
|
Points[0].x += dc->ptlDCOrig.x;
|
|
Points[0].y += dc->ptlDCOrig.y;
|
|
Points[1].x += dc->ptlDCOrig.x;
|
|
Points[1].y += dc->ptlDCOrig.y;
|
|
|
|
Bounds.left = min(Points[0].x, Points[1].x);
|
|
Bounds.top = min(Points[0].y, Points[1].y);
|
|
Bounds.right = max(Points[0].x, Points[1].x);
|
|
Bounds.bottom = max(Points[0].y, Points[1].y);
|
|
|
|
/* Get BRUSH from current pen. */
|
|
pbrLine = dc->dclevel.pbrLine;
|
|
ASSERT(pbrLine);
|
|
|
|
if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
|
|
{
|
|
DPRINT("Bounds dc %p l %d t %d\n",dc,Bounds.left,Bounds.top);
|
|
DPRINT(" r %d b %d\n",Bounds.right,Bounds.bottom);
|
|
AddPenLinesBounds(dc, 2, Points);
|
|
}
|
|
|
|
if (!(pbrLine->flAttrs & BR_IS_NULL))
|
|
{
|
|
Ret = IntEngLineTo(&psurf->SurfObj,
|
|
(CLIPOBJ *)&dc->co,
|
|
&dc->eboLine.BrushObject,
|
|
Points[0].x, Points[0].y,
|
|
Points[1].x, Points[1].y,
|
|
&Bounds,
|
|
ROP2_TO_MIX(pdcattr->jROP2));
|
|
}
|
|
|
|
}
|
|
|
|
if (Ret)
|
|
{
|
|
pdcattr->ptlCurrent.x = XEnd;
|
|
pdcattr->ptlCurrent.y = YEnd;
|
|
pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
|
|
CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
|
|
pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
|
|
}
|
|
|
|
return Ret;
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
IntGdiPolyBezier(DC *dc,
|
|
LPPOINT pt,
|
|
DWORD Count)
|
|
{
|
|
BOOL ret = FALSE; // Default to FAILURE
|
|
|
|
if ( PATH_IsPathOpen(dc->dclevel) )
|
|
{
|
|
return PATH_PolyBezier ( dc, pt, Count );
|
|
}
|
|
|
|
/* We'll convert it into line segments and draw them using Polyline */
|
|
{
|
|
POINT *Pts;
|
|
INT nOut;
|
|
|
|
Pts = GDI_Bezier ( pt, Count, &nOut );
|
|
if ( Pts )
|
|
{
|
|
ret = IntGdiPolyline(dc, Pts, nOut);
|
|
ExFreePoolWithTag(Pts, TAG_BEZIER);
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
IntGdiPolyBezierTo(DC *dc,
|
|
LPPOINT pt,
|
|
DWORD Count)
|
|
{
|
|
BOOL ret = FALSE; // Default to failure
|
|
PDC_ATTR pdcattr = dc->pdcattr;
|
|
|
|
if ( PATH_IsPathOpen(dc->dclevel) )
|
|
ret = PATH_PolyBezierTo ( dc, pt, Count );
|
|
else /* We'll do it using PolyBezier */
|
|
{
|
|
POINT *npt;
|
|
npt = ExAllocatePoolWithTag(PagedPool,
|
|
sizeof(POINT) * (Count + 1),
|
|
TAG_BEZIER);
|
|
if ( npt )
|
|
{
|
|
npt[0].x = pdcattr->ptlCurrent.x;
|
|
npt[0].y = pdcattr->ptlCurrent.y;
|
|
memcpy(npt + 1, pt, sizeof(POINT) * Count);
|
|
ret = IntGdiPolyBezier(dc, npt, Count+1);
|
|
ExFreePoolWithTag(npt, TAG_BEZIER);
|
|
}
|
|
}
|
|
if ( ret )
|
|
{
|
|
pdcattr->ptlCurrent.x = pt[Count-1].x;
|
|
pdcattr->ptlCurrent.y = pt[Count-1].y;
|
|
pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
|
|
CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
|
|
pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
IntGdiPolyline(DC *dc,
|
|
LPPOINT pt,
|
|
int Count)
|
|
{
|
|
SURFACE *psurf;
|
|
BRUSH *pbrLine;
|
|
LPPOINT Points;
|
|
BOOL Ret = TRUE;
|
|
LONG i;
|
|
PDC_ATTR pdcattr = dc->pdcattr;
|
|
|
|
if (!dc->dclevel.pSurface)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
DC_vPrepareDCsForBlit(dc, NULL, NULL, NULL);
|
|
psurf = dc->dclevel.pSurface;
|
|
|
|
/* Get BRUSHOBJ from current pen. */
|
|
pbrLine = dc->dclevel.pbrLine;
|
|
ASSERT(pbrLine);
|
|
|
|
if (!(pbrLine->flAttrs & BR_IS_NULL))
|
|
{
|
|
Points = EngAllocMem(0, Count * sizeof(POINT), GDITAG_TEMP);
|
|
if (Points != NULL)
|
|
{
|
|
RtlCopyMemory(Points, pt, Count * sizeof(POINT));
|
|
IntLPtoDP(dc, Points, Count);
|
|
|
|
/* Offset the array of points by the DC origin */
|
|
for (i = 0; i < Count; i++)
|
|
{
|
|
Points[i].x += dc->ptlDCOrig.x;
|
|
Points[i].y += dc->ptlDCOrig.y;
|
|
}
|
|
|
|
if (dc->fs & (DC_ACCUM_APP|DC_ACCUM_WMGR))
|
|
{
|
|
AddPenLinesBounds(dc, Count, Points);
|
|
}
|
|
|
|
Ret = IntEngPolyline(&psurf->SurfObj,
|
|
(CLIPOBJ *)&dc->co,
|
|
&dc->eboLine.BrushObject,
|
|
Points,
|
|
Count,
|
|
ROP2_TO_MIX(pdcattr->jROP2));
|
|
|
|
EngFreeMem(Points);
|
|
}
|
|
else
|
|
{
|
|
Ret = FALSE;
|
|
}
|
|
}
|
|
|
|
DC_vFinishBlit(dc, NULL);
|
|
|
|
return Ret;
|
|
}
|
|
|
|
BOOL FASTCALL
|
|
IntGdiPolylineTo(DC *dc,
|
|
LPPOINT pt,
|
|
DWORD Count)
|
|
{
|
|
BOOL ret = FALSE; // Default to failure
|
|
PDC_ATTR pdcattr = dc->pdcattr;
|
|
|
|
if (PATH_IsPathOpen(dc->dclevel))
|
|
{
|
|
ret = PATH_PolylineTo(dc, pt, Count);
|
|
}
|
|
else /* Do it using Polyline */
|
|
{
|
|
POINT *pts = ExAllocatePoolWithTag(PagedPool,
|
|
sizeof(POINT) * (Count + 1),
|
|
TAG_SHAPE);
|
|
if ( pts )
|
|
{
|
|
pts[0].x = pdcattr->ptlCurrent.x;
|
|
pts[0].y = pdcattr->ptlCurrent.y;
|
|
memcpy( pts + 1, pt, sizeof(POINT) * Count);
|
|
ret = IntGdiPolyline(dc, pts, Count + 1);
|
|
ExFreePoolWithTag(pts, TAG_SHAPE);
|
|
}
|
|
}
|
|
if ( ret )
|
|
{
|
|
pdcattr->ptlCurrent.x = pt[Count-1].x;
|
|
pdcattr->ptlCurrent.y = pt[Count-1].y;
|
|
pdcattr->ptfxCurrent = pdcattr->ptlCurrent;
|
|
CoordLPtoDP(dc, &pdcattr->ptfxCurrent); // Update fx
|
|
pdcattr->ulDirty_ &= ~(DIRTY_PTLCURRENT|DIRTY_PTFXCURRENT|DIRTY_STYLESTATE);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
BOOL FASTCALL
|
|
IntGdiPolyPolyline(DC *dc,
|
|
LPPOINT pt,
|
|
PULONG PolyPoints,
|
|
DWORD Count)
|
|
{
|
|
ULONG i;
|
|
LPPOINT pts;
|
|
PULONG pc;
|
|
BOOL ret = FALSE; // Default to failure
|
|
pts = pt;
|
|
pc = PolyPoints;
|
|
|
|
if (PATH_IsPathOpen(dc->dclevel))
|
|
{
|
|
return PATH_PolyPolyline( dc, pt, PolyPoints, Count );
|
|
}
|
|
for (i = 0; i < Count; i++)
|
|
{
|
|
ret = IntGdiPolyline ( dc, pts, *pc );
|
|
if (ret == FALSE)
|
|
{
|
|
return ret;
|
|
}
|
|
pts+=*pc++;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
|
|
BOOL
|
|
APIENTRY
|
|
NtGdiLineTo(HDC hDC,
|
|
int XEnd,
|
|
int YEnd)
|
|
{
|
|
DC *dc;
|
|
BOOL Ret;
|
|
RECT rcLockRect ;
|
|
|
|
dc = DC_LockDc(hDC);
|
|
if (!dc)
|
|
{
|
|
EngSetLastError(ERROR_INVALID_HANDLE);
|
|
return FALSE;
|
|
}
|
|
|
|
rcLockRect.left = dc->pdcattr->ptlCurrent.x;
|
|
rcLockRect.top = dc->pdcattr->ptlCurrent.y;
|
|
rcLockRect.right = XEnd;
|
|
rcLockRect.bottom = YEnd;
|
|
|
|
IntLPtoDP(dc, &rcLockRect, 2);
|
|
|
|
/* The DCOrg is in device coordinates */
|
|
rcLockRect.left += dc->ptlDCOrig.x;
|
|
rcLockRect.top += dc->ptlDCOrig.y;
|
|
rcLockRect.right += dc->ptlDCOrig.x;
|
|
rcLockRect.bottom += dc->ptlDCOrig.y;
|
|
|
|
DC_vPrepareDCsForBlit(dc, &rcLockRect, NULL, NULL);
|
|
|
|
Ret = IntGdiLineTo(dc, XEnd, YEnd);
|
|
|
|
DC_vFinishBlit(dc, NULL);
|
|
|
|
DC_UnlockDc(dc);
|
|
return Ret;
|
|
}
|
|
|
|
// FIXME: This function is completely broken
|
|
BOOL
|
|
APIENTRY
|
|
NtGdiPolyDraw(
|
|
IN HDC hdc,
|
|
IN LPPOINT lppt,
|
|
IN LPBYTE lpbTypes,
|
|
IN ULONG cCount)
|
|
{
|
|
PDC dc;
|
|
PDC_ATTR pdcattr;
|
|
POINT bzr[4];
|
|
volatile PPOINT line_pts, line_pts_old, bzr_pts;
|
|
INT num_pts, num_bzr_pts, space, space_old, size;
|
|
ULONG i;
|
|
BOOL result = FALSE;
|
|
|
|
dc = DC_LockDc(hdc);
|
|
if (!dc) return FALSE;
|
|
pdcattr = dc->pdcattr;
|
|
|
|
if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
|
|
DC_vUpdateFillBrush(dc);
|
|
|
|
if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
|
|
DC_vUpdateLineBrush(dc);
|
|
|
|
if (!cCount)
|
|
{
|
|
DC_UnlockDc(dc);
|
|
return TRUE;
|
|
}
|
|
|
|
line_pts = NULL;
|
|
line_pts_old = NULL;
|
|
bzr_pts = NULL;
|
|
|
|
_SEH2_TRY
|
|
{
|
|
ProbeArrayForRead(lppt, sizeof(POINT), cCount, sizeof(LONG));
|
|
ProbeArrayForRead(lpbTypes, sizeof(BYTE), cCount, sizeof(BYTE));
|
|
|
|
if (PATH_IsPathOpen(dc->dclevel))
|
|
{
|
|
result = PATH_PolyDraw(dc, (const POINT *)lppt, (const BYTE *)lpbTypes, cCount);
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
/* Check for valid point types */
|
|
for (i = 0; i < cCount; i++)
|
|
{
|
|
switch (lpbTypes[i])
|
|
{
|
|
case PT_MOVETO:
|
|
case PT_LINETO | PT_CLOSEFIGURE:
|
|
case PT_LINETO:
|
|
break;
|
|
case PT_BEZIERTO:
|
|
if((i + 2 < cCount) && (lpbTypes[i + 1] == PT_BEZIERTO) &&
|
|
((lpbTypes[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO))
|
|
{
|
|
i += 2;
|
|
break;
|
|
}
|
|
default:
|
|
_SEH2_LEAVE;
|
|
}
|
|
}
|
|
|
|
space = cCount + 300;
|
|
line_pts = ExAllocatePoolWithTag(PagedPool, space * sizeof(POINT), TAG_SHAPE);
|
|
if (line_pts == NULL)
|
|
{
|
|
result = FALSE;
|
|
_SEH2_LEAVE;
|
|
}
|
|
|
|
num_pts = 1;
|
|
|
|
line_pts[0].x = pdcattr->ptlCurrent.x;
|
|
line_pts[0].y = pdcattr->ptlCurrent.y;
|
|
|
|
for ( i = 0; i < cCount; i++ )
|
|
{
|
|
switch (lpbTypes[i])
|
|
{
|
|
case PT_MOVETO:
|
|
if (num_pts >= 2) IntGdiPolyline( dc, line_pts, num_pts );
|
|
num_pts = 0;
|
|
line_pts[num_pts++] = lppt[i];
|
|
break;
|
|
case PT_LINETO:
|
|
case (PT_LINETO | PT_CLOSEFIGURE):
|
|
line_pts[num_pts++] = lppt[i];
|
|
break;
|
|
case PT_BEZIERTO:
|
|
bzr[0].x = line_pts[num_pts - 1].x;
|
|
bzr[0].y = line_pts[num_pts - 1].y;
|
|
RtlCopyMemory( &bzr[1], &lppt[i], 3 * sizeof(POINT) );
|
|
|
|
if ((bzr_pts = GDI_Bezier( bzr, 4, &num_bzr_pts )))
|
|
{
|
|
size = num_pts + (cCount - i) + num_bzr_pts;
|
|
if (space < size)
|
|
{
|
|
space_old = space;
|
|
space = size * 2;
|
|
line_pts_old = line_pts;
|
|
line_pts = ExAllocatePoolWithTag(PagedPool, space * sizeof(POINT), TAG_SHAPE);
|
|
if (!line_pts) _SEH2_LEAVE;
|
|
RtlCopyMemory(line_pts, line_pts_old, space_old * sizeof(POINT));
|
|
ExFreePoolWithTag(line_pts_old, TAG_SHAPE);
|
|
line_pts_old = NULL;
|
|
}
|
|
RtlCopyMemory( &line_pts[num_pts], &bzr_pts[1], (num_bzr_pts - 1) * sizeof(POINT) );
|
|
num_pts += num_bzr_pts - 1;
|
|
ExFreePoolWithTag(bzr_pts, TAG_BEZIER);
|
|
bzr_pts = NULL;
|
|
}
|
|
i += 2;
|
|
break;
|
|
}
|
|
if (lpbTypes[i] & PT_CLOSEFIGURE) line_pts[num_pts++] = line_pts[0];
|
|
}
|
|
|
|
if (num_pts >= 2) IntGdiPolyline( dc, line_pts, num_pts );
|
|
IntGdiMoveToEx( dc, line_pts[num_pts - 1].x, line_pts[num_pts - 1].y, NULL );
|
|
result = TRUE;
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
SetLastNtError(_SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
|
|
if (line_pts != NULL)
|
|
{
|
|
ExFreePoolWithTag(line_pts, TAG_SHAPE);
|
|
}
|
|
|
|
if ((line_pts_old != NULL) && (line_pts_old != line_pts))
|
|
{
|
|
ExFreePoolWithTag(line_pts_old, TAG_SHAPE);
|
|
}
|
|
|
|
if (bzr_pts != NULL)
|
|
{
|
|
ExFreePoolWithTag(bzr_pts, TAG_BEZIER);
|
|
}
|
|
|
|
DC_UnlockDc(dc);
|
|
|
|
return result;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
_Success_(return != FALSE)
|
|
BOOL
|
|
APIENTRY
|
|
NtGdiMoveTo(
|
|
IN HDC hdc,
|
|
IN INT x,
|
|
IN INT y,
|
|
OUT OPTIONAL LPPOINT pptOut)
|
|
{
|
|
PDC pdc;
|
|
BOOL Ret;
|
|
POINT Point;
|
|
|
|
pdc = DC_LockDc(hdc);
|
|
if (!pdc) return FALSE;
|
|
|
|
Ret = IntGdiMoveToEx(pdc, x, y, &Point);
|
|
|
|
if (Ret && pptOut)
|
|
{
|
|
_SEH2_TRY
|
|
{
|
|
ProbeForWrite(pptOut, sizeof(POINT), 1);
|
|
RtlCopyMemory(pptOut, &Point, sizeof(POINT));
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
SetLastNtError(_SEH2_GetExceptionCode());
|
|
Ret = FALSE; // CHECKME: is this correct?
|
|
}
|
|
_SEH2_END;
|
|
}
|
|
|
|
DC_UnlockDc(pdc);
|
|
|
|
return Ret;
|
|
}
|
|
|
|
/* EOF */
|