summaryrefslogtreecommitdiff
path: root/draw
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-04-18 16:24:57 +0100
committerRobin Watts <robin.watts@artifex.com>2012-04-19 00:37:47 +0100
commit7aa46e79f2f4994ec94aa94d4a1129e10b6cbd4d (patch)
treecffeb572b7c1e06ba44087bbd9ee8e56ca178152 /draw
parentab29b6831c384048c1011e72dc2a061ac4e66927 (diff)
downloadmupdf-7aa46e79f2f4994ec94aa94d4a1129e10b6cbd4d.tar.xz
Bug 692990: Fix 'underjoin' of strokes.
See Bug 688655 for analysis of what we SHOULD be doing. The code changes to do this are actually quite small. Essentially, when we join we only draw the 'top' (or 'outer') join in a join dependent way. The 'under' join was always joined as a bevel before as this was easy. This produces bad effects when the lines have a significant angle between them and a large linewidth. The correct (i.e. matching Acrobat and others) way to work is to join the bottom of the line via the centre point. The sole exception to this is when drawing under beziers, as we don't want to make our approximation-by-lines obvious. All fixed in this patch.
Diffstat (limited to 'draw')
-rw-r--r--draw/draw_path.c46
1 files changed, 28 insertions, 18 deletions
diff --git a/draw/draw_path.c b/draw/draw_path.c
index 2ef8cf3a..458ce349 100644
--- a/draw/draw_path.c
+++ b/draw/draw_path.c
@@ -135,6 +135,7 @@ struct sctx
fz_point seg[2];
int sn, bn;
int dot;
+ int from_bezier;
float *dash_list;
float dash_phase;
@@ -212,7 +213,7 @@ fz_add_line_stroke(struct sctx *s, fz_point a, fz_point b)
}
static void
-fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c)
+fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c, int join_under)
{
float miterlimit = s->miterlimit;
float linewidth = s->linewidth;
@@ -265,6 +266,16 @@ fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c)
if (cross * cross < FLT_EPSILON && dx0 * dx1 + dy0 * dy1 >= 0)
linejoin = FZ_LINEJOIN_BEVEL;
+ if (join_under)
+ {
+ fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0);
+ }
+ else
+ {
+ fz_add_line(s, b.x + dlx1, b.y + dly1, b.x, b.y);
+ fz_add_line(s, b.x, b.y, b.x + dlx0, b.y + dly0);
+ }
+
/* XPS miter joins are clipped at miterlength, rather than simply
* being converted to bevelled joins. */
if (linejoin == FZ_LINEJOIN_MITER_XPS)
@@ -285,7 +296,6 @@ fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c)
t1x = b.x - dmx + k * (dmx - dlx1);
t1y = b.y - dmy + k * (dmy - dly1);
- fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0);
fz_add_line(s, b.x - dlx0, b.y - dly0, t0x, t0y);
fz_add_line(s, t0x, t0y, t1x, t1y);
fz_add_line(s, t1x, t1y, b.x - dlx1, b.y - dly1);
@@ -301,7 +311,6 @@ fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c)
dmx *= scale;
dmy *= scale;
- fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0);
fz_add_line(s, b.x - dlx0, b.y - dly0, b.x - dmx, b.y - dmy);
fz_add_line(s, b.x - dmx, b.y - dmy, b.x - dlx1, b.y - dly1);
}
@@ -309,12 +318,10 @@ fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c)
if (linejoin == FZ_LINEJOIN_BEVEL)
{
fz_add_line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1);
- fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0);
}
if (linejoin == FZ_LINEJOIN_ROUND)
{
- fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dlx0, b.y + dly0);
fz_add_arc(s, b.x, b.y, -dlx0, -dly0, -dlx1, -dly1);
}
}
@@ -421,10 +428,11 @@ fz_stroke_moveto(struct sctx *s, fz_point cur)
s->sn = 1;
s->bn = 1;
s->dot = 0;
+ s->from_bezier = 0;
}
static void
-fz_stroke_lineto(struct sctx *s, fz_point cur)
+fz_stroke_lineto(struct sctx *s, fz_point cur, int from_bezier)
{
float dx = cur.x - s->seg[s->sn-1].x;
float dy = cur.y - s->seg[s->sn-1].y;
@@ -440,10 +448,11 @@ fz_stroke_lineto(struct sctx *s, fz_point cur)
if (s->sn == 2)
{
- fz_add_line_join(s, s->seg[0], s->seg[1], cur);
+ fz_add_line_join(s, s->seg[0], s->seg[1], cur, s->from_bezier & from_bezier);
s->seg[0] = s->seg[1];
s->seg[1] = cur;
}
+ s->from_bezier = from_bezier;
if (s->sn == 1)
s->seg[s->sn++] = cur;
@@ -456,11 +465,11 @@ fz_stroke_closepath(struct sctx *s)
{
if (s->sn == 2)
{
- fz_stroke_lineto(s, s->beg[0]);
+ fz_stroke_lineto(s, s->beg[0], 0);
if (s->seg[1].x == s->beg[0].x && s->seg[1].y == s->beg[0].y)
- fz_add_line_join(s, s->seg[0], s->beg[0], s->beg[1]);
+ fz_add_line_join(s, s->seg[0], s->beg[0], s->beg[1], 0);
else
- fz_add_line_join(s, s->seg[1], s->beg[0], s->beg[1]);
+ fz_add_line_join(s, s->seg[1], s->beg[0], s->beg[1], 0);
}
else if (s->dot)
{
@@ -471,6 +480,7 @@ fz_stroke_closepath(struct sctx *s)
s->bn = 1;
s->sn = 1;
s->dot = 0;
+ s->from_bezier = 0;
}
static void
@@ -498,7 +508,7 @@ fz_stroke_bezier(struct sctx *s,
fz_point p;
p.x = xd;
p.y = yd;
- fz_stroke_lineto(s, p);
+ fz_stroke_lineto(s, p, 1);
return;
}
@@ -579,7 +589,7 @@ fz_flatten_stroke_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_m
case FZ_LINETO:
p1.x = path->items[i++].v;
p1.y = path->items[i++].v;
- fz_stroke_lineto(&s, p1);
+ fz_stroke_lineto(&s, p1, 0);
p0 = p1;
break;
@@ -630,7 +640,7 @@ fz_dash_moveto(struct sctx *s, fz_point a, fz_linecap start_cap, fz_linecap end_
}
static void
-fz_dash_lineto(struct sctx *s, fz_point b, int dash_cap)
+fz_dash_lineto(struct sctx *s, fz_point b, int dash_cap, int from_bezier)
{
float dx, dy;
float total, used, ratio;
@@ -652,7 +662,7 @@ fz_dash_lineto(struct sctx *s, fz_point b, int dash_cap)
if (s->toggle)
{
- fz_stroke_lineto(s, m);
+ fz_stroke_lineto(s, m, from_bezier);
}
else
{
@@ -674,7 +684,7 @@ fz_dash_lineto(struct sctx *s, fz_point b, int dash_cap)
if (s->toggle)
{
- fz_stroke_lineto(s, b);
+ fz_stroke_lineto(s, b, from_bezier);
}
}
@@ -704,7 +714,7 @@ fz_dash_bezier(struct sctx *s,
fz_point p;
p.x = xd;
p.y = yd;
- fz_dash_lineto(s, p, dash_cap);
+ fz_dash_lineto(s, p, dash_cap, 1);
return;
}
@@ -794,7 +804,7 @@ fz_flatten_dash_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_mat
case FZ_LINETO:
p1.x = path->items[i++].v;
p1.y = path->items[i++].v;
- fz_dash_lineto(&s, p1, stroke->dash_cap);
+ fz_dash_lineto(&s, p1, stroke->dash_cap, 0);
p0 = p1;
break;
@@ -810,7 +820,7 @@ fz_flatten_dash_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_mat
break;
case FZ_CLOSE_PATH:
- fz_dash_lineto(&s, beg, stroke->dash_cap);
+ fz_dash_lineto(&s, beg, stroke->dash_cap, 0);
p0 = p1 = beg;
break;
}