https://git.reactos.org/?p=reactos.git;a=commitdiff;h=6358c4ac9f1b3fe0997cb39b4603d9afcc12a079

commit 6358c4ac9f1b3fe0997cb39b4603d9afcc12a079
Author:     Katayama Hirofumi MZ <[email protected]>
AuthorDate: Mon Dec 6 20:44:06 2021 +0900
Commit:     GitHub <[email protected]>
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) \
+)

Reply via email to