From 6358c4ac9f1b3fe0997cb39b4603d9afcc12a079 Mon Sep 17 00:00:00 2001 From: Katayama Hirofumi MZ Date: Mon, 6 Dec 2021 20:44:06 +0900 Subject: [PATCH] [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 | 177 +++++++++++++++++++++++++---------- win32ss/gdi/ntgdi/line.c | 104 ++++++++++++++++---- win32ss/gdi/ntgdi/path.c | 51 +++++++--- win32ss/gdi/ntgdi/path.h | 5 +- win32ss/gdi/ntgdi/pen.h | 6 ++ 5 files changed, 258 insertions(+), 85 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); + if (IntIsEffectiveWidePen(pbrLine)) + { + /* Clear the path */ + PATH_Delete(dc->dclevel.hPath); + dc->dclevel.hPath = NULL; - ret = ret && IntEngLineTo(&psurf->SurfObj, - (CLIPOBJ *)&dc->co, - &dc->eboLine.BrushObject, - DestRect.right, DestRect.top, DestRect.right, DestRect.bottom, - &DestRect, // Bounding rectangle - Mix); + /* 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); - ret = ret && IntEngLineTo(&psurf->SurfObj, - (CLIPOBJ *)&dc->co, - &dc->eboLine.BrushObject, - DestRect.right, DestRect.bottom, DestRect.left, DestRect.bottom, - &DestRect, // Bounding rectangle - Mix); + PATH_MoveTo(dc, pPath); + PATH_LineTo(dc, RightRect, TopRect); + PATH_LineTo(dc, RightRect, BottomRect); + PATH_LineTo(dc, LeftRect, BottomRect); + PATH_LineTo(dc, LeftRect, TopRect); - ret = ret && IntEngLineTo(&psurf->SurfObj, - (CLIPOBJ *)&dc->co, - &dc->eboLine.BrushObject, - DestRect.left, DestRect.bottom, DestRect.left, DestRect.top, - &DestRect, // Bounding rectangle - Mix); + /* 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) \ +)