From f0d427993c1b9b40f1bc0b77ed9c0433099f2a5d Mon Sep 17 00:00:00 2001 From: Robin Watts Date: Thu, 12 Jan 2012 15:34:30 +0000 Subject: 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. --- fitz/base_geometry.c | 16 ++++++++++++++++ fitz/fitz.h | 21 +++++++++++++++++++-- fitz/res_font.c | 15 ++++++++++++++- fitz/res_path.c | 8 +++++--- 4 files changed, 54 insertions(+), 6 deletions(-) (limited to 'fitz') 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; -- cgit v1.2.3