gdiplus: Implement GdipWidenPath for custom dashed lines.

This commit is contained in:
Vincent Povirk 2013-10-23 13:05:50 -05:00 committed by Alexandre Julliard
parent ae3a6d52d0
commit 1c35dd6cb4
1 changed files with 127 additions and 15 deletions

View File

@ -1851,8 +1851,9 @@ static void widen_cap(const GpPointF *endpoint, const GpPointF *nextpoint,
}
}
static void widen_open_figure(GpPath *path, GpPen *pen, int start, int end,
path_list_node_t **last_point)
static void widen_open_figure(const GpPointF *points, GpPen *pen, int start, int end,
GpLineCap start_cap, GpCustomLineCap *start_custom, GpLineCap end_cap,
GpCustomLineCap *end_custom, path_list_node_t **last_point)
{
int i;
path_list_node_t *prev_point;
@ -1862,22 +1863,22 @@ static void widen_open_figure(GpPath *path, GpPen *pen, int start, int end,
prev_point = *last_point;
widen_cap(&path->pathdata.Points[start], &path->pathdata.Points[start+1],
pen, pen->startcap, pen->customstart, FALSE, TRUE, last_point);
widen_cap(&points[start], &points[start+1],
pen, start_cap, start_custom, FALSE, TRUE, 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, last_point);
widen_joint(&points[i-1], &points[i],
&points[i+1], pen, last_point);
widen_cap(&path->pathdata.Points[end], &path->pathdata.Points[end-1],
pen, pen->endcap, pen->customend, TRUE, TRUE, last_point);
widen_cap(&points[end], &points[end-1],
pen, end_cap, end_custom, TRUE, TRUE, 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, last_point);
widen_joint(&points[i+1], &points[i],
&points[i-1], pen, last_point);
widen_cap(&path->pathdata.Points[start], &path->pathdata.Points[start+1],
pen, pen->startcap, pen->customstart, TRUE, FALSE, last_point);
widen_cap(&points[start], &points[start+1],
pen, start_cap, start_custom, TRUE, FALSE, last_point);
prev_point->next->type = PathPointTypeStart;
(*last_point)->type |= PathPointTypeCloseSubpath;
@ -1925,6 +1926,111 @@ static void widen_closed_figure(GpPath *path, GpPen *pen, int start, int end,
(*last_point)->type |= PathPointTypeCloseSubpath;
}
static void widen_dashed_figure(GpPath *path, GpPen *pen, int start, int end,
int closed, path_list_node_t **last_point)
{
int i, j;
REAL dash_pos=0.0;
int dash_index=0;
const REAL *dash_pattern;
int dash_count;
GpPointF *tmp_points;
REAL segment_dy;
REAL segment_dx;
REAL segment_length;
REAL segment_pos;
int num_tmp_points=0;
int draw_start_cap=0;
if (end <= start)
return;
dash_pattern = pen->dashes;
dash_count = pen->numdashes;
tmp_points = GdipAlloc((end - start + 2) * sizeof(GpPoint));
if (!tmp_points) return; /* FIXME */
if (!closed)
draw_start_cap = 1;
for (j=start; j <= end; j++)
{
if (j == start)
{
if (closed)
i = end;
else
continue;
}
else
i = j-1;
segment_dy = path->pathdata.Points[j].Y - path->pathdata.Points[i].Y;
segment_dx = path->pathdata.Points[j].X - path->pathdata.Points[i].X;
segment_length = sqrtf(segment_dy*segment_dy + segment_dx*segment_dx);
segment_pos = 0.0;
while (1)
{
if (dash_pos == 0.0)
{
if ((dash_index % 2) == 0)
{
/* start dash */
num_tmp_points = 1;
tmp_points[0].X = path->pathdata.Points[i].X + segment_dx * segment_pos / segment_length;
tmp_points[0].Y = path->pathdata.Points[i].Y + segment_dy * segment_pos / segment_length;
}
else
{
/* end dash */
tmp_points[num_tmp_points].X = path->pathdata.Points[i].X + segment_dx * segment_pos / segment_length;
tmp_points[num_tmp_points].Y = path->pathdata.Points[i].Y + segment_dy * segment_pos / segment_length;
widen_open_figure(tmp_points, pen, 0, num_tmp_points,
draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
LineCapFlat, NULL, last_point);
draw_start_cap = 0;
num_tmp_points = 0;
}
}
if (dash_pattern[dash_index] - dash_pos > segment_length - segment_pos)
{
/* advance to next segment */
if ((dash_index % 2) == 0)
{
tmp_points[num_tmp_points] = path->pathdata.Points[j];
num_tmp_points++;
}
dash_pos += segment_length - segment_pos;
break;
}
else
{
/* advance to next dash in pattern */
segment_pos += dash_pattern[dash_index] - dash_pos;
dash_pos = 0.0;
if (++dash_index == dash_count)
dash_index = 0;
continue;
}
}
}
if (dash_index % 2 == 0 && num_tmp_points != 0)
{
/* last dash overflows last segment */
tmp_points[num_tmp_points] = path->pathdata.Points[end];
widen_open_figure(tmp_points, pen, 0, num_tmp_points,
draw_start_cap ? pen->startcap : LineCapFlat, pen->customstart,
closed ? LineCapFlat : pen->endcap, pen->customend, last_point);
}
GdipFree(tmp_points);
}
GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
REAL flatness)
{
@ -1966,7 +2072,7 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
if (pen->join == LineJoinRound)
FIXME("unimplemented line join %d\n", pen->join);
if (pen->dash != DashStyleSolid)
if (pen->dash != DashStyleSolid && pen->dash != DashStyleCustom)
FIXME("unimplemented dash style %d\n", pen->dash);
if (pen->align != PenAlignmentCenter)
@ -1981,12 +2087,18 @@ GpStatus WINGDIPAPI GdipWidenPath(GpPath *path, GpPen *pen, GpMatrix *matrix,
if ((type&PathPointTypeCloseSubpath) == PathPointTypeCloseSubpath)
{
widen_closed_figure(flat_path, pen, subpath_start, i, &last_point);
if (pen->dash == DashStyleCustom)
widen_dashed_figure(flat_path, pen, subpath_start, i, 1, &last_point);
else
widen_closed_figure(flat_path, pen, subpath_start, i, &last_point);
}
else if (i == flat_path->pathdata.Count-1 ||
(flat_path->pathdata.Types[i+1]&PathPointTypePathTypeMask) == PathPointTypeStart)
{
widen_open_figure(flat_path, pen, subpath_start, i, &last_point);
if (pen->dash == DashStyleCustom)
widen_dashed_figure(flat_path, pen, subpath_start, i, 0, &last_point);
else
widen_open_figure(flat_path->pathdata.Points, pen, subpath_start, i, pen->startcap, pen->customstart, pen->endcap, pen->customend, &last_point);
}
}