Commit 1271ae3e authored by Bartosz Kosiorek's avatar Bartosz Kosiorek Committed by Alexandre Julliard

gdiplus: Add support for widen path with GpCustomLineCap.

parent a8e87307
...@@ -352,8 +352,8 @@ struct GpCustomLineCap{ ...@@ -352,8 +352,8 @@ struct GpCustomLineCap{
GpPathData pathdata; GpPathData pathdata;
BOOL fill; /* TRUE for fill, FALSE for stroke */ BOOL fill; /* TRUE for fill, FALSE for stroke */
GpLineCap basecap; /* cap used together with customLineCap */ GpLineCap basecap; /* cap used together with customLineCap */
REAL inset; /* how much to adjust the end of the line */ REAL inset; /* distance between line end and cap beginning */
GpLineJoin join; GpLineJoin join; /* joins used for drawing custom cap*/
REAL scale; REAL scale;
}; };
......
...@@ -1982,9 +1982,17 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint, ...@@ -1982,9 +1982,17 @@ 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);
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, 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) switch (cap)
{ {
default: default:
...@@ -2091,6 +2099,68 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint, ...@@ -2091,6 +2099,68 @@ static void add_anchor(const GpPointF *endpoint, const GpPointF *nextpoint,
endpoint->Y + perp_dy, PathPointTypeLine); endpoint->Y + perp_dy, PathPointTypeLine);
break; 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 adjusted by the inset value of the custom cap. */
break;
}
} }
(*last_point)->type |= PathPointTypeCloseSubpath; (*last_point)->type |= PathPointTypeCloseSubpath;
...@@ -2335,16 +2405,15 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix, ...@@ -2335,16 +2405,15 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
if (status == Ok) 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; REAL pen_width = (pen->unit == UnitWorld) ? max(pen->width, 1.0) : pen->width;
BYTE *types = flat_path->pathdata.Types; BYTE *types = flat_path->pathdata.Types;
last_point = points; last_point = points;
if (pen->endcap > LineCapDiamondAnchor) if (pen->endcap > LineCapDiamondAnchor && pen->endcap != LineCapCustom)
FIXME("unimplemented end cap %x\n", pen->endcap); 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); FIXME("unimplemented start cap %x\n", pen->startcap);
if (pen->dashcap != DashCapFlat) if (pen->dashcap != DashCapFlat)
...@@ -2395,12 +2464,12 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix, ...@@ -2395,12 +2464,12 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
if (pen->startcap & LineCapAnchorMask) if (pen->startcap & LineCapAnchorMask)
add_anchor(&flat_path->pathdata.Points[subpath_start], add_anchor(&flat_path->pathdata.Points[subpath_start],
&flat_path->pathdata.Points[subpath_start+1], &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) if (pen->endcap & LineCapAnchorMask)
add_anchor(&flat_path->pathdata.Points[i], add_anchor(&flat_path->pathdata.Points[i],
&flat_path->pathdata.Points[i-1], &flat_path->pathdata.Points[i-1],
anchor_pen_width, pen->endcap, pen->customend, &last_point); pen, pen->endcap, pen->customend, &last_point);
} }
} }
......
...@@ -1682,9 +1682,12 @@ static void test_widen_cap(void) ...@@ -1682,9 +1682,12 @@ static void test_widen_cap(void)
{ LineCapSquareAnchor, 10.0, widenline_capsquareanchor_dashed_path, { LineCapSquareAnchor, 10.0, widenline_capsquareanchor_dashed_path,
ARRAY_SIZE(widenline_capsquareanchor_dashed_path), TRUE }, ARRAY_SIZE(widenline_capsquareanchor_dashed_path), TRUE },
}; };
GpAdjustableArrowCap *arrowcap;
GpStatus status; GpStatus status;
GpPath *path; GpPath *path;
GpPen *pen; GpPen *pen;
int i; int i;
status = GdipCreatePath(FillModeAlternate, &path); status = GdipCreatePath(FillModeAlternate, &path);
...@@ -1749,6 +1752,16 @@ static void test_widen_cap(void) ...@@ -1749,6 +1752,16 @@ static void test_widen_cap(void)
expect(Ok, status); expect(Ok, status);
ok_path_fudge(path, widenline_capsquareanchor_multifigure_path, ok_path_fudge(path, widenline_capsquareanchor_multifigure_path,
ARRAY_SIZE(widenline_capsquareanchor_multifigure_path), FALSE, 0.000005); 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); GdipDeletePen(pen);
GdipDeletePath(path); GdipDeletePath(path);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment