https://git.reactos.org/?p=reactos.git;a=commitdiff;h=26b5596a111c60b3675df11ba7a03729c42a60c3
commit 26b5596a111c60b3675df11ba7a03729c42a60c3 Author: Jérôme Gardou <jerome.gar...@reactos.org> AuthorDate: Wed Mar 31 16:17:02 2021 +0200 Commit: Jérôme Gardou <zefk...@users.noreply.github.com> CommitDate: Wed Mar 31 18:35:31 2021 +0200 [WIN32K] Rewrite PATH_Ellipse & PATH_RoundRect using integer arithmetics --- win32ss/gdi/ntgdi/path.c | 263 +++++++++++++++++++++++++---------------------- win32ss/gdi/ntgdi/path.h | 5 +- 2 files changed, 144 insertions(+), 124 deletions(-) diff --git a/win32ss/gdi/ntgdi/path.c b/win32ss/gdi/ntgdi/path.c index 92be0058e03..717fe9568b9 100644 --- a/win32ss/gdi/ntgdi/path.c +++ b/win32ss/gdi/ntgdi/path.c @@ -396,8 +396,8 @@ PATH_ScaleNormalizedPoint( * Normalizes a point with respect to the box whose corners are passed in * corners. The normalized coordinates are stored in *pX and *pY. */ +static VOID -FASTCALL PATH_NormalizePoint( POINTL corners[], const POINTL *pPoint, @@ -428,47 +428,32 @@ PATH_NormalizePoint( * * Helper function for PATH_RoundRect() and PATH_Rectangle() */ +static BOOL -PATH_CheckCorners( +PATH_CheckRect( DC *dc, - POINT corners[], + RECTL* rect, INT x1, INT y1, INT x2, INT y2) { - INT temp; PDC_ATTR pdcattr = dc->pdcattr; /* Convert points to device coordinates */ - corners[0].x = x1; - corners[0].y = y1; - corners[1].x = x2; - corners[1].y = y2; - IntLPtoDP(dc, corners, 2); + RECTL_vSetRect(rect, x1, y1, x2, y2); + IntLPtoDP(dc, (PPOINT)rect, 2); /* Make sure first corner is top left and second corner is bottom right */ - if (corners[0].x > corners[1].x) - { - temp = corners[0].x; - corners[0].x = corners[1].x; - corners[1].x = temp; - } - - if (corners[0].y > corners[1].y) - { - temp = corners[0].y; - corners[0].y = corners[1].y; - corners[1].y = temp; - } + RECTL_vMakeWellOrdered(rect); /* In GM_COMPATIBLE, don't include bottom and right edges */ if (pdcattr->iGraphicsMode == GM_COMPATIBLE) { - if (corners[0].x == corners[1].x) return FALSE; - if (corners[0].y == corners[1].y) return FALSE; - corners[1].x--; - corners[1].y--; + if (rect->left == rect->right) return FALSE; + if (rect->top == rect->bottom) return FALSE; + rect->right--; + rect->bottom--; } return TRUE; } @@ -647,26 +632,25 @@ PATH_Rectangle( INT y2) { PPATH pPath; - POINT corners[2], points[4]; + RECTL rect; + POINTL points[4]; BYTE *type; pPath = PATH_LockPath(dc->dclevel.hPath); if (!pPath) return FALSE; - if (!PATH_CheckCorners(dc, corners, x1, y1, x2, y2)) + if (!PATH_CheckRect(dc, &rect, x1, y1, x2, y2)) { PATH_UnlockPath(pPath); return TRUE; } - points[0].x = corners[1].x; - points[0].y = corners[0].y; - points[1] = corners[0]; - points[2].x = corners[0].x; - points[2].y = corners[1].y; - points[3] = corners[1]; + points[0].x = rect.right; points[0].y = rect.top; + points[1].x = rect.left; points[1].y = rect.top; + points[2].x = rect.left; points[2].y = rect.bottom; + points[3].x = rect.right; points[3].y = rect.bottom; - if (dc->dclevel.flPath & DCPATH_CLOCKWISE) reverse_points( points, 4 ); + if (dc->dclevel.flPath & DCPATH_CLOCKWISE) reverse_points(points, 4 ); if (!(type = add_points( pPath, points, 4, PT_LINETO ))) { @@ -688,7 +672,6 @@ PATH_Rectangle( * */ BOOL -FASTCALL PATH_RoundRect( DC *dc, INT x1, @@ -698,72 +681,85 @@ PATH_RoundRect( INT ell_width, INT ell_height) { - const double factor = 0.55428475; /* 4 / 3 * (sqrt(2) - 1) */ PPATH pPath; - POINT corners[2], ellipse[2], points[16]; + RECTL rect, ellipse; + POINT points[16]; BYTE *type; - double width, height; + INT xOffset, yOffset; if (!ell_width || !ell_height) return PATH_Rectangle( dc, x1, y1, x2, y2 ); pPath = PATH_LockPath(dc->dclevel.hPath); if (!pPath) return FALSE; - if (!PATH_CheckCorners(dc, corners, x1, y1, x2, y2)) + if (!PATH_CheckRect(dc, &rect, x1, y1, x2, y2)) { PATH_UnlockPath(pPath); return TRUE; } - ellipse[0].x = ellipse[0].y = 0; - ellipse[1].x = ell_width; - ellipse[1].y = ell_height; - IntLPtoDP( dc, &ellipse, 2 ); - ell_width = min( abs( ellipse[1].x - ellipse[0].x ), corners[1].x - corners[0].x ); - ell_height = min( abs( ellipse[1].y - ellipse[0].y ), corners[1].y - corners[0].y ); - width = ell_width / 2.0; - height = ell_height / 2.0; + RECTL_vSetRect(&ellipse, 0, 0, ell_width, ell_height); + IntLPtoDP( dc, (PPOINT)&ellipse, 2 ); + RECTL_vMakeWellOrdered(&ellipse); + ell_width = min(RECTL_lGetWidth(&ellipse), RECTL_lGetWidth(&rect)); + ell_height = min(RECTL_lGetHeight(&ellipse), RECTL_lGetHeight(&rect)); + + /* + * See here to understand what's happening + * https://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves + */ + xOffset = EngMulDiv(ell_width, 44771525, 200000000); /* w * (1 - 0.5522847) / 2 */ + yOffset = EngMulDiv(ell_height, 44771525, 200000000); /* h * (1 - 0.5522847) / 2 */ + TRACE("xOffset %d, yOffset %d, Rect WxH: %dx%d.\n", + xOffset, yOffset, RECTL_lGetWidth(&rect), RECTL_lGetHeight(&rect)); + + /* + * Get half width & height. + * Do not use integer division, we need the rounding made by EngMulDiv. + */ + ell_width = EngMulDiv(ell_width, 1, 2); + ell_height = EngMulDiv(ell_height, 1, 2); /* starting point */ - points[0].x = corners[1].x; - points[0].y = corners[0].y + GDI_ROUND( height ); + points[0].x = rect.right; + points[0].y = rect.top + ell_height; /* first curve */ - points[1].x = corners[1].x; - points[1].y = corners[0].y + GDI_ROUND( height * (1 - factor) ); - points[2].x = corners[1].x - GDI_ROUND( width * (1 - factor) ); - points[2].y = corners[0].y; - points[3].x = corners[1].x - GDI_ROUND( width ); - points[3].y = corners[0].y; + points[1].x = rect.right; + points[1].y = rect.top + yOffset; + points[2].x = rect.right - xOffset; + points[2].y = rect.top; + points[3].x = rect.right - ell_width; + points[3].y = rect.top; /* horizontal line */ - points[4].x = corners[0].x + GDI_ROUND( width ); - points[4].y = corners[0].y; + points[4].x = rect.left + ell_width; + points[4].y = rect.top; /* second curve */ - points[5].x = corners[0].x + GDI_ROUND( width * (1 - factor) ); - points[5].y = corners[0].y; - points[6].x = corners[0].x; - points[6].y = corners[0].y + GDI_ROUND( height * (1 - factor) ); - points[7].x = corners[0].x; - points[7].y = corners[0].y + GDI_ROUND( height ); + points[5].x = rect.left + xOffset; + points[5].y = rect.top; + points[6].x = rect.left; + points[6].y = rect.top + yOffset; + points[7].x = rect.left; + points[7].y = rect.top + ell_height; /* vertical line */ - points[8].x = corners[0].x; - points[8].y = corners[1].y - GDI_ROUND( height ); + points[8].x = rect.left; + points[8].y = rect.bottom - ell_height; /* third curve */ - points[9].x = corners[0].x; - points[9].y = corners[1].y - GDI_ROUND( height * (1 - factor) ); - points[10].x = corners[0].x + GDI_ROUND( width * (1 - factor) ); - points[10].y = corners[1].y; - points[11].x = corners[0].x + GDI_ROUND( width ); - points[11].y = corners[1].y; + points[9].x = rect.left; + points[9].y = rect.bottom - yOffset; + points[10].x = rect.left + xOffset; + points[10].y = rect.bottom; + points[11].x = rect.left + ell_width; + points[11].y = rect.bottom; /* horizontal line */ - points[12].x = corners[1].x - GDI_ROUND( width ); - points[12].y = corners[1].y; + points[12].x = rect.right - ell_width; + points[12].y = rect.bottom; /* fourth curve */ - points[13].x = corners[1].x - GDI_ROUND( width * (1 - factor) ); - points[13].y = corners[1].y; - points[14].x = corners[1].x; - points[14].y = corners[1].y - GDI_ROUND( height * (1 - factor) ); - points[15].x = corners[1].x; - points[15].y = corners[1].y - GDI_ROUND( height ); + points[13].x = rect.right - xOffset; + points[13].y = rect.bottom; + points[14].x = rect.right; + points[14].y = rect.bottom - yOffset; + points[15].x = rect.right; + points[15].y = rect.bottom - ell_height; if (dc->dclevel.flPath & DCPATH_CLOCKWISE) reverse_points( points, 16 ); if (!(type = add_points( pPath, points, 16, PT_BEZIERTO ))) @@ -783,7 +779,6 @@ PATH_RoundRect( * */ BOOL -FASTCALL PATH_Ellipse( PDC dc, INT x1, @@ -791,55 +786,81 @@ PATH_Ellipse( INT x2, INT y2) { - const double factor = 0.55428475; /* 4 / 3 * (sqrt(2) - 1) */ PPATH pPath; - POINT corners[2], points[13]; + POINT points[13]; + RECTL rect; BYTE *type; - double width, height; + LONG xRadius, yRadius, xOffset, yOffset; + POINT left, top, right, bottom; - pPath = PATH_LockPath(dc->dclevel.hPath); - if (!pPath) return FALSE; + TRACE("PATH_Ellipse: %p -> (%d, %d) - (%d, %d)\n", + dc, x1, y1, x2, y2); - if (!PATH_CheckCorners(dc, corners, x1, y1, x2, y2)) + if (!PATH_CheckRect(dc, &rect, x1, y1, x2, y2)) { - PATH_UnlockPath(pPath); return TRUE; } - width = (corners[1].x - corners[0].x) / 2.0; - height = (corners[1].y - corners[0].y) / 2.0; + xRadius = RECTL_lGetWidth(&rect) / 2; + yRadius = RECTL_lGetHeight(&rect) / 2; - /* starting point */ - points[0].x = corners[1].x; - points[0].y = corners[0].y + GDI_ROUND( height ); - /* first curve */ - points[1].x = corners[1].x; - points[1].y = corners[0].y + GDI_ROUND( height * (1 - factor) ); - points[2].x = corners[1].x - GDI_ROUND( width * (1 - factor) ); - points[2].y = corners[0].y; - points[3].x = corners[0].x + GDI_ROUND( width ); - points[3].y = corners[0].y; - /* second curve */ - points[4].x = corners[0].x + GDI_ROUND( width * (1 - factor) ); - points[4].y = corners[0].y; - points[5].x = corners[0].x; - points[5].y = corners[0].y + GDI_ROUND( height * (1 - factor) ); - points[6].x = corners[0].x; - points[6].y = corners[0].y + GDI_ROUND( height ); - /* third curve */ - points[7].x = corners[0].x; - points[7].y = corners[1].y - GDI_ROUND( height * (1 - factor) ); - points[8].x = corners[0].x + GDI_ROUND( width * (1 - factor) ); - points[8].y = corners[1].y; - points[9].x = corners[0].x + GDI_ROUND( width ); - points[9].y = corners[1].y; - /* fourth curve */ - points[10].x = corners[1].x - GDI_ROUND( width * (1 - factor) ); - points[10].y = corners[1].y; - points[11].x = corners[1].x; - points[11].y = corners[1].y - GDI_ROUND( height * (1 - factor) ); - points[12].x = corners[1].x; - points[12].y = corners[1].y - GDI_ROUND( height ); + /* Get the four points which box our ellipse */ + left.x = rect.left; left.y = rect.top + yRadius; + top.x = rect.left + xRadius; top.y = rect.top; + right.x = rect.right; right.y = rect.bottom - yRadius; + bottom.x = rect.right - xRadius; bottom.y = rect.bottom; + + /* + * See here to understand what's happening + * https://stackoverflow.com/questions/1734745/how-to-create-circle-with-b%C3%A9zier-curves + */ + xOffset = EngMulDiv(RECTL_lGetWidth(&rect), 55428475, 200000000); /* w * 0.55428475 / 2 */ + yOffset = EngMulDiv(RECTL_lGetHeight(&rect), 55428475, 200000000); /* h * 0.55428475 / 2 */ + TRACE("xOffset %d, yOffset %d, Rect WxH: %dx%d.\n", + xOffset, yOffset, RECTL_lGetWidth(&rect), RECTL_lGetHeight(&rect)); + + pPath = PATH_LockPath(dc->dclevel.hPath); + if (!pPath) + return FALSE; + + /* Starting point: Right */ + points[0] = right; + + /* first curve - going up, left */ + points[1] = right; + points[1].y -= yOffset; + points[2] = top; + points[2].x += xOffset; + + /* top */ + points[3] = top; + + /* second curve - going left, down*/ + points[4] = top; + points[4].x -= xOffset; + points[5] = left; + points[5].y -= yOffset; + + /* Left */ + points[6] = left; + + /* Third curve - going down, right */ + points[7] = left; + points[7].y += yOffset; + points[8] = bottom; + points[8].x -= xOffset; + + /* bottom */ + points[9] = bottom; + + /* Fourth curve - Going right, up */ + points[10] = bottom; + points[10].x += xOffset; + points[11] = right; + points[11].y += yOffset; + + /* Back to starting point */ + points[12] = right; if (dc->dclevel.flPath & DCPATH_CLOCKWISE) reverse_points( points, 13 ); if (!(type = add_points( pPath, points, 13, PT_BEZIERTO ))) diff --git a/win32ss/gdi/ntgdi/path.h b/win32ss/gdi/ntgdi/path.h index fc8144644a1..038e58195dc 100644 --- a/win32ss/gdi/ntgdi/path.h +++ b/win32ss/gdi/ntgdi/path.h @@ -74,7 +74,7 @@ typedef struct _EPATHOBJ #define PATH_IsPathOpen(dclevel) ( ((dclevel).hPath) && ((dclevel).flPath & DCPATH_ACTIVE) ) BOOL FASTCALL PATH_Arc (PDC dc, INT x1, INT y1, INT x2, INT y2, INT xStart, INT yStart, INT xEnd, INT yEnd, INT direction, INT lines); -BOOL FASTCALL PATH_Ellipse (PDC dc, INT x1, INT y1, INT x2, INT y2); +BOOL PATH_Ellipse (PDC dc, INT x1, INT y1, INT x2, INT y2); VOID FASTCALL PATH_EmptyPath (PPATH pPath); BOOL FASTCALL PATH_LineTo (PDC dc, INT x, INT y); BOOL FASTCALL PATH_PolyBezier (PDC dc, const POINT *pts, DWORD cbPoints); @@ -84,7 +84,7 @@ BOOL FASTCALL PATH_PolylineTo (PDC dc, const POINT *pts, DWORD cbPoints); BOOL FASTCALL PATH_PolyPolygon ( PDC dc, const POINT* pts, const INT* counts, UINT polygons); BOOL FASTCALL PATH_PolyPolyline( PDC dc, const POINT* pts, const DWORD* counts, DWORD polylines); BOOL FASTCALL PATH_Rectangle (PDC dc, INT x1, INT y1, INT x2, INT y2); -BOOL FASTCALL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height); +BOOL PATH_RoundRect(DC *dc, INT x1, INT y1, INT x2, INT y2, INT ell_width, INT ell_height); BOOL FASTCALL PATH_PathToRegion (PPATH pPath, INT nPolyFillMode, PREGION Rgn); BOOL FASTCALL PATH_ExtTextOut(PDC dc,INT x,INT y,UINT flags,const RECTL *lprc,LPCWSTR str,UINT count,const INT *dx); @@ -96,7 +96,6 @@ PPATH FASTCALL PATH_FlattenPath (PPATH pPath); BOOL FASTCALL PATH_ReserveEntries (PPATH pPath, INT numEntries); BOOL FASTCALL PATH_StrokePath(DC *dc, PPATH pPath); -BOOL PATH_CheckCorners(DC *dc, POINT corners[], INT x1, INT y1, INT x2, INT y2); VOID FASTCALL IntGdiCloseFigure(PPATH pPath); BOOL FASTCALL PATH_Delete(HPATH hPath);