Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45273
-- v10: gdiplus: add support for LineCapArrowAnchor.
From: Bartosz Kosiorek gang65@poczta.onet.pl
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45273 --- dlls/gdiplus/graphicspath.c | 53 +++++++++++++++++++++---------------- 1 file changed, 30 insertions(+), 23 deletions(-)
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index fdb7dd24906..9194f6d42aa 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, int add_first_points, + REAL pen_width, GpLineCap cap, GpCustomLineCap* custom_cap, int add_first_points, int add_last_point, path_list_node_t **last_point) { switch (cap) @@ -1889,6 +1889,7 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint, add_bevel_point(endpoint, nextpoint, pen_width, 0, last_point); break; case LineCapSquare: + case LineCapCustom: { REAL segment_dy = nextpoint->Y-endpoint->Y; REAL segment_dx = nextpoint->X-endpoint->X; @@ -1897,20 +1898,25 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint, REAL bevel_dx, bevel_dy; REAL extend_dx, extend_dy;
- extend_dx = -distance * segment_dx / segment_length; - extend_dy = -distance * segment_dy / segment_length; + extend_dx = distance * segment_dx / segment_length; + extend_dy = distance * segment_dy / segment_length;
- bevel_dx = -distance * segment_dy / segment_length; - bevel_dy = distance * segment_dx / segment_length; + bevel_dx = -extend_dy; + bevel_dy = extend_dx; + + if (cap == LineCapCustom) + { + extend_dx = -2.0 * custom_cap->inset * extend_dx; + extend_dy = -2.0 * custom_cap->inset * extend_dy; + }
if (add_first_points) - *last_point = add_path_list_node(*last_point, endpoint->X + extend_dx + bevel_dx, - endpoint->Y + extend_dy + bevel_dy, PathPointTypeLine); + *last_point = add_path_list_node(*last_point, endpoint->X - extend_dx + bevel_dx, + endpoint->Y - extend_dy + bevel_dy, PathPointTypeLine);
if (add_last_point) - *last_point = add_path_list_node(*last_point, endpoint->X + extend_dx - bevel_dx, - endpoint->Y + extend_dy - bevel_dy, PathPointTypeLine); - + *last_point = add_path_list_node(*last_point, endpoint->X - extend_dx - bevel_dx, + endpoint->Y - extend_dy - bevel_dy, PathPointTypeLine); break; } case LineCapRound: @@ -1983,8 +1989,8 @@ 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); + GpPen *pen, REAL pen_width, GpLineCap start_cap, GpCustomLineCap* custom_start, + GpLineCap end_cap, GpCustomLineCap* custom_end, path_list_node_t **last_point);
static void widen_closed_figure(const GpPointF *points, int start, int end, GpPen *pen, REAL pen_width, path_list_node_t **last_point); @@ -2145,7 +2151,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, custom->strokeEndCap, custom->strokeStartCap, last_point); + widen_open_figure(tmp_points, 0, custom->pathdata.Count - 1, pen, pen_width, custom->strokeEndCap, NULL, custom->strokeStartCap, NULL, last_point); } else { @@ -2167,8 +2173,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, - GpLineCap end_cap, path_list_node_t **last_point) + GpPen *pen, REAL pen_width, GpLineCap start_cap, GpCustomLineCap* custom_start, + GpLineCap end_cap, GpCustomLineCap* custom_end, path_list_node_t **last_point) { int i; path_list_node_t *prev_point; @@ -2179,21 +2185,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, FALSE, TRUE, last_point); + pen_width, start_cap, custom_start, 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); + pen_width, end_cap, custom_end, 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); + pen_width, start_cap, custom_start, TRUE, FALSE, last_point);
prev_point->next->type = PathPointTypeStart; (*last_point)->type |= PathPointTypeCloseSubpath; @@ -2337,8 +2343,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, - LineCapFlat, last_point); + draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart, + LineCapFlat, NULL, last_point); draw_start_cap = 0; num_tmp_points = 0; } @@ -2371,8 +2377,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, - closed ? LineCapFlat : pen->endcap, last_point); + draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart, + closed ? LineCapFlat : pen->endcap, pen->customend, last_point); }
heap_free(dash_pattern_scaled); @@ -2446,7 +2452,8 @@ 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->endcap, &last_point); + widen_open_figure(flat_path->pathdata.Points, subpath_start, i, pen, pen_width, + pen->startcap, pen->customstart, pen->endcap, pen->customend, &last_point); } }
From: Bartosz Kosiorek gang65@poczta.onet.pl
--- dlls/gdiplus/graphicspath.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index 9194f6d42aa..10ffa85d6e3 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -2128,13 +2128,13 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, 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;
+ /* Coordination where cap needs to be drawn */ + posx = endpoint->X + sina; + posy = endpoint->Y - cosa; + if (!custom->fill) { tmp_points = heap_alloc_zero(custom->pathdata.Count * sizeof(GpPoint));
From: Bartosz Kosiorek gang65@poczta.onet.pl
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=42809 --- dlls/gdiplus/graphicspath.c | 30 ++++++++++++++++++++++++------ dlls/gdiplus/tests/graphicspath.c | 7 +++---- 2 files changed, 27 insertions(+), 10 deletions(-)
diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index 10ffa85d6e3..01a39cf70fa 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -1890,6 +1890,7 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint, break; case LineCapSquare: case LineCapCustom: + case LineCapArrowAnchor: { REAL segment_dy = nextpoint->Y-endpoint->Y; REAL segment_dx = nextpoint->X-endpoint->X; @@ -1909,6 +1910,11 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint, extend_dx = -2.0 * custom_cap->inset * extend_dx; extend_dy = -2.0 * custom_cap->inset * extend_dy; } + else if (cap == LineCapArrowAnchor) + { + extend_dx = -3.0 * extend_dx; + extend_dy = -3.0 * extend_dy; + }
if (add_first_points) *last_point = add_path_list_node(*last_point, endpoint->X - extend_dx + bevel_dx, @@ -2105,6 +2111,24 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, endpoint->Y + perp_dy, PathPointTypeLine); break; } + case LineCapArrowAnchor: + { + 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 par_dx = pen_width * segment_dx / segment_length; + REAL par_dy = pen_width * segment_dy / segment_length; + REAL perp_dx = -par_dy; + REAL perp_dy = par_dx; + + *last_point = add_path_list_node(*last_point, endpoint->X, + endpoint->Y, PathPointTypeStart); + *last_point = add_path_list_node(*last_point, endpoint->X + 1.7320507 * par_dx - perp_dx, + endpoint->Y + 1.7320507 * par_dy - perp_dy, PathPointTypeLine); + *last_point = add_path_list_node(*last_point, endpoint->X + 1.7320507 * par_dx + perp_dx, + endpoint->Y + 1.7320507 * par_dy + perp_dy, PathPointTypeLine); + break; + } case LineCapCustom: { REAL segment_dy = nextpoint->Y - endpoint->Y; @@ -2416,12 +2440,6 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
last_point = points;
- if (pen->endcap > LineCapDiamondAnchor && pen->endcap != LineCapCustom) - FIXME("unimplemented end cap %x\n", pen->endcap); - - if (pen->startcap > LineCapDiamondAnchor && pen->startcap != LineCapCustom) - FIXME("unimplemented start cap %x\n", pen->startcap); - if (pen->dashcap != DashCapFlat) FIXME("unimplemented dash cap %d\n", pen->dashcap);
diff --git a/dlls/gdiplus/tests/graphicspath.c b/dlls/gdiplus/tests/graphicspath.c index ab1e7cb2fda..5082f0671d2 100644 --- a/dlls/gdiplus/tests/graphicspath.c +++ b/dlls/gdiplus/tests/graphicspath.c @@ -114,7 +114,7 @@ static void _ok_path_fudge(GpPath* path, const path_test_t *expected, INT expect stringify_point_type(types[idx], name);
todo_wine_if (expected[eidx].todo || numskip) - ok_(__FILE__,line)(match, "Expected #%d: %s (%.1f,%.1f) but got %s (%.1f,%.1f)\n", eidx, + ok_(__FILE__,line)(match, "Expected #%d: %s (%.6f,%.6f) but got %s (%.6f,%.6f)\n", eidx, ename, expected[eidx].X, expected[eidx].Y, name, points[idx].X, points[idx].Y);
@@ -1655,7 +1655,6 @@ static void test_widen_cap(void) const path_test_t *expected; INT expected_size; BOOL dashed; - BOOL todo_size; } caps[] = { @@ -1676,7 +1675,7 @@ static void test_widen_cap(void) { LineCapDiamondAnchor, 10.0, widenline_capdiamondanchor_path, ARRAY_SIZE(widenline_capdiamondanchor_path) }, { LineCapArrowAnchor, 10.0, widenline_caparrowanchor_path, - ARRAY_SIZE(widenline_caparrowanchor_path), FALSE, TRUE }, + ARRAY_SIZE(widenline_caparrowanchor_path) }, { LineCapSquareAnchor, 0.0, widenline_capsquareanchor_thin_path, ARRAY_SIZE(widenline_capsquareanchor_thin_path) }, { LineCapSquareAnchor, 10.0, widenline_capsquareanchor_dashed_path, @@ -1729,7 +1728,7 @@ static void test_widen_cap(void) } }
- ok_path_fudge(path, caps[i].expected, caps[i].expected_size, caps[i].todo_size, 0.000005); + ok_path_fudge(path, caps[i].expected, caps[i].expected_size, FALSE, 0.000005);
GdipDeletePen(pen); }
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=126820
Your paranoid android.
=== debian11 (32 bit report) ===
winhttp: winhttp.c:3637: Test failed: got 12152 winhttp.c:3638: Test failed: got winhttp.c:3639: Test failed: got 0 winhttp.c:3640: Test failed: got 3735928559 winhttp.c:3646: Test failed: got 12152 winhttp.c:3647: Test failed: got winhttp.c:3648: Test failed: got 0 winhttp.c:3649: Test failed: got 3735928559 winhttp.c:3669: Test failed: got 12152 winhttp.c:3688: Test failed: got 4317 winhttp.c:3689: Test failed: got 3735928559 winhttp.c:3698: Test failed: got 4317 winhttp.c:3699: Test failed: got 57005 winhttp.c:3700: Test failed: got 3735928559
On Sat Nov 26 08:49:21 2022 +0000, Bartosz Kosiorek wrote:
changed this line in [version 3 of the diff](/wine/wine/-/merge_requests/1539/diffs?diff_id=21176&start_sha=7fc0346ad975cd21c06f3861e3c3839fb9caa986#9d342cb9ef84c6aa095e339b5428909837d1092b_2124_2124)
You could probably get this exact by testing the result of GdipWidenPath.
On Sat Nov 26 17:37:30 2022 +0000, Esme Povirk wrote:
You could probably get this exact by testing the result of GdipWidenPath.
Oh, I guess we already had a test for that.
Esme Povirk (@madewokherd) commented about dlls/gdiplus/graphicspath.c:
endpoint->Y + perp_dy, PathPointTypeLine); break; }
- case LineCapArrowAnchor:
- {
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 par_dx = pen_width * segment_dx / segment_length;
REAL par_dy = pen_width * segment_dy / segment_length;
REAL perp_dx = -par_dy;
REAL perp_dy = par_dx;
*last_point = add_path_list_node(*last_point, endpoint->X,
endpoint->Y, PathPointTypeStart);
*last_point = add_path_list_node(*last_point, endpoint->X + 1.7320507 * par_dx - perp_dx,
I think this constant is sqrt(3).
On Sat Nov 26 17:44:43 2022 +0000, Esme Povirk wrote:
I think this constant is sqrt(3).
Nice catch. Should I change something terenie?
On Sat Nov 26 17:52:25 2022 +0000, Bartosz Kosiorek wrote:
Nice catch. Should I change something terenie?
Well, we don't want to call sqrt() at runtime for this, but it'd be good to document. I'd just make a `#define SQRT_3`.