Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45273
-- v9: gdiplus: Add GdipSetCustomLineCapStrokeCaps implementation and usage.
From: Bartosz Kosiorek gang65@poczta.onet.pl
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45273 --- dlls/gdiplus/customlinecap.c | 17 ++++++++--------- dlls/gdiplus/gdiplus_private.h | 2 +- dlls/gdiplus/tests/customlinecap.c | 5 +++-- 3 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/dlls/gdiplus/customlinecap.c b/dlls/gdiplus/customlinecap.c index c74928eeda6..2e7b000355e 100644 --- a/dlls/gdiplus/customlinecap.c +++ b/dlls/gdiplus/customlinecap.c @@ -96,7 +96,7 @@ static GpStatus init_custom_linecap(GpCustomLineCap *cap, GpPathData *pathdata, cap->pathdata.Count = pathdata->Count;
cap->inset = base_inset; - cap->cap = basecap; + cap->basecap = basecap; cap->join = LineJoinMiter; cap->scale = 1.0;
@@ -193,16 +193,15 @@ GpStatus WINGDIPAPI GdipSetCustomLineCapStrokeCaps(GpCustomLineCap* custom, }
GpStatus WINGDIPAPI GdipSetCustomLineCapBaseCap(GpCustomLineCap* custom, - GpLineCap base) + GpLineCap basecap) { - static int calls; + TRACE("(%p,%u)\n", custom, basecap); + if(!custom || basecap > LineCapTriangle) + return InvalidParameter;
- TRACE("(%p,%u)\n", custom, base); + custom->basecap = basecap;
- if(!(calls++)) - FIXME("not implemented\n"); - - return NotImplemented; + return Ok; }
GpStatus WINGDIPAPI GdipGetCustomLineCapBaseInset(GpCustomLineCap* custom, @@ -264,7 +263,7 @@ GpStatus WINGDIPAPI GdipGetCustomLineCapBaseCap(GpCustomLineCap *customCap, GpLi if(!customCap || !baseCap) return InvalidParameter;
- *baseCap = customCap->cap; + *baseCap = customCap->basecap;
return Ok; } diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 0c55af6614a..77b35659946 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -351,7 +351,7 @@ struct GpCustomLineCap{ CustomLineCapType type; GpPathData pathdata; BOOL fill; /* TRUE for fill, FALSE for stroke */ - GpLineCap cap; /* as far as I can tell, this value is ignored */ + GpLineCap basecap; /* cap used together with customLineCap */ REAL inset; /* how much to adjust the end of the line */ GpLineJoin join; REAL scale; diff --git a/dlls/gdiplus/tests/customlinecap.c b/dlls/gdiplus/tests/customlinecap.c index 26175ca8f66..c475216ff21 100644 --- a/dlls/gdiplus/tests/customlinecap.c +++ b/dlls/gdiplus/tests/customlinecap.c @@ -283,14 +283,15 @@ static void test_create_adjustable_cap(void) ok(base == LineCapTriangle, "Unexpected base cap %d\n", base);
stat = GdipSetCustomLineCapBaseCap((GpCustomLineCap*)cap, LineCapSquare); - todo_wine ok(stat == Ok, "Unexpected return code, %d\n", stat);
stat = GdipGetCustomLineCapBaseCap((GpCustomLineCap*)cap, &base); ok(stat == Ok, "Unexpected return code, %d\n", stat); - todo_wine ok(base == LineCapSquare, "Unexpected base cap %d\n", base);
+ stat = GdipSetCustomLineCapBaseCap((GpCustomLineCap*)cap, LineCapSquareAnchor); + ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat); + /* Base inset */ stat = GdipGetAdjustableArrowCapWidth(cap, &width); ok(stat == Ok, "Unexpected return code, %d\n", stat);
From: Bartosz Kosiorek gang65@poczta.onet.pl
--- dlls/gdiplus/graphicspath.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index d98a5ae4bf6..5ddd96778db 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -1876,7 +1876,7 @@ static void widen_joint(const GpPointF *p1, const GpPointF *p2, const GpPointF * }
static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint, - REAL pen_width, GpLineCap cap, GpCustomLineCap *custom, int add_first_points, + REAL pen_width, GpLineCap cap, int add_first_points, int add_last_point, path_list_node_t **last_point) { switch (cap) @@ -2097,8 +2097,8 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, }
static void widen_open_figure(const GpPointF *points, int start, int end, - GpPen *pen, REAL pen_width, GpLineCap start_cap, GpCustomLineCap *start_custom, - GpLineCap end_cap, GpCustomLineCap *end_custom, path_list_node_t **last_point) + GpPen *pen, REAL pen_width, GpLineCap start_cap, + GpLineCap end_cap, path_list_node_t **last_point) { int i; path_list_node_t *prev_point; @@ -2109,21 +2109,21 @@ static void widen_open_figure(const GpPointF *points, int start, int end, prev_point = *last_point;
widen_cap(&points[start], &points[start+1], - pen_width, start_cap, start_custom, FALSE, TRUE, last_point); + pen_width, start_cap, FALSE, TRUE, last_point);
for (i=start+1; i<end; i++) widen_joint(&points[i-1], &points[i], &points[i+1], pen, pen_width, last_point);
widen_cap(&points[end], &points[end-1], - pen_width, end_cap, end_custom, TRUE, TRUE, last_point); + pen_width, end_cap, TRUE, TRUE, last_point);
for (i=end-1; i>start; i--) widen_joint(&points[i+1], &points[i], &points[i-1], pen, pen_width, last_point);
widen_cap(&points[start], &points[start+1], - pen_width, start_cap, start_custom, TRUE, FALSE, last_point); + pen_width, start_cap, TRUE, FALSE, last_point);
prev_point->next->type = PathPointTypeStart; (*last_point)->type |= PathPointTypeCloseSubpath; @@ -2267,8 +2267,8 @@ static void widen_dashed_figure(GpPath *path, int start, int end, int closed, tmp_points[num_tmp_points].Y = path->pathdata.Points[i].Y + segment_dy * segment_pos / segment_length;
widen_open_figure(tmp_points, 0, num_tmp_points, pen, pen_width, - draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart, - LineCapFlat, NULL, last_point); + draw_start_cap ? pen->startcap : LineCapFlat, + LineCapFlat, last_point); draw_start_cap = 0; num_tmp_points = 0; } @@ -2301,8 +2301,8 @@ static void widen_dashed_figure(GpPath *path, int start, int end, int closed, { /* last dash overflows last segment */ widen_open_figure(tmp_points, 0, num_tmp_points-1, pen, pen_width, - draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart, - closed ? LineCapFlat : pen->endcap, pen->customend, last_point); + draw_start_cap ? pen->startcap : LineCapFlat, + closed ? LineCapFlat : pen->endcap, last_point); }
heap_free(dash_pattern_scaled); @@ -2377,7 +2377,7 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix, if (pen->dash != DashStyleSolid) widen_dashed_figure(flat_path, subpath_start, i, 0, pen, pen_width, &last_point); else - widen_open_figure(flat_path->pathdata.Points, subpath_start, i, pen, pen_width, pen->startcap, pen->customstart, pen->endcap, pen->customend, &last_point); + widen_open_figure(flat_path->pathdata.Points, subpath_start, i, pen, pen_width, pen->startcap, pen->endcap, &last_point); } }
From: Bartosz Kosiorek gang65@poczta.onet.pl
--- dlls/gdiplus/customlinecap.c | 10 +++++----- dlls/gdiplus/tests/customlinecap.c | 8 ++++++++ 2 files changed, 13 insertions(+), 5 deletions(-)
diff --git a/dlls/gdiplus/customlinecap.c b/dlls/gdiplus/customlinecap.c index 2e7b000355e..c05aecae29a 100644 --- a/dlls/gdiplus/customlinecap.c +++ b/dlls/gdiplus/customlinecap.c @@ -220,14 +220,14 @@ GpStatus WINGDIPAPI GdipGetCustomLineCapBaseInset(GpCustomLineCap* custom, GpStatus WINGDIPAPI GdipSetCustomLineCapBaseInset(GpCustomLineCap* custom, REAL inset) { - static int calls; - TRACE("(%p,%0.2f)\n", custom, inset);
- if(!(calls++)) - FIXME("not implemented\n"); + if(!custom) + return InvalidParameter;
- return NotImplemented; + custom->inset = inset; + + return Ok; }
/*FIXME: LineJoin completely ignored now */ diff --git a/dlls/gdiplus/tests/customlinecap.c b/dlls/gdiplus/tests/customlinecap.c index c475216ff21..89323040ad1 100644 --- a/dlls/gdiplus/tests/customlinecap.c +++ b/dlls/gdiplus/tests/customlinecap.c @@ -165,6 +165,14 @@ static void test_inset(void) expect(Ok, stat); expectf(0.0, inset);
+ stat = GdipSetCustomLineCapBaseInset(custom, 2.0); + expect(Ok, stat); + + inset = (REAL)0xdeadbeef; + stat = GdipGetCustomLineCapBaseInset(custom, &inset); + expect(Ok, stat); + ok(inset == 2.0, "Unexpected inset value %f\n", inset); + GdipDeleteCustomLineCap(custom); GdipDeletePath(path); }
From: Bartosz Kosiorek gang65@poczta.onet.pl
--- dlls/gdiplus/graphicspath.c | 66 ++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 33 deletions(-)
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index 5ddd96778db..c65dc19de5b 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -1982,6 +1982,39 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint, } }
+static void widen_open_figure(const GpPointF *points, int start, int end, + GpPen *pen, REAL pen_width, GpLineCap start_cap, + GpLineCap end_cap, path_list_node_t **last_point) +{ + int i; + path_list_node_t *prev_point; + + if (end <= start || pen_width == 0.0) + return; + + prev_point = *last_point; + + widen_cap(&points[start], &points[start+1], + pen_width, start_cap, FALSE, TRUE, last_point); + + for (i=start+1; i<end; i++) + widen_joint(&points[i-1], &points[i], &points[i+1], + pen, pen_width, last_point); + + widen_cap(&points[end], &points[end-1], + pen_width, end_cap, TRUE, TRUE, last_point); + + for (i=end-1; i>start; i--) + widen_joint(&points[i+1], &points[i], &points[i-1], + pen, pen_width, last_point); + + widen_cap(&points[start], &points[start+1], + pen_width, start_cap, TRUE, FALSE, last_point); + + prev_point->next->type = PathPointTypeStart; + (*last_point)->type |= PathPointTypeCloseSubpath; +} + static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, REAL pen_width, GpLineCap cap, GpCustomLineCap *custom, path_list_node_t **last_point) { @@ -2096,39 +2129,6 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, (*last_point)->type |= PathPointTypeCloseSubpath; }
-static void widen_open_figure(const GpPointF *points, int start, int end, - GpPen *pen, REAL pen_width, GpLineCap start_cap, - GpLineCap end_cap, path_list_node_t **last_point) -{ - int i; - path_list_node_t *prev_point; - - if (end <= start || pen_width == 0.0) - return; - - prev_point = *last_point; - - widen_cap(&points[start], &points[start+1], - pen_width, start_cap, FALSE, TRUE, last_point); - - for (i=start+1; i<end; i++) - widen_joint(&points[i-1], &points[i], &points[i+1], - pen, pen_width, last_point); - - widen_cap(&points[end], &points[end-1], - pen_width, end_cap, TRUE, TRUE, last_point); - - for (i=end-1; i>start; i--) - widen_joint(&points[i+1], &points[i], &points[i-1], - pen, pen_width, last_point); - - widen_cap(&points[start], &points[start+1], - pen_width, start_cap, TRUE, FALSE, last_point); - - prev_point->next->type = PathPointTypeStart; - (*last_point)->type |= PathPointTypeCloseSubpath; -} - static void widen_closed_figure(GpPath *path, int start, int end, GpPen *pen, REAL pen_width, path_list_node_t **last_point) {
From: Bartosz Kosiorek gang65@poczta.onet.pl
--- dlls/gdiplus/graphicspath.c | 84 ++++++++++++++++++------------------- 1 file changed, 42 insertions(+), 42 deletions(-)
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index c65dc19de5b..39e1494f603 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -2015,6 +2015,48 @@ static void widen_open_figure(const GpPointF *points, int start, int end, (*last_point)->type |= PathPointTypeCloseSubpath; }
+static void widen_closed_figure(GpPath *path, int start, int end, + GpPen *pen, REAL pen_width, path_list_node_t **last_point) +{ + int i; + path_list_node_t *prev_point; + + if (end <= start || pen_width == 0.0) + return; + + /* left outline */ + prev_point = *last_point; + + widen_joint(&path->pathdata.Points[end], &path->pathdata.Points[start], + &path->pathdata.Points[start+1], pen, pen_width, last_point); + + for (i=start+1; i<end; i++) + widen_joint(&path->pathdata.Points[i-1], &path->pathdata.Points[i], + &path->pathdata.Points[i+1], pen, pen_width, last_point); + + widen_joint(&path->pathdata.Points[end-1], &path->pathdata.Points[end], + &path->pathdata.Points[start], pen, pen_width, last_point); + + prev_point->next->type = PathPointTypeStart; + (*last_point)->type |= PathPointTypeCloseSubpath; + + /* right outline */ + prev_point = *last_point; + + widen_joint(&path->pathdata.Points[start], &path->pathdata.Points[end], + &path->pathdata.Points[end-1], pen, pen_width, last_point); + + for (i=end-1; i>start; i--) + widen_joint(&path->pathdata.Points[i+1], &path->pathdata.Points[i], + &path->pathdata.Points[i-1], pen, pen_width, last_point); + + widen_joint(&path->pathdata.Points[start+1], &path->pathdata.Points[start], + &path->pathdata.Points[end], pen, pen_width, last_point); + + prev_point->next->type = PathPointTypeStart; + (*last_point)->type |= PathPointTypeCloseSubpath; +} + static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, REAL pen_width, GpLineCap cap, GpCustomLineCap *custom, path_list_node_t **last_point) { @@ -2129,48 +2171,6 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, (*last_point)->type |= PathPointTypeCloseSubpath; }
-static void widen_closed_figure(GpPath *path, int start, int end, - GpPen *pen, REAL pen_width, path_list_node_t **last_point) -{ - int i; - path_list_node_t *prev_point; - - if (end <= start || pen_width == 0.0) - return; - - /* left outline */ - prev_point = *last_point; - - widen_joint(&path->pathdata.Points[end], &path->pathdata.Points[start], - &path->pathdata.Points[start+1], pen, pen_width, last_point); - - for (i=start+1; i<end; i++) - widen_joint(&path->pathdata.Points[i-1], &path->pathdata.Points[i], - &path->pathdata.Points[i+1], pen, pen_width, last_point); - - widen_joint(&path->pathdata.Points[end-1], &path->pathdata.Points[end], - &path->pathdata.Points[start], pen, pen_width, last_point); - - prev_point->next->type = PathPointTypeStart; - (*last_point)->type |= PathPointTypeCloseSubpath; - - /* right outline */ - prev_point = *last_point; - - widen_joint(&path->pathdata.Points[start], &path->pathdata.Points[end], - &path->pathdata.Points[end-1], pen, pen_width, last_point); - - for (i=end-1; i>start; i--) - widen_joint(&path->pathdata.Points[i+1], &path->pathdata.Points[i], - &path->pathdata.Points[i-1], pen, pen_width, last_point); - - widen_joint(&path->pathdata.Points[start+1], &path->pathdata.Points[start], - &path->pathdata.Points[end], pen, pen_width, last_point); - - prev_point->next->type = PathPointTypeStart; - (*last_point)->type |= PathPointTypeCloseSubpath; -} - static void widen_dashed_figure(GpPath *path, int start, int end, int closed, GpPen *pen, REAL pen_width, path_list_node_t **last_point) {
From: Bartosz Kosiorek gang65@poczta.onet.pl
--- dlls/gdiplus/graphicspath.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-)
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index 39e1494f603..d1e31f0761b 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -2015,7 +2015,7 @@ static void widen_open_figure(const GpPointF *points, int start, int end, (*last_point)->type |= PathPointTypeCloseSubpath; }
-static void widen_closed_figure(GpPath *path, int start, int end, +static void widen_closed_figure(const GpPointF *points, int start, int end, GpPen *pen, REAL pen_width, path_list_node_t **last_point) { int i; @@ -2027,15 +2027,15 @@ static void widen_closed_figure(GpPath *path, int start, int end, /* left outline */ prev_point = *last_point;
- widen_joint(&path->pathdata.Points[end], &path->pathdata.Points[start], - &path->pathdata.Points[start+1], pen, pen_width, last_point); + widen_joint(&points[end], &points[start], + &points[start+1], pen, pen_width, last_point);
for (i=start+1; i<end; i++) - widen_joint(&path->pathdata.Points[i-1], &path->pathdata.Points[i], - &path->pathdata.Points[i+1], pen, pen_width, last_point); + widen_joint(&points[i-1], &points[i], + &points[i+1], pen, pen_width, last_point);
- widen_joint(&path->pathdata.Points[end-1], &path->pathdata.Points[end], - &path->pathdata.Points[start], pen, pen_width, last_point); + widen_joint(&points[end-1], &points[end], + &points[start], pen, pen_width, last_point);
prev_point->next->type = PathPointTypeStart; (*last_point)->type |= PathPointTypeCloseSubpath; @@ -2043,15 +2043,15 @@ static void widen_closed_figure(GpPath *path, int start, int end, /* right outline */ prev_point = *last_point;
- widen_joint(&path->pathdata.Points[start], &path->pathdata.Points[end], - &path->pathdata.Points[end-1], pen, pen_width, last_point); + widen_joint(&points[start], &points[end], + &points[end-1], pen, pen_width, last_point);
for (i=end-1; i>start; i--) - widen_joint(&path->pathdata.Points[i+1], &path->pathdata.Points[i], - &path->pathdata.Points[i-1], pen, pen_width, last_point); + widen_joint(&points[i+1], &points[i], + &points[i-1], pen, pen_width, last_point);
- widen_joint(&path->pathdata.Points[start+1], &path->pathdata.Points[start], - &path->pathdata.Points[end], pen, pen_width, last_point); + widen_joint(&points[start+1], &points[start], + &points[end], pen, pen_width, last_point);
prev_point->next->type = PathPointTypeStart; (*last_point)->type |= PathPointTypeCloseSubpath; @@ -2369,7 +2369,7 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix, if (pen->dash != DashStyleSolid) widen_dashed_figure(flat_path, subpath_start, i, 1, pen, pen_width, &last_point); else - widen_closed_figure(flat_path, subpath_start, i, pen, pen_width, &last_point); + widen_closed_figure(flat_path->pathdata.Points, subpath_start, i, pen, pen_width, &last_point); } else if (i == flat_path->pathdata.Count-1 || (types[i+1]&PathPointTypePathTypeMask) == PathPointTypeStart)
From: Bartosz Kosiorek gang65@poczta.onet.pl
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45273 --- dlls/gdiplus/gdiplus_private.h | 4 +- dlls/gdiplus/graphicspath.c | 74 ++++++++++++++++++++++++++++--- dlls/gdiplus/tests/graphicspath.c | 13 ++++++ 3 files changed, 83 insertions(+), 8 deletions(-)
diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 77b35659946..51b83b3242a 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -352,8 +352,8 @@ struct GpCustomLineCap{ GpPathData pathdata; BOOL fill; /* TRUE for fill, FALSE for stroke */ GpLineCap basecap; /* cap used together with customLineCap */ - REAL inset; /* how much to adjust the end of the line */ - GpLineJoin join; + REAL inset; /* distance between line and cap */ + GpLineJoin join; /* joins used for drawing custom cap*/ REAL scale; };
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index d1e31f0761b..08c96416e7c 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -2058,8 +2058,9 @@ static void widen_closed_figure(const GpPointF *points, int start, int end, }
static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, - REAL pen_width, GpLineCap cap, GpCustomLineCap *custom, path_list_node_t **last_point) + GpPen *pen, GpLineCap cap, GpCustomLineCap *custom, path_list_node_t **last_point) { + REAL pen_width = max(pen->width, 2.0); switch (cap) { default: @@ -2166,6 +2167,68 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, endpoint->Y + perp_dy, PathPointTypeLine); break; } + case LineCapCustom: + { + REAL segment_dy = nextpoint->Y - endpoint->Y; + REAL segment_dx = nextpoint->X - endpoint->X; + REAL segment_length = sqrtf(segment_dy * segment_dy + segment_dx * segment_dx); + REAL posx, posy; + REAL perp_dx, perp_dy; + REAL sina, cosa; + GpPointF *tmp_points; + + if(!custom) + break; + + if (custom->type == CustomLineCapTypeAdjustableArrow) + { + GpAdjustableArrowCap *arrow = (GpAdjustableArrowCap *)custom; + TRACE("GpAdjustableArrowCap middle_inset: %f height: %f width: %f\n", + arrow->middle_inset, arrow->height, arrow->width); + } + else + TRACE("GpCustomLineCap fill: %d basecap: %d inset: %f join: %d scale: %f pen_width:%f\n", + custom->fill, custom->basecap, custom->inset, custom->join, custom->scale, pen_width); + + // Coordination where cap needs to be drawn + posx = endpoint->X - pen_width * segment_dx / segment_length; + posy = endpoint->Y - pen_width * segment_dy / segment_length; + + sina = -pen_width * custom->scale * segment_dx / segment_length; + cosa = pen_width * custom->scale * segment_dy / segment_length; + + if (!custom->fill) + { + tmp_points = heap_alloc_zero(custom->pathdata.Count * sizeof(GpPoint)); + if (!tmp_points) { + ERR("Out of memory\n"); + return; + } + + for (INT i = 0; i < custom->pathdata.Count; i++) + { + tmp_points[i].X = posx + custom->pathdata.Points[i].X * cosa + (custom->pathdata.Points[i].Y - 1.0) * sina; + tmp_points[i].Y = posy + custom->pathdata.Points[i].X * sina - (custom->pathdata.Points[i].Y - 1.0) * cosa; + } + if ((custom->pathdata.Types[custom->pathdata.Count - 1] & PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath) + widen_closed_figure(tmp_points, 0, custom->pathdata.Count - 1, pen, pen_width, last_point); + else + widen_open_figure(tmp_points, 0, custom->pathdata.Count - 1, pen, pen_width, LineCapFlat, LineCapFlat, last_point); + } + else + { + for (INT i = 0; i < custom->pathdata.Count; i++) + { + // rotation of CustomCap according to line + perp_dx = custom->pathdata.Points[i].X * cosa + (custom->pathdata.Points[i].Y - 1.0) * sina; + perp_dy = custom->pathdata.Points[i].X * sina - (custom->pathdata.Points[i].Y - 1.0) * cosa; + *last_point = add_path_list_node(*last_point, posx + perp_dx, + posy + perp_dy, custom->pathdata.Types[i]); + } + } + // FIXME: The line should be shorter, and it should ends up when Arrow/Cap is started draw + break; + } }
(*last_point)->type |= PathPointTypeCloseSubpath; @@ -2335,16 +2398,15 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
if (status == Ok) { - REAL anchor_pen_width = max(pen->width, 2.0); REAL pen_width = (pen->unit == UnitWorld) ? max(pen->width, 1.0) : pen->width; BYTE *types = flat_path->pathdata.Types;
last_point = points;
- if (pen->endcap > LineCapDiamondAnchor) + if (pen->endcap > LineCapDiamondAnchor && pen->endcap != LineCapCustom) FIXME("unimplemented end cap %x\n", pen->endcap);
- if (pen->startcap > LineCapDiamondAnchor) + if (pen->startcap > LineCapDiamondAnchor && pen->startcap != LineCapCustom) FIXME("unimplemented start cap %x\n", pen->startcap);
if (pen->dashcap != DashCapFlat) @@ -2395,12 +2457,12 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix, if (pen->startcap & LineCapAnchorMask) add_anchor(&flat_path->pathdata.Points[subpath_start], &flat_path->pathdata.Points[subpath_start+1], - anchor_pen_width, pen->startcap, pen->customstart, &last_point); + pen, pen->startcap, pen->customstart, &last_point);
if (pen->endcap & LineCapAnchorMask) add_anchor(&flat_path->pathdata.Points[i], &flat_path->pathdata.Points[i-1], - anchor_pen_width, pen->endcap, pen->customend, &last_point); + pen, pen->endcap, pen->customend, &last_point); } }
diff --git a/dlls/gdiplus/tests/graphicspath.c b/dlls/gdiplus/tests/graphicspath.c index 07e6dd166ad..ab1e7cb2fda 100644 --- a/dlls/gdiplus/tests/graphicspath.c +++ b/dlls/gdiplus/tests/graphicspath.c @@ -1682,9 +1682,12 @@ static void test_widen_cap(void) { LineCapSquareAnchor, 10.0, widenline_capsquareanchor_dashed_path, ARRAY_SIZE(widenline_capsquareanchor_dashed_path), TRUE }, }; + + GpAdjustableArrowCap *arrowcap; GpStatus status; GpPath *path; GpPen *pen; + int i;
status = GdipCreatePath(FillModeAlternate, &path); @@ -1749,6 +1752,16 @@ static void test_widen_cap(void) expect(Ok, status); ok_path_fudge(path, widenline_capsquareanchor_multifigure_path, ARRAY_SIZE(widenline_capsquareanchor_multifigure_path), FALSE, 0.000005); + + status = GdipCreateAdjustableArrowCap(4.0, 4.0, TRUE, &arrowcap); + ok(status == Ok, "Failed to create adjustable cap, %d\n", status); + status = GdipSetAdjustableArrowCapMiddleInset(arrowcap, 1.0); + ok(status == Ok, "Failed to set middle inset inadjustable cap, %d\n", status); + status = GdipSetPenCustomEndCap(pen, (GpCustomLineCap*)arrowcap); + ok(status == Ok, "Failed to create custom end cap, %d\n", status); + status = GdipWidenPath(path, pen, NULL, FlatnessDefault); + expect(Ok, status); + GdipDeletePen(pen);
GdipDeletePath(path);
From: Bartosz Kosiorek gang65@poczta.onet.pl
--- dlls/gdiplus/customlinecap.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/gdiplus/customlinecap.c b/dlls/gdiplus/customlinecap.c index c05aecae29a..306c4db242b 100644 --- a/dlls/gdiplus/customlinecap.c +++ b/dlls/gdiplus/customlinecap.c @@ -305,18 +305,18 @@ static void arrowcap_update_path(GpAdjustableArrowCap *cap) points[2].X = cap->width / 2.0; points[2].Y = -cap->height; points[3].X = 0.0; - points[3].Y = -cap->height - cap->middle_inset; + points[3].Y = -cap->height + cap->middle_inset; } else { memcpy(cap->cap.pathdata.Types, types_unfilled, sizeof(types_unfilled)); cap->cap.pathdata.Count = 3; - points[0].X = -cap->width / 4.0; - points[0].Y = -cap->height / 2.0; + points[0].X = -cap->width / 2.0; + points[0].Y = -cap->height; points[1].X = 0.0; points[1].Y = 0.0; - points[2].X = cap->width / 4.0; - points[2].Y = -cap->height / 2.0; + points[2].X = cap->width / 2.0; + points[2].Y = -cap->height; }
if (cap->width == 0.0)
From: Bartosz Kosiorek gang65@poczta.onet.pl
--- dlls/gdiplus/customlinecap.c | 16 +++++++-------- dlls/gdiplus/gdiplus_private.h | 4 +++- dlls/gdiplus/graphicspath.c | 2 +- dlls/gdiplus/tests/customlinecap.c | 31 ++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 10 deletions(-)
diff --git a/dlls/gdiplus/customlinecap.c b/dlls/gdiplus/customlinecap.c index 306c4db242b..f35fea90eba 100644 --- a/dlls/gdiplus/customlinecap.c +++ b/dlls/gdiplus/customlinecap.c @@ -97,6 +97,8 @@ static GpStatus init_custom_linecap(GpCustomLineCap *cap, GpPathData *pathdata,
cap->inset = base_inset; cap->basecap = basecap; + cap->strokeStartCap = LineCapFlat; + cap->strokeEndCap = LineCapFlat; cap->join = LineJoinMiter; cap->scale = 1.0;
@@ -177,19 +179,17 @@ GpStatus WINGDIPAPI GdipGetCustomLineCapWidthScale(GpCustomLineCap* custom, }
GpStatus WINGDIPAPI GdipSetCustomLineCapStrokeCaps(GpCustomLineCap* custom, - GpLineCap start, GpLineCap end) + GpLineCap startcap, GpLineCap endcap) { - static int calls; + TRACE("(%p,%u,%u)\n", custom, startcap, endcap);
- TRACE("(%p,%u,%u)\n", custom, start, end); - - if(!custom) + if(!custom || startcap > LineCapTriangle || endcap > LineCapTriangle) return InvalidParameter;
- if(!(calls++)) - FIXME("not implemented\n"); + custom->strokeStartCap = startcap; + custom->strokeEndCap = endcap;
- return NotImplemented; + return Ok; }
GpStatus WINGDIPAPI GdipSetCustomLineCapBaseCap(GpCustomLineCap* custom, diff --git a/dlls/gdiplus/gdiplus_private.h b/dlls/gdiplus/gdiplus_private.h index 51b83b3242a..bb7d32af47f 100644 --- a/dlls/gdiplus/gdiplus_private.h +++ b/dlls/gdiplus/gdiplus_private.h @@ -352,7 +352,9 @@ struct GpCustomLineCap{ GpPathData pathdata; BOOL fill; /* TRUE for fill, FALSE for stroke */ GpLineCap basecap; /* cap used together with customLineCap */ - REAL inset; /* distance between line and cap */ + REAL inset; /* distance between line end and cap beginning */ + GpLineCap strokeStartCap; + GpLineCap strokeEndCap; GpLineJoin join; /* joins used for drawing custom cap*/ REAL scale; }; diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index 08c96416e7c..15a5461ae6d 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -2213,7 +2213,7 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, if ((custom->pathdata.Types[custom->pathdata.Count - 1] & PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath) widen_closed_figure(tmp_points, 0, custom->pathdata.Count - 1, pen, pen_width, last_point); else - widen_open_figure(tmp_points, 0, custom->pathdata.Count - 1, pen, pen_width, LineCapFlat, LineCapFlat, last_point); + widen_open_figure(tmp_points, 0, custom->pathdata.Count - 1, pen, pen_width, custom->strokeEndCap, custom->strokeStartCap, last_point); } else { diff --git a/dlls/gdiplus/tests/customlinecap.c b/dlls/gdiplus/tests/customlinecap.c index 89323040ad1..9efb0694285 100644 --- a/dlls/gdiplus/tests/customlinecap.c +++ b/dlls/gdiplus/tests/customlinecap.c @@ -380,6 +380,36 @@ static void test_captype(void) GdipDeleteCustomLineCap((GpCustomLineCap*)arrowcap); }
+static void test_strokecap(void) +{ + GpAdjustableArrowCap *arrowcap; + GpCustomLineCap *cap; + CustomLineCapType type; + GpStatus stat; + GpPath *path; + + /* default cap */ + stat = GdipCreatePath(FillModeAlternate, &path); + ok(stat == Ok, "Failed to create path, %d\n", stat); + stat = GdipAddPathRectangle(path, 5.0, 5.0, 10.0, 10.0); + ok(stat == Ok, "AddPathRectangle failed, %d\n", stat); + + stat = GdipCreateCustomLineCap(NULL, path, LineCapFlat, 0.0, &cap); + ok(stat == Ok, "Failed to create cap, %d\n", stat); + + stat = GdipSetCustomLineCapStrokeCaps((GpCustomLineCap*)cap, LineCapSquare, LineCapFlat); + ok(stat == Ok, "Unexpected return code, %d\n", stat); + + stat = GdipSetCustomLineCapStrokeCaps((GpCustomLineCap*)cap, LineCapSquareAnchor, LineCapFlat); + ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat); + + stat = GdipSetCustomLineCapStrokeCaps((GpCustomLineCap*)cap, LineCapFlat, LineCapSquareAnchor); + ok(stat == InvalidParameter, "Unexpected return code, %d\n", stat); + GdipDeleteCustomLineCap(cap); + GdipDeletePath(path); + GdipDeleteCustomLineCap((GpCustomLineCap*)arrowcap); +} + START_TEST(customlinecap) { struct GdiplusStartupInput gdiplusStartupInput; @@ -405,6 +435,7 @@ START_TEST(customlinecap) test_scale(); test_create_adjustable_cap(); test_captype(); + test_strokecap();
GdiplusShutdown(gdiplusToken); }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=126383
Your paranoid android.
=== debian11 (32 bit report) ===
d3d9: stateblock: Timeout visual: Timeout
d3dcompiler_43: asm: Timeout blob: Timeout hlsl_d3d11: Timeout hlsl_d3d9: Timeout reflection: Timeout
d3dcompiler_46: asm: Timeout blob: Timeout hlsl_d3d11: Timeout hlsl_d3d9: Timeout reflection: Timeout
d3dcompiler_47: asm: Timeout blob: Timeout hlsl_d3d11: Timeout hlsl_d3d9: Timeout reflection: Timeout
d3drm: d3drm: Timeout vector: Timeout
d3dx10_34: d3dx10: Timeout
d3dx10_35: d3dx10: Timeout
d3dx10_36: d3dx10: Timeout
d3dx10_37: d3dx10: Timeout
d3dx10_38: d3dx10: Timeout
d3dx10_39: d3dx10: Timeout
d3dx10_40: d3dx10: Timeout
d3dx10_41: d3dx10: Timeout
d3dx10_42: d3dx10: Timeout
d3dx10_43: d3dx10: Timeout
d3dx11_42: d3dx11: Timeout
d3dx11_43: d3dx11: Timeout
d3dx9_36: asm: Timeout core: Timeout effect: Timeout
Report validation errors: line: Timeout
=== debian11 (build log) ===
WineRunWineTest.pl:error: The task timed out
An application used for testing (including stroke caps, filled/unfilled caps, position of the cap): [gdiplusdisplay.exe](/uploads/207cf34fc03b93190e69b9846bdaf385/gdiplusdisplay.exe)
How it tooks like under Windows:
On Thu Nov 17 10:17:28 2022 +0000, Bartosz Kosiorek wrote:
TODO The line should be shortened, to not mix with Customized Cap (the customized cap was drawn correctly, only the line is too long). Do you know how to implement that? ![Screenshot_from_2022-11-08_19-51-40](/uploads/dabd7fb066ec5b47b828621383efcb5e/Screenshot_from_2022-11-08_19-51-40.png)
I'm not sure. Maybe widen_open_figure needs to be aware of the inset and adjust the points it passes to width_joint. Or maybe the path needs to be adjusted after GdipFlattenPath.
I think it depends on what happens when the path ends with a segment that's shorter than the inset.