diff options
author | Robin Watts <robin.watts@artifex.com> | 2015-04-01 18:25:23 +0100 |
---|---|---|
committer | Robin Watts <robin.watts@artifex.com> | 2015-04-06 19:32:01 +0100 |
commit | 05e491cddf81813977141e6c89a032fd507d8cb1 (patch) | |
tree | 17155acd2db89204f93546c94984d17b0393fd57 | |
parent | 928939c346e12ecce75d8de573b13c411f1bebd5 (diff) | |
download | mupdf-05e491cddf81813977141e6c89a032fd507d8cb1.tar.xz |
Bug 694367: Attempt to avoid dropouts of rectangles.
This is not a complete general fix for features dropping out of
rendered line art, but merely a fix for one of the more common
cases.
When rendering rectangles (currently, specifically only those
rectangles that are actually defined as rectangles within the
path structure), if they are axis aligned, then ensure that they
always fill the subpixel line they are on.
-rw-r--r-- | source/fitz/draw-edge.c | 45 | ||||
-rw-r--r-- | source/fitz/draw-imp.h | 1 | ||||
-rw-r--r-- | source/fitz/draw-path.c | 39 |
3 files changed, 84 insertions, 1 deletions
diff --git a/source/fitz/draw-edge.c b/source/fitz/draw-edge.c index a4c0d02e..4309b858 100644 --- a/source/fitz/draw-edge.c +++ b/source/fitz/draw-edge.c @@ -425,6 +425,51 @@ fz_insert_gel(fz_context *ctx, fz_gel *gel, float fx0, float fy0, float fx1, flo fz_insert_gel_raw(ctx, gel, x0, y0, x1, y1); } +void +fz_insert_gel_rect(fz_context *ctx, fz_gel *gel, float fx0, float fy0, float fx1, float fy1) +{ + int x0, y0, x1, y1; + fz_aa_context *ctxaa = ctx->aa; + + if (fx0 <= fx1) + { + fx0 = floorf(fx0 * fz_aa_hscale); + fx1 = ceilf(fx1 * fz_aa_hscale); + } + else + { + fx0 = ceilf(fx0 * fz_aa_hscale); + fx1 = floorf(fx1 * fz_aa_hscale); + } + if (fy0 <= fy1) + { + fy0 = floorf(fy0 * fz_aa_vscale); + fy1 = ceilf(fy1 * fz_aa_vscale); + } + else + { + fy0 = ceilf(fy0 * fz_aa_vscale); + fy1 = floorf(fy1 * fz_aa_vscale); + } + + fx0 = fz_clamp(fx0, gel->clip.x0, gel->clip.x1); + fx1 = fz_clamp(fx1, gel->clip.x0, gel->clip.x1); + fy0 = fz_clamp(fy0, gel->clip.y0, gel->clip.y1); + fy1 = fz_clamp(fy1, gel->clip.y0, gel->clip.y1); + + /* Call fz_clamp so that clamping is done in the float domain, THEN + * cast down to an int. Calling fz_clampi causes problems due to the + * implicit cast down from float to int of the first argument + * over/underflowing and flipping sign at extreme values. */ + x0 = (int)fz_clamp(fx0, BBOX_MIN * fz_aa_hscale, BBOX_MAX * fz_aa_hscale); + y0 = (int)fz_clamp(fy0, BBOX_MIN * fz_aa_vscale, BBOX_MAX * fz_aa_vscale); + x1 = (int)fz_clamp(fx1, BBOX_MIN * fz_aa_hscale, BBOX_MAX * fz_aa_hscale); + y1 = (int)fz_clamp(fy1, BBOX_MIN * fz_aa_vscale, BBOX_MAX * fz_aa_vscale); + + fz_insert_gel_raw(ctx, gel, x1, y0, x1, y1); + fz_insert_gel_raw(ctx, gel, x0, y1, x0, y0); +} + static int cmpedge(const void *va, const void *vb) { diff --git a/source/fitz/draw-imp.h b/source/fitz/draw-imp.h index ed457d34..3a1ddbd2 100644 --- a/source/fitz/draw-imp.h +++ b/source/fitz/draw-imp.h @@ -9,6 +9,7 @@ typedef struct fz_gel_s fz_gel; fz_gel *fz_new_gel(fz_context *ctx); void fz_insert_gel(fz_context *ctx, fz_gel *gel, float x0, float y0, float x1, float y1); +void fz_insert_gel_rect(fz_context *ctx, fz_gel *gel, float x0, float y0, float x1, float y1); void fz_reset_gel(fz_context *ctx, fz_gel *gel, const fz_irect *clip); void fz_sort_gel(fz_context *ctx, fz_gel *gel); fz_irect *fz_bound_gel(fz_context *ctx, const fz_gel *gel, fz_irect *bbox); diff --git a/source/fitz/draw-path.c b/source/fitz/draw-path.c index 2e751222..2c0caa50 100644 --- a/source/fitz/draw-path.c +++ b/source/fitz/draw-path.c @@ -168,13 +168,50 @@ flatten_close(fz_context *ctx, void *arg_) arg->c.y = arg->b.y; } +static void +flatten_rectto(fz_context *ctx, void *arg_, float x0, float y0, float x1, float y1) +{ + flatten_arg *arg = (flatten_arg *)arg_; + const fz_matrix *ctm = arg->ctm; + + flatten_moveto(ctx, arg_, x0, y0); + /* In the case where we have an axis aligned rectangle, do some + * horrid antidropout stuff. */ + if (ctm->b == 0 && ctm->c == 0) + { + float tx0 = ctm->a * x0 + ctm->e; + float ty0 = ctm->d * y0 + ctm->f; + float tx1 = ctm->a * x1 + ctm->e; + float ty1 = ctm->d * y1 + ctm->f; + fz_insert_gel_rect(ctx, arg->gel, tx0, ty0, tx1, ty1); + } + else if (ctm->a == 0 && ctm->d == 0) + { + float tx0 = ctm->c * y0 + ctm->e; + float ty0 = ctm->b * x0 + ctm->f; + float tx1 = ctm->c * y1 + ctm->e; + float ty1 = ctm->b * x1 + ctm->f; + fz_insert_gel_rect(ctx, arg->gel, tx0, ty1, tx1, ty0); + } + else + { + flatten_lineto(ctx, arg_, x1, y0); + flatten_lineto(ctx, arg_, x1, y1); + flatten_lineto(ctx, arg_, x0, y1); + flatten_close(ctx, arg_); + } +} + static const fz_path_processor flatten_proc = { flatten_moveto, flatten_lineto, flatten_curveto, flatten_close, - flatten_quadto + flatten_quadto, + NULL, + NULL, + flatten_rectto }; void |