https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6358c4ac9f1b3fe0997cb…
commit 6358c4ac9f1b3fe0997cb39b4603d9afcc12a079
Author: Katayama Hirofumi MZ <katayama.hirofumi.mz(a)gmail.com>
AuthorDate: Mon Dec 6 20:44:06 2021 +0900
Commit: GitHub <noreply(a)github.com>
CommitDate: Mon Dec 6 20:44:06 2021 +0900
[NTGDI] Support the wide pen (#4137)
- Extend PATH_WidenPath function as PATH_WidenPathEx with the path argument.
- Use PATH_WidenPathEx and PATH_FillPathEx functions to implement wide pen drawing in
PATH_StrokePath function.
- Add the code to IntGdiLineTo, IntRectangle, IntGdiPolygon, and IntGdiPolyline in
order to stroke the path when the effective wide pen.
FIXME: Boundary rectangle.
CORE-2527, CORE-8366
---
win32ss/gdi/ntgdi/fillshap.c | 185 ++++++++++++++++++++++++++++++-------------
win32ss/gdi/ntgdi/line.c | 106 +++++++++++++++++++++----
win32ss/gdi/ntgdi/path.c | 51 ++++++++----
win32ss/gdi/ntgdi/path.h | 5 +-
win32ss/gdi/ntgdi/pen.h | 6 ++
5 files changed, 263 insertions(+), 90 deletions(-)
diff --git a/win32ss/gdi/ntgdi/fillshap.c b/win32ss/gdi/ntgdi/fillshap.c
index c18ff0093cc..f0d08d8505b 100644
--- a/win32ss/gdi/ntgdi/fillshap.c
+++ b/win32ss/gdi/ntgdi/fillshap.c
@@ -23,9 +23,10 @@ IntGdiPolygon(PDC dc,
PBRUSH pbrLine, pbrFill;
BOOL ret = FALSE; // Default to failure
RECTL DestRect;
- int CurrentPoint;
+ INT i, CurrentPoint;
PDC_ATTR pdcattr;
POINTL BrushOrigin;
+ PPATH pPath;
// int Left;
// int Top;
@@ -105,38 +106,72 @@ IntGdiPolygon(PDC dc,
// Draw the Polygon Edges with the current pen ( if not a NULL pen )
if (!(pbrLine->flAttrs & BR_IS_NULL))
{
- int i;
-
- for (i = 0; i < Count-1; i++)
+ if (IntIsEffectiveWidePen(pbrLine))
{
-
+ /* Clear the path */
+ PATH_Delete(dc->dclevel.hPath);
+ dc->dclevel.hPath = NULL;
+
+ /* Begin a path */
+ pPath = PATH_CreatePath(Count + 1);
+ dc->dclevel.flPath |= DCPATH_ACTIVE;
+ dc->dclevel.hPath = pPath->BaseObject.hHmgr;
+ pPath->pos = Points[0];
+ IntLPtoDP(dc, &pPath->pos, 1);
+
+ PATH_MoveTo(dc, pPath);
+ for (i = 1; i < Count; ++i)
+ {
+ PATH_LineTo(dc, Points[i].x, Points[i].y);
+ }
+ PATH_LineTo(dc, Points[0].x, Points[0].y);
+
+ /* Close the path */
+ pPath->state = PATH_Closed;
+ dc->dclevel.flPath &= ~DCPATH_ACTIVE;
+
+ /* Actually stroke a path */
+ ret = PATH_StrokePath(dc, pPath);
+
+ /* Clear the path */
+ PATH_UnlockPath(pPath);
+ PATH_Delete(dc->dclevel.hPath);
+ dc->dclevel.hPath = NULL;
+
+ /* FIXME: Boundary */
+ }
+ else
+ {
+ for (i = 0; i < Count-1; i++)
+ {
// DPRINT1("Polygon Making line from (%d,%d) to (%d,%d)\n",
// Points[0].x, Points[0].y,
// Points[1].x, Points[1].y );
- ret = IntEngLineTo(&psurf->SurfObj,
- (CLIPOBJ *)&dc->co,
- &dc->eboLine.BrushObject,
- Points[i].x, /* From */
- Points[i].y,
- Points[i+1].x, /* To */
- Points[i+1].y,
- &DestRect,
- ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */
- if (!ret) break;
- }
- /* Close the polygon */
- if (ret)
- {
- ret = IntEngLineTo(&psurf->SurfObj,
- (CLIPOBJ *)&dc->co,
- &dc->eboLine.BrushObject,
- Points[Count-1].x, /* From */
- Points[Count-1].y,
- Points[0].x, /* To */
- Points[0].y,
- &DestRect,
- ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */
+ ret = IntEngLineTo(&psurf->SurfObj,
+ (CLIPOBJ *)&dc->co,
+ &dc->eboLine.BrushObject,
+ Points[i].x, /* From */
+ Points[i].y,
+ Points[i+1].x, /* To */
+ Points[i+1].y,
+ &DestRect,
+ ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */
+ if (!ret) break;
+ }
+ /* Close the polygon */
+ if (ret)
+ {
+ ret = IntEngLineTo(&psurf->SurfObj,
+ (CLIPOBJ *)&dc->co,
+ &dc->eboLine.BrushObject,
+ Points[Count-1].x, /* From */
+ Points[Count-1].y,
+ Points[0].x, /* To */
+ Points[0].y,
+ &DestRect,
+ ROP2_TO_MIX(pdcattr->jROP2)); /* MIX */
+ }
}
}
}
@@ -542,6 +577,7 @@ IntRectangle(PDC dc,
MIX Mix;
PDC_ATTR pdcattr;
POINTL BrushOrigin;
+ PPATH pPath;
ASSERT ( dc ); // Caller's responsibility to set this up
@@ -628,34 +664,71 @@ IntRectangle(PDC dc,
if (!(pbrLine->flAttrs & BR_IS_NULL))
{
- Mix = ROP2_TO_MIX(pdcattr->jROP2);
- ret = ret && IntEngLineTo(&psurf->SurfObj,
- (CLIPOBJ *)&dc->co,
- &dc->eboLine.BrushObject,
- DestRect.left, DestRect.top, DestRect.right,
DestRect.top,
- &DestRect, // Bounding rectangle
- Mix);
-
- ret = ret && IntEngLineTo(&psurf->SurfObj,
- (CLIPOBJ *)&dc->co,
- &dc->eboLine.BrushObject,
- DestRect.right, DestRect.top, DestRect.right,
DestRect.bottom,
- &DestRect, // Bounding rectangle
- Mix);
-
- ret = ret && IntEngLineTo(&psurf->SurfObj,
- (CLIPOBJ *)&dc->co,
- &dc->eboLine.BrushObject,
- DestRect.right, DestRect.bottom, DestRect.left,
DestRect.bottom,
- &DestRect, // Bounding rectangle
- Mix);
-
- ret = ret && IntEngLineTo(&psurf->SurfObj,
- (CLIPOBJ *)&dc->co,
- &dc->eboLine.BrushObject,
- DestRect.left, DestRect.bottom, DestRect.left,
DestRect.top,
- &DestRect, // Bounding rectangle
- Mix);
+ if (IntIsEffectiveWidePen(pbrLine))
+ {
+ /* Clear the path */
+ PATH_Delete(dc->dclevel.hPath);
+ dc->dclevel.hPath = NULL;
+
+ /* Begin a path */
+ pPath = PATH_CreatePath(5);
+ dc->dclevel.flPath |= DCPATH_ACTIVE;
+ dc->dclevel.hPath = pPath->BaseObject.hHmgr;
+ pPath->pos.x = LeftRect;
+ pPath->pos.y = TopRect;
+ IntLPtoDP(dc, &pPath->pos, 1);
+
+ PATH_MoveTo(dc, pPath);
+ PATH_LineTo(dc, RightRect, TopRect);
+ PATH_LineTo(dc, RightRect, BottomRect);
+ PATH_LineTo(dc, LeftRect, BottomRect);
+ PATH_LineTo(dc, LeftRect, TopRect);
+
+ /* Close the path */
+ pPath->state = PATH_Closed;
+ dc->dclevel.flPath &= ~DCPATH_ACTIVE;
+
+ /* Actually stroke a path */
+ ret = PATH_StrokePath(dc, pPath);
+
+ /* Clear the path */
+ PATH_UnlockPath(pPath);
+ PATH_Delete(dc->dclevel.hPath);
+ dc->dclevel.hPath = NULL;
+
+ /* FIXME: Boundary */
+ }
+ else
+ {
+ Mix = ROP2_TO_MIX(pdcattr->jROP2);
+ ret = ret && IntEngLineTo(&psurf->SurfObj,
+ (CLIPOBJ *)&dc->co,
+ &dc->eboLine.BrushObject,
+ DestRect.left, DestRect.top, DestRect.right,
DestRect.top,
+ &DestRect, // Bounding rectangle
+ Mix);
+
+ ret = ret && IntEngLineTo(&psurf->SurfObj,
+ (CLIPOBJ *)&dc->co,
+ &dc->eboLine.BrushObject,
+ DestRect.right, DestRect.top, DestRect.right,
DestRect.bottom,
+ &DestRect, // Bounding rectangle
+ Mix);
+
+ ret = ret && IntEngLineTo(&psurf->SurfObj,
+ (CLIPOBJ *)&dc->co,
+ &dc->eboLine.BrushObject,
+ DestRect.right, DestRect.bottom, DestRect.left,
DestRect.bottom,
+ &DestRect, // Bounding rectangle
+ Mix);
+
+ ret = ret && IntEngLineTo(&psurf->SurfObj,
+ (CLIPOBJ *)&dc->co,
+ &dc->eboLine.BrushObject,
+ DestRect.left, DestRect.bottom, DestRect.left,
DestRect.top,
+ &DestRect, // Bounding rectangle
+ Mix);
+ }
}
cleanup:
diff --git a/win32ss/gdi/ntgdi/line.c b/win32ss/gdi/ntgdi/line.c
index aeebebc58a1..c61f62db7a0 100644
--- a/win32ss/gdi/ntgdi/line.c
+++ b/win32ss/gdi/ntgdi/line.c
@@ -31,7 +31,7 @@ AddPenLinesBounds(PDC dc, int count, POINT *points)
bounds.left = bounds.top = INT_MAX;
bounds.right = bounds.bottom = INT_MIN;
- if (((pbrLine->ulPenStyle & PS_TYPE_MASK) & PS_GEOMETRIC) ||
(pbrLine->lWidth > 1))
+ if (IntIsEffectiveWidePen(pbrLine))
{
/* Windows uses some heuristics to estimate the distance from the point that will
be painted */
lWidth = pbrLine->lWidth + 2;
@@ -152,9 +152,13 @@ IntGdiLineTo(DC *dc,
PBRUSH pbrLine;
RECTL Bounds;
POINT Points[2];
- PDC_ATTR pdcattr = dc->pdcattr;
+ PDC_ATTR pdcattr;
+ PPATH pPath;
+
ASSERT_DC_PREPARED(dc);
+ pdcattr = dc->pdcattr;
+
if (PATH_IsPathOpen(dc->dclevel))
{
Ret = PATH_LineTo(dc, XEnd, YEnd);
@@ -199,15 +203,47 @@ IntGdiLineTo(DC *dc,
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 (IntIsEffectiveWidePen(pbrLine))
+ {
+ /* Clear the path */
+ PATH_Delete(dc->dclevel.hPath);
+ dc->dclevel.hPath = NULL;
+
+ /* Begin a path */
+ pPath = PATH_CreatePath(2);
+ dc->dclevel.flPath |= DCPATH_ACTIVE;
+ dc->dclevel.hPath = pPath->BaseObject.hHmgr;
+ IntGetCurrentPositionEx(dc, &pPath->pos);
+ IntLPtoDP(dc, &pPath->pos, 1);
+
+ PATH_MoveTo(dc, pPath);
+ PATH_LineTo(dc, XEnd, YEnd);
+
+ /* Close the path */
+ pPath->state = PATH_Closed;
+ dc->dclevel.flPath &= ~DCPATH_ACTIVE;
+
+ /* Actually stroke a path */
+ Ret = PATH_StrokePath(dc, pPath);
+ /* Clear the path */
+ PATH_UnlockPath(pPath);
+ PATH_Delete(dc->dclevel.hPath);
+ dc->dclevel.hPath = NULL;
+
+ /* FIXME: Boundary */
+ }
+ else
+ {
+ 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)
@@ -298,6 +334,7 @@ IntGdiPolyline(DC *dc,
BOOL Ret = TRUE;
LONG i;
PDC_ATTR pdcattr = dc->pdcattr;
+ PPATH pPath;
if (!dc->dclevel.pSurface)
{
@@ -331,13 +368,48 @@ IntGdiPolyline(DC *dc,
AddPenLinesBounds(dc, Count, Points);
}
- Ret = IntEngPolyline(&psurf->SurfObj,
- (CLIPOBJ *)&dc->co,
- &dc->eboLine.BrushObject,
- Points,
- Count,
- ROP2_TO_MIX(pdcattr->jROP2));
-
+ if (IntIsEffectiveWidePen(pbrLine))
+ {
+ /* Clear the path */
+ PATH_Delete(dc->dclevel.hPath);
+ dc->dclevel.hPath = NULL;
+
+ /* Begin a path */
+ pPath = PATH_CreatePath(Count);
+ dc->dclevel.flPath |= DCPATH_ACTIVE;
+ dc->dclevel.hPath = pPath->BaseObject.hHmgr;
+ pPath->pos = pt[0];
+ IntLPtoDP(dc, &pPath->pos, 1);
+
+ PATH_MoveTo(dc, pPath);
+ for (i = 1; i < Count; ++i)
+ {
+ PATH_LineTo(dc, pt[i].x, pt[i].y);
+ }
+
+ /* Close the path */
+ pPath->state = PATH_Closed;
+ dc->dclevel.flPath &= ~DCPATH_ACTIVE;
+
+ /* Actually stroke a path */
+ Ret = PATH_StrokePath(dc, pPath);
+
+ /* Clear the path */
+ PATH_UnlockPath(pPath);
+ PATH_Delete(dc->dclevel.hPath);
+ dc->dclevel.hPath = NULL;
+
+ /* FIXME: Boundary */
+ }
+ else
+ {
+ Ret = IntEngPolyline(&psurf->SurfObj,
+ (CLIPOBJ *)&dc->co,
+ &dc->eboLine.BrushObject,
+ Points,
+ Count,
+ ROP2_TO_MIX(pdcattr->jROP2));
+ }
EngFreeMem(Points);
}
else
diff --git a/win32ss/gdi/ntgdi/path.c b/win32ss/gdi/ntgdi/path.c
index 4343d553e0e..37b82ad5a7d 100644
--- a/win32ss/gdi/ntgdi/path.c
+++ b/win32ss/gdi/ntgdi/path.c
@@ -1600,17 +1600,35 @@ PATH_StrokePath(
PPATH pPath)
{
BOOL ret = FALSE;
- INT i = 0;
- INT nLinePts, nAlloc;
+ INT nLinePts, nAlloc, jOldFillMode, i = 0;
POINT *pLinePts = NULL;
POINT ptViewportOrg, ptWindowOrg;
SIZE szViewportExt, szWindowExt;
DWORD mapMode, graphicsMode;
XFORM xform;
PDC_ATTR pdcattr = dc->pdcattr;
+ PBRUSH pbrLine;
+ PPATH pNewPath;
TRACE("Enter %s\n", __FUNCTION__);
+ pbrLine = dc->dclevel.pbrLine;
+ if (IntIsEffectiveWidePen(pbrLine))
+ {
+ pNewPath = PATH_WidenPathEx(dc, pPath);
+ if (pNewPath)
+ {
+ /* Fill the path with the WINDING fill mode */
+ jOldFillMode = pdcattr->jFillMode;
+ pdcattr->jFillMode = WINDING;
+ PATH_FillPathEx(dc, pNewPath, pbrLine);
+ pdcattr->jFillMode = jOldFillMode;
+
+ PATH_Delete(pNewPath->BaseObject.hHmgr);
+ return TRUE;
+ }
+ }
+
/* Save the mapping mode info */
mapMode = pdcattr->iMapMode;
@@ -2100,12 +2118,7 @@ PPATH
FASTCALL
PATH_WidenPath(DC *dc)
{
- INT size;
- UINT penWidth, penStyle;
- DWORD obj_type;
PPATH pPath, pNewPath;
- LPEXTLOGPEN elp;
- PDC_ATTR pdcattr = dc->pdcattr;
pPath = PATH_LockPath(dc->dclevel.hPath);
if (!pPath)
@@ -2114,10 +2127,24 @@ PATH_WidenPath(DC *dc)
return NULL;
}
+ pNewPath = PATH_WidenPathEx(dc, pPath);
+ PATH_UnlockPath(pPath);
+ return pNewPath;
+}
+
+PPATH
+FASTCALL
+PATH_WidenPathEx(DC *dc, PPATH pPath)
+{
+ INT size;
+ UINT penWidth, penStyle;
+ DWORD obj_type;
+ LPEXTLOGPEN elp;
+ PDC_ATTR pdcattr = dc->pdcattr;
+
if (pPath->state != PATH_Closed)
{
TRACE("PWP 1\n");
- PATH_UnlockPath(pPath);
EngSetLastError(ERROR_CAN_NOT_COMPLETE);
return NULL;
}
@@ -2126,7 +2153,6 @@ PATH_WidenPath(DC *dc)
if (!size)
{
TRACE("PWP 2\n");
- PATH_UnlockPath(pPath);
EngSetLastError(ERROR_CAN_NOT_COMPLETE);
return NULL;
}
@@ -2135,7 +2161,6 @@ PATH_WidenPath(DC *dc)
if (elp == NULL)
{
TRACE("PWP 3\n");
- PATH_UnlockPath(pPath);
EngSetLastError(ERROR_OUTOFMEMORY);
return NULL;
}
@@ -2156,7 +2181,6 @@ PATH_WidenPath(DC *dc)
TRACE("PWP 4\n");
EngSetLastError(ERROR_CAN_NOT_COMPLETE);
ExFreePoolWithTag(elp, TAG_PATH);
- PATH_UnlockPath(pPath);
return NULL;
}
@@ -2168,14 +2192,11 @@ PATH_WidenPath(DC *dc)
(PS_TYPE_MASK & penStyle) == PS_COSMETIC)
{
TRACE("PWP 5\n");
- PATH_UnlockPath(pPath);
EngSetLastError(ERROR_CAN_NOT_COMPLETE);
return FALSE;
}
- pNewPath = IntGdiWidenPath(pPath, penWidth, penStyle,
dc->dclevel.laPath.eMiterLimit);
- PATH_UnlockPath(pPath);
- return pNewPath;
+ return IntGdiWidenPath(pPath, penWidth, penStyle,
dc->dclevel.laPath.eMiterLimit);
}
static inline INT int_from_fixed(FIXED f)
diff --git a/win32ss/gdi/ntgdi/path.h b/win32ss/gdi/ntgdi/path.h
index 038e58195dc..c5028caa8e4 100644
--- a/win32ss/gdi/ntgdi/path.h
+++ b/win32ss/gdi/ntgdi/path.h
@@ -69,14 +69,14 @@ typedef struct _EPATHOBJ
#define PATH_AllocPathWithHandle() ((PPATH) GDIOBJ_AllocObjWithHandle
(GDI_OBJECT_TYPE_PATH, sizeof(PATH)))
#define PATH_LockPath(hPath) ((PPATH)GDIOBJ_ShareLockObj((HGDIOBJ)hPath,
GDI_OBJECT_TYPE_PATH))
#define PATH_UnlockPath(pPath) GDIOBJ_vDereferenceObject((POBJ)pPath)
-
-
#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 PATH_Ellipse (PDC dc, INT x1, INT y1, INT x2, INT y2);
+PPATH FASTCALL PATH_CreatePath(int count);
VOID FASTCALL PATH_EmptyPath (PPATH pPath);
BOOL FASTCALL PATH_LineTo (PDC dc, INT x, INT y);
+BOOL FASTCALL PATH_MoveTo(PDC dc, PPATH pPath);
BOOL FASTCALL PATH_PolyBezier (PDC dc, const POINT *pts, DWORD cbPoints);
BOOL FASTCALL PATH_PolyBezierTo (PDC dc, const POINT *pts, DWORD cbPoints);
BOOL FASTCALL PATH_PolyDraw(PDC dc, const POINT *pts, const BYTE *types, DWORD
cbPoints);
@@ -93,6 +93,7 @@ BOOL FASTCALL PATH_AddFlatBezier (PPATH pPath, POINT *pt, BOOL closed);
BOOL FASTCALL PATH_FillPath( PDC dc, PPATH pPath );
BOOL FASTCALL PATH_FillPathEx(PDC dc, PPATH pPath, PBRUSH pbrFill);
PPATH FASTCALL PATH_FlattenPath (PPATH pPath);
+PPATH FASTCALL PATH_WidenPathEx(DC *dc, PPATH pPath);
BOOL FASTCALL PATH_ReserveEntries (PPATH pPath, INT numEntries);
BOOL FASTCALL PATH_StrokePath(DC *dc, PPATH pPath);
diff --git a/win32ss/gdi/ntgdi/pen.h b/win32ss/gdi/ntgdi/pen.h
index ea995c532a0..7a0793fc4c7 100644
--- a/win32ss/gdi/ntgdi/pen.h
+++ b/win32ss/gdi/ntgdi/pen.h
@@ -29,3 +29,9 @@ PEN_GetObject(
_Out_ PLOGPEN Buffer);
VOID FASTCALL AddPenLinesBounds(PDC,int,POINT *);
+
+#define IntIsEffectiveWidePen(pbrLine) ( \
+ (pbrLine)->lWidth > 1 && \
+ ((pbrLine->flAttrs & BR_IS_OLDSTYLEPEN) || \
+ ((pbrLine)->ulPenStyle & PS_TYPE_MASK) == PS_GEOMETRIC) \
+)