Module: wine Branch: master Commit: b7caffea25b4a066301dbd4007c3f4e92e2f3fab URL: https://gitlab.winehq.org/wine/wine/-/commit/b7caffea25b4a066301dbd4007c3f4e...
Author: Esme Povirk esme@codeweavers.com Date: Sat May 4 18:27:46 2024 +0000
gdiplus: Support anchors on thin paths.
---
dlls/gdiplus/gdiplus_private.h | 2 + dlls/gdiplus/graphics.c | 80 ++++++++++++++++++++++++++++++++++++- dlls/gdiplus/graphicspath.c | 91 +++++++++++++++++++++++++++++++----------- 3 files changed, 148 insertions(+), 25 deletions(-)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index c3b516a9a2b..c327d44af66 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -137,6 +137,8 @@ extern void free_installed_fonts(void);
extern BOOL lengthen_path(GpPath *path, INT len);
+extern GpStatus widen_flat_path_anchors(GpPath *flat_path, GpPen *pen, REAL pen_width, GpPath **anchors); + extern DWORD write_region_data(const GpRegion *region, void *data); extern DWORD write_path_data(GpPath *path, void *data);
diff --git a/dlls/gdiplus/graphics.c b/dlls/gdiplus/graphics.c index 86c156354ef..7eea3f58c77 100644 --- a/dlls/gdiplus/graphics.c +++ b/dlls/gdiplus/graphics.c @@ -3737,7 +3737,8 @@ end: static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPath *path) { GpStatus stat; - GpPath* flat_path; + GpPath *flat_path, *anchor_path; + GpRegion *anchor_region; GpMatrix* transform; GpRectF gp_bound_rect; GpRect gp_output_area; @@ -3765,6 +3766,9 @@ static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPa if (stat == Ok) stat = GdipFlattenPath(flat_path, transform, 1.0);
+ if (stat == Ok) + stat = widen_flat_path_anchors(flat_path, pen, 1.0, &anchor_path); + GdipDeleteMatrix(transform); }
@@ -3788,6 +3792,18 @@ static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPa if (ceilf(y) > output_area.bottom) output_area.bottom = ceilf(y); }
+ for (i=0; i<anchor_path->pathdata.Count; i++) + { + REAL x, y; + x = anchor_path->pathdata.Points[i].X; + y = anchor_path->pathdata.Points[i].Y; + + if (floorf(x) < output_area.left) output_area.left = floorf(x); + if (floorf(y) < output_area.top) output_area.top = floorf(y); + if (ceilf(x) > output_area.right) output_area.right = ceilf(x); + if (ceilf(y) > output_area.bottom) output_area.bottom = ceilf(y); + } + stat = get_graphics_device_bounds(graphics, &gp_bound_rect); }
@@ -3804,6 +3820,7 @@ static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPa if (output_width <= 0 || output_height <= 0) { GdipDeletePath(flat_path); + GdipDeletePath(anchor_path); return Ok; }
@@ -4015,6 +4032,66 @@ static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPa } } } + + /* draw anchors */ + stat = GdipCreateRegionPath(anchor_path, &anchor_region); + if (stat == Ok) + { + HRGN hrgn; + DWORD rgn_data_size; + RGNDATA *rgn_data; + RECT *rects; + INT x, y; + + stat = GdipCombineRegionRectI(anchor_region, &gp_output_area, CombineModeIntersect); + + if (stat == Ok) + stat = GdipGetRegionHRgn(anchor_region, NULL, &hrgn); + + if (stat == Ok) + { + rgn_data_size = GetRegionData(hrgn, 0, NULL); + + if (rgn_data_size) + { + rgn_data = malloc(rgn_data_size); + + if (rgn_data) + { + GetRegionData(hrgn, rgn_data_size, rgn_data); + + rects = (RECT*)&rgn_data->Buffer; + + for (i=0; i < rgn_data->rdh.nCount; i++) + { + RECT rc; + rc = rects[i]; + + OffsetRect(&rc, -output_area.left, -output_area.top); + + for (y = rc.top; y < rc.bottom; y++) + { + for (x = rc.left; x < rc.right; x++) + { + if (brush_bits) + output_bits[x + y*output_width] = brush_bits[x + y*output_width]; + else + output_bits[x + y*output_width] = ((GpSolidFill*)pen->brush)->color; + } + } + } + + free(rgn_data); + } + else + stat = OutOfMemory; + } + + DeleteObject(hrgn); + } + + GdipDeleteRegion(anchor_region); + } }
/* draw output image */ @@ -4035,6 +4112,7 @@ static GpStatus SOFTWARE_GdipDrawThinPath(GpGraphics *graphics, GpPen *pen, GpPa }
GdipDeletePath(flat_path); + GdipDeletePath(anchor_path);
return stat; } diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index 662e20071aa..105df4cacfd 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -2111,9 +2111,8 @@ static void widen_closed_figure(const GpPointF *points, int start, int end, GpPen *pen, REAL pen_width, path_list_node_t **last_point);
static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, - GpPen *pen, GpLineCap cap, GpCustomLineCap *custom, path_list_node_t **last_point) + GpPen *pen, REAL pen_width, GpLineCap cap, GpCustomLineCap *custom, path_list_node_t **last_point) { - REAL pen_width = max(pen->width, 2.0); switch (cap) { default: @@ -2520,6 +2519,71 @@ static void widen_dashed_figure(GpPath *path, int start, int end, int closed, free(tmp_points); }
+void widen_anchors(GpPath *flat_path, GpPen *pen, REAL pen_width, path_list_node_t** last_point) +{ + BYTE *types = flat_path->pathdata.Types; + int i, subpath_start=0; + + for (i=0; i < flat_path->pathdata.Count; i++) + { + if ((types[i]&PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath) + continue; + + if ((types[i]&PathPointTypePathTypeMask) == PathPointTypeStart) + subpath_start = i; + + if (i == flat_path->pathdata.Count-1 || + (types[i+1]&PathPointTypePathTypeMask) == PathPointTypeStart) + { + if (pen->startcap & LineCapAnchorMask) + add_anchor(&flat_path->pathdata.Points[subpath_start], + &flat_path->pathdata.Points[subpath_start+1], + pen, pen_width, pen->startcap, pen->customstart, last_point); + + if (pen->endcap & LineCapAnchorMask) + add_anchor(&flat_path->pathdata.Points[i], + &flat_path->pathdata.Points[i-1], + pen, pen_width, pen->endcap, pen->customend, last_point); + } + } +} + +GpStatus widen_flat_path_anchors(GpPath *flat_path, GpPen *pen, REAL pen_width, GpPath **anchors) +{ + GpStatus stat; + path_list_node_t *points=NULL, *last_point=NULL; + + if (!flat_path || !pen) + return InvalidParameter; + + if (init_path_list(&points, 314.0, 22.0)) + { + last_point = points; + + stat = GdipCreatePath(flat_path->fill, anchors); + if (stat == Ok) + { + widen_anchors(flat_path, pen, pen_width, &last_point); + + if (!path_list_to_path(points->next, *anchors)) + stat = OutOfMemory; + + if (stat != Ok) + { + GdipDeletePath(*anchors); + *anchors = NULL; + } + } + free_path_list(points); + } + else + stat = OutOfMemory; + + /* FIXME: Apply insets to flat_path */ + + return stat; +} + GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix, REAL flatness) { @@ -2586,28 +2650,7 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix, } }
- for (i=0; i < flat_path->pathdata.Count; i++) - { - if ((types[i]&PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath) - continue; - - if ((types[i]&PathPointTypePathTypeMask) == PathPointTypeStart) - subpath_start = i; - - if (i == flat_path->pathdata.Count-1 || - (types[i+1]&PathPointTypePathTypeMask) == PathPointTypeStart) - { - if (pen->startcap & LineCapAnchorMask) - add_anchor(&flat_path->pathdata.Points[subpath_start], - &flat_path->pathdata.Points[subpath_start+1], - pen, pen->startcap, pen->customstart, &last_point); - - if (pen->endcap & LineCapAnchorMask) - add_anchor(&flat_path->pathdata.Points[i], - &flat_path->pathdata.Points[i-1], - pen, pen->endcap, pen->customend, &last_point); - } - } + widen_anchors(flat_path, pen, fmax(pen->width, 2.0), &last_point);
if (!path_list_to_path(points->next, path)) status = OutOfMemory;