Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45273
-- v2: gdiplus: Add support for widen path with GpCustomLineCap. gdiplus: Add GdipSetCustomLineCapBaseInset implementation.
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
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45273 --- dlls/gdiplus/customlinecap.c | 2 +- dlls/gdiplus/gdiplus_private.h | 4 ++-- dlls/gdiplus/graphicspath.c | 35 +++++++++++++++++++++++++++++-- dlls/gdiplus/tests/graphicspath.c | 13 ++++++++++++ 4 files changed, 49 insertions(+), 5 deletions(-)
diff --git a/dlls/gdiplus/customlinecap.c b/dlls/gdiplus/customlinecap.c index c05aecae29a..3943150d875 100644 --- a/dlls/gdiplus/customlinecap.c +++ b/dlls/gdiplus/customlinecap.c @@ -305,7 +305,7 @@ 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 { 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 5ddd96778db..1758306ef58 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -2091,6 +2091,37 @@ 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 par_dx, par_dy; + REAL perp_dx, perp_dy; + REAL sina, cosa; + + if(!custom) + break; + + 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 + par_dx = -pen_width * segment_dx / segment_length; + par_dy = -pen_width * segment_dy / segment_length; + + sina = -pen_width * custom->scale * segment_dx / segment_length; + cosa = pen_width * custom->scale * segment_dy / segment_length; + + 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 - custom->inset) * sina; + perp_dy = custom->pathdata.Points[i].X * sina - (custom->pathdata.Points[i].Y - custom->inset) * cosa; + *last_point = add_path_list_node(*last_point, endpoint->X + par_dx + perp_dx, + endpoint->Y + par_dy + 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; @@ -2341,10 +2372,10 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
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) diff --git a/dlls/gdiplus/tests/graphicspath.c b/dlls/gdiplus/tests/graphicspath.c index 07e6dd166ad..213fecef2ca 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, 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);
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=125914
Your paranoid android.
=== debian11 (32 bit report) ===
d3drm: d3drm.c:4776: Test failed: Cannot create IDirect3DRMDevice2 interface, hr 0x8007000e. d3drm.c:4778: Test failed: expected ref3 > ref1, got ref1 = 1 , ref3 = 1. d3drm.c:4782: Test failed: Expected surface_ref2 > surface_ref1, got surface_ref1 = 1, surface_ref2 = 1. Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x004106c1).
=== debian11 (build log) ===
053c:err:winediag:d3d_device_create The application wants to create a Direct3D device, but the current DirectDrawRenderer does not support this.