[gs-cvs] rev 7213 - trunk/gs/src
leonardo at ghostscript.com
leonardo at ghostscript.com
Sun Nov 19 06:36:43 PST 2006
Author: leonardo
Date: 2006-11-19 06:36:42 -0800 (Sun, 19 Nov 2006)
New Revision: 7213
Modified:
trunk/gs/src/gxpath.h
trunk/gs/src/gxpcopy.c
trunk/gs/src/gxpflat.c
trunk/gs/src/gxstroke.c
trunk/gs/src/gzpath.h
Log:
Fix (filling) : Very long lines sometimes painted in a wrong direction.
DETAILS :
Debugged with CET 11-14.PS : (next 3E9 dup moveto 1 dup lto fini) .
A fixed overflow happened in gxstroke.c .
To work around it we subdivide long segments into 2 parts
before applying the stroking algorithm.
1. The hew function gx_path_has_long_segments checks for long segments.
2. The function gx_path_copy_reducing now breaks long segments into 2 parts.
3. gxstroke.c is changed to apply (1) and (2).
4. Note that (2) also affects the filling algorithm,
rather it is not related to the test case.
It had problems with long segments also,
at least gx_default_fill_trapezoid must not be called with
very long setgments, because it computes coordinate differences.
EXPECTED DIFFERENCES :
None.
Modified: trunk/gs/src/gxpath.h
===================================================================
--- trunk/gs/src/gxpath.h 2006-11-18 21:44:30 UTC (rev 7212)
+++ trunk/gs/src/gxpath.h 2006-11-19 14:36:42 UTC (rev 7213)
@@ -195,6 +195,7 @@
gx_path_is_void(const gx_path *), /* no segments */
gx_path_is_null(const gx_path *), /* nothing at all */
gx_path__check_curves(const gx_path * ppath, gx_path_copy_options options, fixed fixed_flat);
+ gx_path_has_long_segments(const gx_path * ppath);
typedef enum {
prt_none = 0,
prt_open = 1, /* only 3 sides */
Modified: trunk/gs/src/gxpcopy.c
===================================================================
--- trunk/gs/src/gxpcopy.c 2006-11-18 21:44:30 UTC (rev 7212)
+++ trunk/gs/src/gxpcopy.c 2006-11-19 14:36:42 UTC (rev 7213)
@@ -26,6 +26,35 @@
/* Forward declarations */
private void adjust_point_to_tangent(segment *, const segment *,
const gs_fixed_point *);
+
+private inline int
+break_line_if_long(gx_path *ppath, const segment *pseg)
+{
+ fixed x0 = ppath->position.x;
+ fixed y0 = ppath->position.y;
+
+ if (gx_check_fixed_diff_overflow(pseg->pt.x, x0) ||
+ gx_check_fixed_diff_overflow(pseg->pt.y, y0)) {
+ fixed x, y;
+
+ if (gx_check_fixed_sum_overflow(pseg->pt.x, x0))
+ x = (pseg->pt.x >> 1) + (x0 >> 1);
+ else
+ x = (pseg->pt.x + x0) >> 1;
+ if (gx_check_fixed_sum_overflow(pseg->pt.y, y0))
+ y = (pseg->pt.y >> 1) + (y0 >> 1);
+ else
+ y = (pseg->pt.y + y0) >> 1;
+ return gx_path_add_line_notes(ppath, x, y, pseg->notes);
+ /* WARNING: Stringly speaking, the next half segment must get
+ the sn_not_first flag. We don't bother, because that flag
+ has no important meaning with colinear segments.
+ */
+ }
+ return 0;
+}
+
+
/* Copy a path, optionally flattening or monotonizing it. */
/* If the copy fails, free the new path. */
int
@@ -177,6 +206,9 @@
break;
}
case s_line:
+ code = break_line_if_long(ppath, pseg);
+ if (code < 0)
+ break;
code = gx_path_add_line_notes(ppath,
pseg->pt.x, pseg->pt.y, pseg->notes);
vd_lineto(pseg->pt.x, pseg->pt.y);
@@ -190,6 +222,9 @@
break;
}
case s_line_close:
+ code = break_line_if_long(ppath, pseg);
+ if (code < 0)
+ break;
code = gx_path_close_subpath(ppath);
vd_closepath;
break;
@@ -303,6 +338,11 @@
pseg = psub->last;
}
break;
+ case s_line:
+ if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
+ gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
+ return true;
+ break;
case s_curve:
{
const curve_segment *pc = (const curve_segment *)pseg;
@@ -339,6 +379,35 @@
return true;
}
+/* Test whether a path is free of long segments. */
+/* WARNING : This function checks the distance between
+ * the starting point and the ending point of a segment.
+ * When they are not too far, a curve nevertheless may be too long.
+ * Don't worry about it here, because we assume
+ * this function is never called with paths which have curves.
+ */
+bool
+gx_path_has_long_segments(const gx_path * ppath)
+{
+ const segment *pseg = (const segment *)(ppath->first_subpath);
+ gs_fixed_point pt0;
+
+ while (pseg) {
+ switch (pseg->type) {
+ case s_start:
+ break;
+ default:
+ if (gx_check_fixed_diff_overflow(pseg->pt.x, pt0.x) ||
+ gx_check_fixed_diff_overflow(pseg->pt.y, pt0.y))
+ return true;
+ break;
+ }
+ pt0 = pseg->pt;
+ pseg = pseg->next;
+ }
+ return false;
+}
+
/* Monotonize a curve, by splitting it if necessary. */
/* In the worst case, this could split the curve into 9 pieces. */
int
Modified: trunk/gs/src/gxpflat.c
===================================================================
--- trunk/gs/src/gxpflat.c 2006-11-18 21:44:30 UTC (rev 7212)
+++ trunk/gs/src/gxpflat.c 2006-11-19 14:36:42 UTC (rev 7213)
@@ -278,6 +278,20 @@
return false;
}
+bool
+gx_check_fixed_diff_overflow(fixed v0, fixed v1)
+{
+ return check_diff_overflow(v0, v1);
+}
+bool
+gx_check_fixed_sum_overflow(fixed v0, fixed v1)
+{
+ /* We assume that clamp_point_aux have been applied to v1,
+ thus -v alweays exists.
+ */
+ return check_diff_overflow(v0, -v1);
+}
+
/* Initialize the iterator with a line. */
bool
gx_flattened_iterator__init_line(gx_flattened_iterator *this,
Modified: trunk/gs/src/gxstroke.c
===================================================================
--- trunk/gs/src/gxstroke.c 2006-11-18 21:44:30 UTC (rev 7212)
+++ trunk/gs/src/gxstroke.c 2006-11-19 14:36:42 UTC (rev 7213)
@@ -503,7 +503,8 @@
device_dot_length *= fabs(pmat->xy) + fabs(pmat->yy);
}
/* Start by flattening the path. We should do this on-the-fly.... */
- if (!gx_path_has_curves(ppath)) { /* don't need to flatten */
+ if (!gx_path_has_curves(ppath) && !gx_path_has_long_segments(ppath)) {
+ /* don't need to flatten */
if (!ppath->first_subpath)
return 0;
spath = ppath;
Modified: trunk/gs/src/gzpath.h
===================================================================
--- trunk/gs/src/gzpath.h 2006-11-18 21:44:30 UTC (rev 7212)
+++ trunk/gs/src/gzpath.h 2006-11-19 14:36:42 UTC (rev 7213)
@@ -403,4 +403,7 @@
fixed *ay, fixed *by, fixed *cy,
int k);
+bool gx_check_fixed_diff_overflow(fixed v0, fixed v1);
+bool gx_check_fixed_sum_overflow(fixed v0, fixed v1);
+
#endif /* gzpath_INCLUDED */
More information about the gs-cvs
mailing list