From 93ec9fcda7fdc74284c9ffe03915760650c02670 Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Thu, 9 Nov 2017 16:48:39 +0000 Subject: Fix potential problem with null path segments leaving dots. When stroking paths if we meet segments of 0 length, we can't determine a direction, thus start/end caps are omitted. Line widths are irrelevant, and we thus render nothing. (Note that moves on their own do NOT count as a line segment). The exception to this is where we are using round caps, whereupon whatever direction the path is taken to have, the appearance will be the same - and this we render the segment as a dot. We have code in the renderer already to do this, but it looks to me like it could be fooled into leaving a dot by us first doing a move, a lineto the same point, and then a lineto to somewhere else. The current code sets the 'dot' value to 1 when it detects the degenerate line, and doesn't reset when it meets a non-degenerate line later. Accordingly I've changed the code here to account for such a circumstance. This produces no diffs in the cluster testing, but seems more correct to me. --- source/fitz/draw-path.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) (limited to 'source/fitz/draw-path.c') diff --git a/source/fitz/draw-path.c b/source/fitz/draw-path.c index 2c3d8e37..09cb06db 100644 --- a/source/fitz/draw-path.c +++ b/source/fitz/draw-path.c @@ -305,6 +305,12 @@ fz_flatten_fill_path(fz_context *ctx, fz_rasterizer *rast, const fz_path *path, return fz_is_empty_irect(fz_intersect_irect(bbox, &local_bbox)); } +enum { + ONLY_MOVES = 0, + NON_NULL_LINE = 1, + NULL_LINE +}; + typedef struct sctx { fz_rasterizer *rast; @@ -720,10 +726,8 @@ fz_stroke_flush(fz_context *ctx, sctx *s, fz_linecap start_cap, fz_linecap end_c fz_add_line_cap(ctx, s, s->beg[1].x, s->beg[1].y, s->beg[0].x, s->beg[0].y, start_cap, 2); fz_add_line_cap(ctx, s, s->seg[0].x, s->seg[0].y, s->seg[1].x, s->seg[1].y, end_cap, 0); } - else if (s->dot) - { + else if (s->dot == NULL_LINE) fz_add_line_dot(ctx, s, s->beg[0].x, s->beg[0].y); - } fz_gap_rasterizer(ctx, s->rast); } @@ -735,7 +739,7 @@ fz_stroke_moveto(fz_context *ctx, void *s_, float x, float y) s->seg[0].x = s->beg[0].x = x; s->seg[0].y = s->beg[0].y = y; s->sn = 1; - s->dot = 0; + s->dot = ONLY_MOVES; s->from_bezier = 0; } @@ -750,10 +754,11 @@ fz_stroke_lineto(fz_context *ctx, sctx *s, float x, float y, int from_bezier) if (dx * dx + dy * dy < FLT_EPSILON) { - if (s->cap == FZ_LINECAP_ROUND || s->dash_list) - s->dot = 1; + if (s->dot == ONLY_MOVES && (s->cap == FZ_LINECAP_ROUND || s->dash_list)) + s->dot = NULL_LINE; return; } + s->dot = NON_NULL_LINE; if (s->sn == 2) fz_add_line_join(ctx, s, s->seg[0].x, s->seg[0].y, ox, oy, x, y, s->from_bezier & from_bezier); @@ -805,12 +810,12 @@ fz_stroke_closepath(fz_context *ctx, sctx *s) else fz_add_line_join(ctx, s, s->seg[1].x, s->seg[1].y, s->beg[0].x, s->beg[0].y, s->beg[1].x, s->beg[1].y, 0); } - else if (s->dot) + else if (s->dot == NULL_LINE) fz_add_line_dot(ctx, s, s->beg[0].x, s->beg[0].y); s->seg[0] = s->beg[0]; s->sn = 1; - s->dot = 0; + s->dot = ONLY_MOVES; s->from_bezier = 0; fz_gap_rasterizer(ctx, s->rast); @@ -1409,7 +1414,7 @@ do_flatten_stroke(fz_context *ctx, fz_rasterizer *rast, const fz_path *path, con s.linewidth = linewidth * 0.5f; /* hairlines use a different value from the path value */ s.miterlimit = stroke->miterlimit; s.sn = 0; - s.dot = 0; + s.dot = ONLY_MOVES; s.toggle = 0; s.offset = 0; s.phase = 0; -- cgit v1.2.3