summaryrefslogtreecommitdiff
path: root/xps
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2012-01-12 15:34:30 +0000
committerRobin Watts <robin.watts@artifex.com>2012-01-12 20:15:09 +0000
commitf0d427993c1b9b40f1bc0b77ed9c0433099f2a5d (patch)
treec89144197a2aafec4dac4a05506dad93e098ebdc /xps
parent269a44d92e2fc15631b86cc0c7135baf2023f312 (diff)
downloadmupdf-f0d427993c1b9b40f1bc0b77ed9c0433099f2a5d.tar.xz
Support proper XPS mitering. (And stroke fixes).
XPS differs from PS/PDF/etc in the way it handles miters; rather than simply converting a miter that's overly long to a bevel, it truncates it at the miter limit. As such it needs to be handled correctly. For clarity, expose new enumerated types for linejoins and linecaps, and use these throughout code. When we upgrade our freetype, we can move to using proper xps mitering in that too. Add new fz_matrix_max_expansion function to return a safer expansion value that works in the case where we scale up in one direction and down in another. In the xps path drawing code, avoid generating unnecessary linetos. Thanks to Zeniko for spotting these and providing implementations.
Diffstat (limited to 'xps')
-rw-r--r--xps/xps_path.c41
1 files changed, 19 insertions, 22 deletions
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;