summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobin Watts <robin.watts@artifex.com>2015-04-01 18:25:23 +0100
committerRobin Watts <robin.watts@artifex.com>2015-04-06 19:32:01 +0100
commit05e491cddf81813977141e6c89a032fd507d8cb1 (patch)
tree17155acd2db89204f93546c94984d17b0393fd57
parent928939c346e12ecce75d8de573b13c411f1bebd5 (diff)
downloadmupdf-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.c45
-rw-r--r--source/fitz/draw-imp.h1
-rw-r--r--source/fitz/draw-path.c39
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