mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-15 07:40:21 +00:00
gdiplus: Add support for widen path with GpCustomLineCap.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=45273
This commit is contained in:
parent
a8e8730769
commit
1271ae3ebd
|
@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
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,
|
||||||
|
|
||||||
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,
|
||||||
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)
|
||||||
{ 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)
|
||||||
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);
|
||||||
|
|
Loading…
Reference in a new issue