https://git.reactos.org/?p=reactos.git;a=commitdiff;h=26b5596a111c60b3675df…
commit 26b5596a111c60b3675df11ba7a03729c42a60c3
Author: Jérôme Gardou <jerome.gardou(a)reactos.org>
AuthorDate: Wed Mar 31 16:17:02 2021 +0200
Commit: Jérôme Gardou <zefklop(a)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%…
+ */
+ 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%…
+ */
+ 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);