diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c index 62f84907101..8fa3cc0d808 100644 --- a/dlls/gdiplus/graphicspath.c +++ b/dlls/gdiplus/graphicspath.c @@ -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; ipathdata.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); } }