summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--draw/draw_path.c78
-rw-r--r--fitz/base_geometry.c16
-rw-r--r--fitz/fitz.h21
-rw-r--r--fitz/res_font.c15
-rw-r--r--fitz/res_path.c8
-rw-r--r--pdf/pdf_interpret.c8
-rw-r--r--xps/xps_path.c41
7 files changed, 121 insertions, 66 deletions
diff --git a/draw/draw_path.c b/draw/draw_path.c
index d6f9934b..29614ec5 100644
--- a/draw/draw_path.c
+++ b/draw/draw_path.c
@@ -2,8 +2,6 @@
#define MAX_DEPTH 8
-enum { BUTT = 0, ROUND = 1, SQUARE = 2, TRIANGLE = 3, MITER = 0, BEVEL = 2 };
-
static void
line(fz_gel *gel, fz_matrix *ctm, float x0, float y0, float x1, float y1)
{
@@ -218,7 +216,7 @@ fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c)
{
float miterlimit = s->miterlimit;
float linewidth = s->linewidth;
- int linejoin = s->linejoin;
+ fz_linejoin linejoin = s->linejoin;
float dx0, dy0;
float dx1, dy1;
float dlx0, dly0;
@@ -234,10 +232,20 @@ fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c)
dx1 = c.x - b.x;
dy1 = c.y - b.y;
+ cross = dx1 * dy0 - dx0 * dy1;
+ /* Ensure that cross >= 0 */
+ if (cross < 0)
+ {
+ float tmp;
+ tmp = dx1; dx1 = -dx0; dx0 = -tmp;
+ tmp = dy1; dy1 = -dy0; dy0 = -tmp;
+ cross = -cross;
+ }
+
if (dx0 * dx0 + dy0 * dy0 < FLT_EPSILON)
- linejoin = BEVEL;
+ linejoin = FZ_LINEJOIN_BEVEL;
if (dx1 * dx1 + dy1 * dy1 < FLT_EPSILON)
- linejoin = BEVEL;
+ linejoin = FZ_LINEJOIN_BEVEL;
scale = linewidth / sqrtf(dx0 * dx0 + dy0 * dy0);
dlx0 = dy0 * scale;
@@ -247,36 +255,46 @@ fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c)
dlx1 = dy1 * scale;
dly1 = -dx1 * scale;
- cross = dx1 * dy0 - dx0 * dy1;
-
dmx = (dlx0 + dlx1) * 0.5f;
dmy = (dly0 + dly1) * 0.5f;
dmr2 = dmx * dmx + dmy * dmy;
if (cross * cross < FLT_EPSILON && dx0 * dx1 + dy0 * dy1 >= 0)
- linejoin = BEVEL;
+ linejoin = FZ_LINEJOIN_BEVEL;
- if (linejoin == MITER)
+ if (linejoin == FZ_LINEJOIN_MITER)
if (dmr2 * miterlimit * miterlimit < linewidth * linewidth)
- linejoin = BEVEL;
+ linejoin = FZ_LINEJOIN_BEVEL;
- if (linejoin == BEVEL)
+ 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 == MITER)
+ if (linejoin == FZ_LINEJOIN_MITER)
+ {
+ scale = linewidth * linewidth / dmr2;
+ 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);
+ }
+
+ /* XPS miter joins are clipped at miterlength, rather than simply
+ * being converted to bevelled joins. */
+ if (linejoin == FZ_LINEJOIN_MITER_XPS)
{
scale = linewidth * linewidth / dmr2;
dmx *= scale;
dmy *= scale;
- if (cross < 0)
+ if (cross == 0)
{
+ 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 - dlx1, b.y - dly1);
- fz_add_line(s, b.x + dlx1, b.y + dly1, b.x + dmx, b.y + dmy);
- fz_add_line(s, b.x + dmx, b.y + dmy, b.x + dlx0, b.y + dly0);
}
else
{
@@ -286,23 +304,15 @@ fz_add_line_join(struct sctx *s, fz_point a, fz_point b, fz_point c)
}
}
- if (linejoin == ROUND)
+ if (linejoin == FZ_LINEJOIN_ROUND)
{
- if (cross < 0)
- {
- fz_add_line(s, b.x - dlx0, b.y - dly0, b.x - dlx1, b.y - dly1);
- fz_add_arc(s, b.x, b.y, dlx1, dly1, dlx0, dly0);
- }
- else
- {
- 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);
- }
+ 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);
}
}
static void
-fz_add_line_cap(struct sctx *s, fz_point a, fz_point b, int linecap)
+fz_add_line_cap(struct sctx *s, fz_point a, fz_point b, fz_linecap linecap)
{
float flatness = s->flatness;
float linewidth = s->linewidth;
@@ -314,10 +324,10 @@ fz_add_line_cap(struct sctx *s, fz_point a, fz_point b, int linecap)
float dlx = dy * scale;
float dly = -dx * scale;
- if (linecap == BUTT)
+ if (linecap == FZ_LINECAP_BUTT)
fz_add_line(s, b.x - dlx, b.y - dly, b.x + dlx, b.y + dly);
- if (linecap == ROUND)
+ if (linecap == FZ_LINECAP_ROUND)
{
int i;
int n = ceilf((float)M_PI / (2.0f * (float)M_SQRT2 * sqrtf(flatness / linewidth)));
@@ -337,7 +347,7 @@ fz_add_line_cap(struct sctx *s, fz_point a, fz_point b, int linecap)
fz_add_line(s, ox, oy, b.x + dlx, b.y + dly);
}
- if (linecap == SQUARE)
+ if (linecap == FZ_LINECAP_SQUARE)
{
fz_add_line(s, b.x - dlx, b.y - dly,
b.x - dlx - dly, b.y - dly + dlx);
@@ -347,7 +357,7 @@ fz_add_line_cap(struct sctx *s, fz_point a, fz_point b, int linecap)
b.x + dlx, b.y + dly);
}
- if (linecap == TRIANGLE)
+ if (linecap == FZ_LINECAP_TRIANGLE)
{
float mx = -dly;
float my = dlx;
@@ -382,7 +392,7 @@ fz_add_line_dot(struct sctx *s, fz_point a)
}
static void
-fz_stroke_flush(struct sctx *s, int start_cap, int end_cap)
+fz_stroke_flush(struct sctx *s, fz_linecap start_cap, fz_linecap end_cap)
{
if (s->sn == 2)
{
@@ -413,7 +423,7 @@ fz_stroke_lineto(struct sctx *s, fz_point cur)
if (dx * dx + dy * dy < FLT_EPSILON)
{
- if (s->cap == ROUND || s->dash_list)
+ if (s->cap == FZ_LINECAP_ROUND || s->dash_list)
s->dot = 1;
return;
}
@@ -586,7 +596,7 @@ fz_flatten_stroke_path(fz_gel *gel, fz_path *path, fz_stroke_state *stroke, fz_m
}
static void
-fz_dash_moveto(struct sctx *s, fz_point a, int start_cap, int end_cap)
+fz_dash_moveto(struct sctx *s, fz_point a, fz_linecap start_cap, fz_linecap end_cap)
{
s->toggle = 1;
s->offset = 0;
diff --git a/fitz/base_geometry.c b/fitz/base_geometry.c
index 3269605d..e8d9032f 100644
--- a/fitz/base_geometry.c
+++ b/fitz/base_geometry.c
@@ -121,6 +121,22 @@ fz_matrix_expansion(fz_matrix m)
return sqrtf(fabsf(m.a * m.d - m.b * m.c));
}
+float
+fz_matrix_max_expansion(fz_matrix m)
+{
+ float max = fabsf(m.a);
+ float x = fabsf(m.b);
+ if (max < x)
+ max = x;
+ x = fabsf(m.c);
+ if (max < x)
+ max = x;
+ x = fabsf(m.d);
+ if (max < x)
+ max = x;
+ return max;
+}
+
fz_point
fz_transform_point(fz_matrix m, fz_point p)
{
diff --git a/fitz/fitz.h b/fitz/fitz.h
index 6aebdf61..bfc4723a 100644
--- a/fitz/fitz.h
+++ b/fitz/fitz.h
@@ -520,6 +520,7 @@ fz_matrix fz_translate(float tx, float ty);
fz_matrix fz_invert_matrix(fz_matrix m);
int fz_is_rectilinear(fz_matrix m);
float fz_matrix_expansion(fz_matrix m);
+float fz_matrix_max_expansion(fz_matrix m);
fz_bbox fz_round_rect(fz_rect r);
fz_bbox fz_intersect_bbox(fz_bbox a, fz_bbox b);
@@ -1102,6 +1103,22 @@ typedef enum fz_path_item_kind_e
FZ_CLOSE_PATH
} fz_path_item_kind;
+typedef enum fz_linecap_e
+{
+ FZ_LINECAP_BUTT = 0,
+ FZ_LINECAP_ROUND = 1,
+ FZ_LINECAP_SQUARE = 2,
+ FZ_LINECAP_TRIANGLE = 3
+} fz_linecap;
+
+typedef enum fz_linejoin_e
+{
+ FZ_LINEJOIN_MITER = 0,
+ FZ_LINEJOIN_ROUND = 1,
+ FZ_LINEJOIN_BEVEL = 2,
+ FZ_LINEJOIN_MITER_XPS = 3
+} fz_linejoin;
+
union fz_path_item_s
{
fz_path_item_kind k;
@@ -1116,8 +1133,8 @@ struct fz_path_s
struct fz_stroke_state_s
{
- int start_cap, dash_cap, end_cap;
- int linejoin;
+ fz_linecap start_cap, dash_cap, end_cap;
+ fz_linejoin linejoin;
float linewidth;
float miterlimit;
float dash_phase;
diff --git a/fitz/res_font.c b/fitz/res_font.c
index c3e2e0bd..4a1c9dfa 100644
--- a/fitz/res_font.c
+++ b/fitz/res_font.c
@@ -449,6 +449,7 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix tr
FT_Glyph glyph;
FT_BitmapGlyph bitmap;
fz_pixmap *pixmap;
+ FT_Stroker_LineJoin line_join;
trm = fz_adjust_ft_glyph_width(ctx, font, gid, trm);
@@ -485,7 +486,19 @@ fz_render_ft_stroked_glyph(fz_context *ctx, fz_font *font, int gid, fz_matrix tr
return NULL;
}
- FT_Stroker_Set(stroker, linewidth, state->start_cap, state->linejoin, state->miterlimit * 65536);
+#if 0
+ line_join = state->linejoin == FZ_LINEJOIN_MITER ? FT_STROKER_LINEJOIN_MITER_FIXED :
+ state->linejoin == FZ_LINEJOIN_ROUND ? FT_STROKER_LINEJOIN_ROUND :
+ state->linejoin == FZ_LINEJOIN_BEVEL ? FT_STROKER_LINEJOIN_BEVEL :
+ FT_STROKER_LINEJOIN_MITER_VARIABLE;
+#else
+ /* Until we upgrade freetype */
+ line_join = state->linejoin == FZ_LINEJOIN_MITER ? FT_STROKER_LINEJOIN_MITER :
+ state->linejoin == FZ_LINEJOIN_ROUND ? FT_STROKER_LINEJOIN_ROUND :
+ state->linejoin == FZ_LINEJOIN_BEVEL ? FT_STROKER_LINEJOIN_BEVEL :
+ FT_STROKER_LINEJOIN_MITER;
+#endif
+ FT_Stroker_Set(stroker, linewidth, state->start_cap, line_join, state->miterlimit * 65536);
fterr = FT_Get_Glyph(face->glyph, &glyph);
if (fterr)
diff --git a/fitz/res_path.c b/fitz/res_path.c
index d8838899..a062f813 100644
--- a/fitz/res_path.c
+++ b/fitz/res_path.c
@@ -189,9 +189,11 @@ fz_bound_path(fz_path *path, fz_stroke_state *stroke, fz_matrix ctm)
if (stroke)
{
- float miterlength = stroke->miterlimit;
- float linewidth = stroke->linewidth;
- float expand = MAX(miterlength, linewidth) * 0.5f;
+ float expand = stroke->linewidth;
+ if (expand == 0)
+ expand = 1.0f;
+ expand *= fz_matrix_max_expansion(ctm);
+ expand *= stroke->miterlimit;
r.x0 -= expand;
r.y0 -= expand;
r.x1 += expand;
diff --git a/pdf/pdf_interpret.c b/pdf/pdf_interpret.c
index fe0e1ce8..0976912e 100644
--- a/pdf/pdf_interpret.c
+++ b/pdf/pdf_interpret.c
@@ -818,10 +818,10 @@ pdf_init_gstate(pdf_gstate *gs, fz_matrix ctm)
gs->ctm = ctm;
gs->clip_depth = 0;
- gs->stroke_state.start_cap = 0;
- gs->stroke_state.dash_cap = 0;
- gs->stroke_state.end_cap = 0;
- gs->stroke_state.linejoin = 0;
+ gs->stroke_state.start_cap = FZ_LINECAP_BUTT;
+ gs->stroke_state.dash_cap = FZ_LINECAP_BUTT;
+ gs->stroke_state.end_cap = FZ_LINECAP_BUTT;
+ gs->stroke_state.linejoin = FZ_LINEJOIN_MITER;
gs->stroke_state.linewidth = 1;
gs->stroke_state.miterlimit = 10;
gs->stroke_state.dash_phase = 0;
diff --git a/xps/xps_path.c b/xps/xps_path.c
index 402ca532..8b66e1ff 100644
--- a/xps/xps_path.c
+++ b/xps/xps_path.c
@@ -39,6 +39,9 @@ fz_currentpoint(fz_path *path)
* line segments. We cannot use the fz_arc function because they only draw
* circular arcs, we need to transform the line to make them elliptical but
* without transforming the line width.
+ *
+ * We are guaranteed that on entry the point is at the point that would be
+ * calculated by th0, and on exit, a point is generated for us at th0.
*/
static void
xps_draw_arc_segment(fz_context *doc, fz_path *path, fz_matrix mtx, float th0, float th1, int iscw)
@@ -53,40 +56,24 @@ xps_draw_arc_segment(fz_context *doc, fz_path *path, fz_matrix mtx, float th0, f
if (iscw)
{
- p.x = cosf(th0);
- p.y = sinf(th0);
- p = fz_transform_point(mtx, p);
- fz_lineto(doc, path, p.x, p.y);
- for (t = th0; t < th1; t += d)
+ for (t = th0 + d; t < th1 - d/2; t += d)
{
p.x = cosf(t);
p.y = sinf(t);
p = fz_transform_point(mtx, p);
fz_lineto(doc, path, p.x, p.y);
}
- p.x = cosf(th1);
- p.y = sinf(th1);
- p = fz_transform_point(mtx, p);
- fz_lineto(doc, path, p.x, p.y);
}
else
{
th0 += (float)M_PI * 2;
- p.x = cosf(th0);
- p.y = sinf(th0);
- p = fz_transform_point(mtx, p);
- fz_lineto(doc, path, p.x, p.y);
- for (t = th0; t > th1; t -= d)
+ for (t = th0 - d; t > th1 + d/2; t -= d)
{
p.x = cosf(t);
p.y = sinf(t);
p = fz_transform_point(mtx, p);
fz_lineto(doc, path, p.x, p.y);
}
- p.x = cosf(th1);
- p.y = sinf(th1);
- p = fz_transform_point(mtx, p);
- fz_lineto(doc, path, p.x, p.y);
}
}
@@ -106,6 +93,16 @@ angle_between(const fz_point u, const fz_point v)
return sign * acosf(t);
}
+/* Some explaination of the parameters here is warranted. See:
+ * http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes
+ * Add an arc segment to path, that describes a section of an elliptical arc
+ * from the current point of path to (point_x,point_y), such that:
+ * the arc segment is taken from an elliptical arc of semi major radius
+ * size_x, semi minor radius size_y, where the semi major axis of the
+ * ellipse is rotated by rotation_angle.
+ * if is_large_arc, then the arc segment is selected to be > 180 degrees.
+ * if is_clockwise, then the arc sweeps clockwise.
+ */
static void
xps_draw_arc(fz_context *doc, fz_path *path,
float size_x, float size_y, float rotation_angle,
@@ -884,12 +881,12 @@ xps_parse_path(xps_document *doc, fz_matrix ctm, char *base_uri, xps_resource *d
stroke.dash_cap = xps_parse_line_cap(stroke_dash_cap_att);
stroke.end_cap = xps_parse_line_cap(stroke_end_line_cap_att);
- stroke.linejoin = 0;
+ stroke.linejoin = FZ_LINEJOIN_MITER_XPS;
if (stroke_line_join_att)
{
- if (!strcmp(stroke_line_join_att, "Miter")) stroke.linejoin = 0;
- if (!strcmp(stroke_line_join_att, "Round")) stroke.linejoin = 1;
- if (!strcmp(stroke_line_join_att, "Bevel")) stroke.linejoin = 2;
+ if (!strcmp(stroke_line_join_att, "Miter")) stroke.linejoin = FZ_LINEJOIN_MITER_XPS;
+ if (!strcmp(stroke_line_join_att, "Round")) stroke.linejoin = FZ_LINEJOIN_ROUND;
+ if (!strcmp(stroke_line_join_att, "Bevel")) stroke.linejoin = FZ_LINEJOIN_BEVEL;
}
stroke.miterlimit = 10;