diff --git a/win32ss/gdi/gdi32/objects/painting.c b/win32ss/gdi/gdi32/objects/painting.c index 2ece2184915..73e0061c448 100644 --- a/win32ss/gdi/gdi32/objects/painting.c +++ b/win32ss/gdi/gdi32/objects/painting.c @@ -283,11 +283,53 @@ PolyBezierTo( _In_reads_(cpt) const POINT *apt, _In_ DWORD cpt) { + POINT pt1 = { 0, 0 }; + BOOL ret = FALSE; + HANDLE_EMETAFDC(BOOL, PolyBezierTo, FALSE, hdc, apt, cpt); if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE; - return NtGdiPolyPolyDraw(hdc , (PPOINT)apt, &cpt, 1, GdiPolyBezierTo); + if (cpt == 3) + { + /* If there are exactly 3 points, see if all three points of + * the PolyBezierTo are equal. */ + if (apt[0].x == apt[1].x && apt[1].x == apt[2].x && + apt[0].y == apt[1].y && apt[1].y == apt[2].y) + { + POINT pt1 = { 0, 0 }; // Current Position + /* If all points are equal and they equal the start point, + * then we can just return TRUE as an optimization. */ + if (GetCurrentPositionEx(hdc, &pt1) && + pt1.x == apt[0].x && pt1.y == apt[0].y) + return TRUE; + /* If they are all equal, but not equal to the start point, + * then we can just do a LineTo and return as an optimization. */ + else + return LineTo(hdc, apt[0].x, apt[0].y); + } + } + + /* Following based on Wine 10.0 nulldrv_PolyBezierTo function */ + POINT *pts = HeapAlloc(GetProcessHeap(), 0, (cpt + 1) * sizeof(*apt)); + + if (pts) + { + if (GetCurrentPositionEx(hdc, &pt1)) + { + pts[0] = pt1; + memcpy(&pts[1], apt, sizeof(*apt) * cpt); + cpt++; + ret = NtGdiPolyPolyDraw(hdc , (PPOINT)pts, &cpt, 1, GdiPolyBezierTo); + } + else + ret = FALSE; + HeapFree(GetProcessHeap(), 0, pts); + } + else + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + + return ret; } @@ -356,11 +398,33 @@ PolylineTo( _In_reads_(cpt) const POINT *apt, _In_ DWORD cpt) { + POINT pt1 = { 0, 0 }; + BOOL ret = FALSE; + HANDLE_EMETAFDC(BOOL, PolylineTo, FALSE, hdc, apt, cpt); if ( GdiConvertAndCheckDC(hdc) == NULL ) return FALSE; - return NtGdiPolyPolyDraw(hdc , (PPOINT)apt, &cpt, 1, GdiPolyLineTo); + /* Following based on Wine 10.0 nulldrv_PolylineTo function */ + POINT *pts = HeapAlloc(GetProcessHeap(), 0, (cpt + 1) * sizeof(*apt)); + + if (pts) + { + if (GetCurrentPositionEx(hdc, &pt1)) + { + pts[0] = pt1; + memcpy(&pts[1], apt, sizeof(*apt) * cpt); + cpt++; + ret = NtGdiPolyPolyDraw(hdc , (PPOINT)pts, &cpt, 1, GdiPolyLineTo); + } + else + ret = FALSE; + HeapFree(GetProcessHeap(), 0, pts); + } + else + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + + return ret; } diff --git a/win32ss/gdi/ntgdi/fillshap.c b/win32ss/gdi/ntgdi/fillshap.c index 8f50548e374..9a4118b3b0f 100644 --- a/win32ss/gdi/ntgdi/fillshap.c +++ b/win32ss/gdi/ntgdi/fillshap.c @@ -432,7 +432,7 @@ NtGdiPolyPolyDraw( IN HDC hDC, ProbeForRead(UnsafePoints, Count * sizeof(POINT), 1); ProbeForRead(UnsafeCounts, Count * sizeof(ULONG), 1); - /* Count points and validate poligons */ + /* Count points and validate polygons */ for (i = 0; i < Count; i++) { if (UnsafeCounts[i] < 2) @@ -544,7 +544,18 @@ NtGdiPolyPolyDraw( IN HDC hDC, Ret = IntGdiPolylineTo(dc, SafePoints, *SafeCounts); break; case GdiPolyBezierTo: - Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts); + /* From Wine 10.0 dlls/win32u/painting.c NtGdiPolyPolyDraw + * UnsafeCounts[0] must be 3 * n + 1 (where n >= 1) */ + if (Count == 1 && UnsafeCounts[0] != 1 && UnsafeCounts[0] % 3 == 1) + { + SafeCounts[0]--; + Ret = IntGdiPolyBezierTo(dc, SafePoints, *SafeCounts); + } + else + { + EngSetLastError(ERROR_INVALID_PARAMETER); + Ret = FALSE; + } break; default: EngSetLastError(ERROR_INVALID_PARAMETER); diff --git a/win32ss/gdi/ntgdi/path.c b/win32ss/gdi/ntgdi/path.c index c64d872aefc..0fade86267d 100644 --- a/win32ss/gdi/ntgdi/path.c +++ b/win32ss/gdi/ntgdi/path.c @@ -323,6 +323,8 @@ PATH_ReserveEntries( pPointsNew = (POINT *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(POINT), TAG_PATH); if (!pPointsNew) return FALSE; + else + memset(pPointsNew, 0, numEntriesToAllocate * sizeof(POINT)); pFlagsNew = (BYTE *)ExAllocatePoolWithTag(PagedPool, numEntriesToAllocate * sizeof(BYTE), TAG_PATH); if (!pFlagsNew) @@ -330,6 +332,8 @@ PATH_ReserveEntries( ExFreePoolWithTag(pPointsNew, TAG_PATH); return FALSE; } + else + memset(pFlagsNew, 0, numEntriesToAllocate * sizeof(BYTE)); /* Copy old arrays to new arrays and discard old arrays */ if (pPath->pPoints) @@ -461,15 +465,25 @@ PATH_CheckRect( /* add a number of points, converting them to device coords */ /* return a pointer to the first type byte so it can be fixed up if necessary */ static BYTE *add_log_points( DC *dc, PPATH path, const POINT *points, - DWORD count, BYTE type ) + DWORD count, BYTE type, BOOL bExtraPt ) { BYTE *ret; if (!PATH_ReserveEntries( path, path->numEntriesUsed + count )) return NULL; ret = &path->pFlags[path->numEntriesUsed]; - memcpy( &path->pPoints[path->numEntriesUsed], points, count * sizeof(*points) ); - IntLPtoDP( dc, &path->pPoints[path->numEntriesUsed], count ); + + if (bExtraPt && path->numEntriesUsed == 1) + { + memcpy( &path->pPoints[0], points, (count + 1) * sizeof(*points) ); + IntLPtoDP( dc, &path->pPoints[0], count + 1); + } + else + { + memcpy( &path->pPoints[path->numEntriesUsed], points, count * sizeof(*points) ); + IntLPtoDP( dc, &path->pPoints[path->numEntriesUsed], count ); + } + memset( ret, type, count ); path->numEntriesUsed += count; return ret; @@ -531,10 +545,10 @@ static void close_figure( PPATH path ) /* add a number of points, starting a new stroke if necessary */ static BOOL add_log_points_new_stroke( DC *dc, PPATH path, const POINT *points, - DWORD count, BYTE type ) + DWORD count, BYTE type, BOOL bExtraPt) { if (!start_new_stroke( path )) return FALSE; - if (!add_log_points( dc, path, points, count, type )) return FALSE; + if (!add_log_points( dc, path, points, count, type, bExtraPt )) return FALSE; update_current_pos( path ); TRACE("ALPNS : Pos X %d Y %d\n",path->pos.x, path->pos.y); @@ -612,7 +626,7 @@ PATH_LineTo( } } } - Ret = add_log_points_new_stroke( dc, pPath, &point, 1, PT_LINETO ); + Ret = add_log_points_new_stroke( dc, pPath, &point, 1, PT_LINETO , FALSE); PATH_UnlockPath(pPath); return Ret; } @@ -1143,7 +1157,7 @@ PATH_PolyBezierTo( pPath = PATH_LockPath(dc->dclevel.hPath); if (!pPath) return FALSE; - ret = add_log_points_new_stroke( dc, pPath, pts, cbPoints, PT_BEZIERTO ); + ret = add_log_points_new_stroke( dc, pPath, pts, cbPoints, PT_BEZIERTO , TRUE); PATH_UnlockPath(pPath); return ret; @@ -1166,7 +1180,7 @@ PATH_PolyBezier( pPath = PATH_LockPath(dc->dclevel.hPath); if (!pPath) return FALSE; - type = add_log_points( dc, pPath, pts, cbPoints, PT_BEZIERTO ); + type = add_log_points( dc, pPath, pts, cbPoints, PT_BEZIERTO, FALSE ); if (!type) return FALSE; type[0] = PT_MOVETO; @@ -1217,7 +1231,7 @@ PATH_PolyDraw( break; case PT_LINETO: case PT_LINETO | PT_CLOSEFIGURE: - if (!add_log_points_new_stroke( dc, pPath, &pts[i], 1, PT_LINETO )) + if (!add_log_points_new_stroke( dc, pPath, &pts[i], 1, PT_LINETO , FALSE)) { PATH_UnlockPath(pPath); return FALSE; @@ -1227,7 +1241,7 @@ PATH_PolyDraw( if ((i + 2 < cbPoints) && (types[i + 1] == PT_BEZIERTO) && (types[i + 2] & ~PT_CLOSEFIGURE) == PT_BEZIERTO) { - if (!add_log_points_new_stroke( dc, pPath, &pts[i], 3, PT_BEZIERTO )) + if (!add_log_points_new_stroke( dc, pPath, &pts[i], 3, PT_BEZIERTO , FALSE)) { PATH_UnlockPath(pPath); return FALSE; @@ -1278,7 +1292,10 @@ PATH_PolylineTo( pPath = PATH_LockPath(dc->dclevel.hPath); if (!pPath) return FALSE; - ret = add_log_points_new_stroke( dc, pPath, pts, cbPoints, PT_LINETO ); + if (pPath->newStroke) + cbPoints--; + + ret = add_log_points_new_stroke( dc, pPath, pts, cbPoints, PT_LINETO , TRUE); PATH_UnlockPath(pPath); return ret; } @@ -1316,7 +1333,7 @@ PATH_PolyPolygon( count += counts[poly]; } - type = add_log_points( dc, pPath, pts, count, PT_LINETO ); + type = add_log_points( dc, pPath, pts, count, PT_LINETO, FALSE ); if (!type) { PATH_UnlockPath(pPath);