Vincent Povirk : gdiplus: Implement GdipWidenPath for custom dashed lines.

Alexandre Julliard julliard at winehq.org
Thu Oct 24 13:18:56 CDT 2013


Module: wine
Branch: master
Commit: 1c35dd6cb422c575a5cbfb3d2dd402a1cd9a1f23
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=1c35dd6cb422c575a5cbfb3d2dd402a1cd9a1f23

Author: Vincent Povirk <vincent at codeweavers.com>
Date:   Wed Oct 23 13:05:50 2013 -0500

gdiplus: Implement GdipWidenPath for custom dashed lines.

---

 dlls/gdiplus/graphicspath.c |  142 ++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 127 insertions(+), 15 deletions(-)

diff --git a/dlls/gdiplus/graphicspath.c b/dlls/gdiplus/graphicspath.c
index 62f8490..8fa3cc0 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; 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);
             }
         }
 




More information about the wine-cvs mailing list