[gs-cvs] rev 7594 - in trunk/gs: doc src

leonardo at ghostscript.com leonardo at ghostscript.com
Wed Jan 10 06:47:53 PST 2007


Author: leonardo
Date: 2007-01-10 06:47:52 -0800 (Wed, 10 Jan 2007)
New Revision: 7594

Modified:
   trunk/gs/doc/pscet_status.txt
   trunk/gs/src/gxfill.c
   trunk/gs/src/gxfill.h
   trunk/gs/src/gxfilltr.h
   trunk/gs/src/zchar1.c
Log:
Implementing a smart filling rule.

DETAILS :

With CET 16-01.PS CPSI fills some contours with the even-odd rule,
and others with non-zero rule.

We implement a new rule, which counts signed even-odd numbers 
for each contour independently, and then summarizes them.

The new rule works for all characters in CPSI mode only.
Probably we don't need it for True Types,
but currently the filling algorithm doesn't recieve
the information about the font type.
Will do later on necessity.

For a faster result we generate more 4 instances of
TEMPLATE_spot_into_trapezoids, which deal with the smart winding only.

Removing Raph's hack about even-odd filing rule for Type 1 (zchar1.c).
The new rule perfectly works instead that together with
the contour sign adjustment, which was inplemented few days ago.

The new array line_list::windings stores winding numbers per contour.
The macro ADVANCE_WINDING computes the smart winding rule.
We wouild like to optimize it (to get a smaller portable code),
suggestions are welcome.

EXPECTED DIFFERENCES :

None.


Modified: trunk/gs/doc/pscet_status.txt
===================================================================
--- trunk/gs/doc/pscet_status.txt	2007-01-10 02:15:52 UTC (rev 7593)
+++ trunk/gs/doc/pscet_status.txt	2007-01-10 14:47:52 UTC (rev 7594)
@@ -3412,15 +3412,12 @@
 
 15-15-1  OK	Minor rasterizing differences. -Tor
 
-16-01-1  DIFF	differences in glyphs 6-10, 66-68, 192-194, 203-206,
-                209 can be resolved by changing GS_CHAR_FILL from
-                gs_fill to gs_eofill (zchar1.c, line 67).  glyph 21,
-                22: Ok. tiny gaps between almost adjoining black
+16-01-1  DIFF	Tiny gaps between almost adjoining black
                 rectangles; output will vary from device to device to
-                device, and our rendering is valid glyphs 195-202:
-                difference in positioning, needs more analysis glyphs
+                device, and our rendering is valid. Glyphs 195-202:
+                difference in positioning, needs more analysis. Glyphs
                 207, 208: reverse video in Adobe output, needs more
-                analysis Positioning errors (glyph 196 confirmed) are
+                analysis. Positioning errors (glyph 196 confirmed) are
                 due to font violating type1 spec. Type1 spec says that
                 lsb in seac command must match lsb of base
                 character. See also this patch to FontForge, which
@@ -3428,14 +3425,8 @@
                 seac. 
                 http://fontforge.cvs.sourceforge.net/fontforge/fontforge/fontforge/splinesave.c?r1=1.57&r2=1.58
                 Raph
-                What Raph suggests contradicts old bug fixes done for customers.
-                Ray will address eofill issue per conversation with Raph, Henry.
-                .
-                A comment from Igor : the glyph eofill problem to be fixed forever 
-                with a dynamic filling rule in the trapezoid filling algorithm.
-                I will need a month for this improvement.
                 -
-		Remaining issues : assign:-Igor.
+		Remaining issues : assign: Igor.
 
 16-02-1  DIFF	butterfly shapes: CPSI has bevel line caps, gs has
                 miter circle tests: positioning error looks similar to
@@ -3472,19 +3463,15 @@
 
 16-09-1  DIFF	Distorted shapes, may be similar to 16-03-2. Needs further analysis - Raph
 
-16-10-1  DIFF	6-10, 192, 193, 209: eofill
-                21-22: Ok, same analysis as 16-01-1
+16-10-1  DIFF	21-22: Ok, same analysis as 16-01-1
                 196-206 - positioning similar to 16-01-1, glyph 195
                 207-208 - reverse video similar to 16-01-1, glyph 207-208
-                Ray will address eofill issue per conversation with Raph, Henry.
-		Remaining issues : assign:-Igor.
+		Remaining issues : assign: Igor.
 
 16-10-2  DIFF	21-22: Ok, same analysis as 16-01-1
                 207-208 - reverse video similar to 16-01-1, glyph 207-208
-                6-10, 192, 193, 195, 203-206: fill
                 196-202: positioning, similar to 16-01-1, glyph 196
-                Ray will address eofill issue per conversation with Raph, Henry.
-		Remaining issues : assig:-Igor.
+		Remaining issues : assig: Igor.
 
 16-10-3  DIFF	many instances of glyph 208, similar to 16-01-1, glyph 208
                 Ray will address eofill issue per conversation with Raph, Henry.

Modified: trunk/gs/src/gxfill.c
===================================================================
--- trunk/gs/src/gxfill.c	2007-01-10 02:15:52 UTC (rev 7593)
+++ trunk/gs/src/gxfill.c	2007-01-10 14:47:52 UTC (rev 7594)
@@ -306,6 +306,7 @@
     bool big_path = ppath->subpath_count > 50;
     fill_options fo;
     line_list lst;
+    extern bool CPSI_mode;
 
     *(const fill_options **)&lst.fo = &fo; /* break 'const'. */
     /*
@@ -328,6 +329,8 @@
 	adjust = params->adjust;
     if (params->fill_zero_width && !pseudo_rasterization)
 	gx_adjust_if_empty(&ibox, &adjust);
+    lst.contour_count = 0;
+    lst.windings = NULL;
     lst.bbox_left = fixed2int(ibox.p.x - adjust.x - fixed_epsilon);
     lst.bbox_width = fixed2int(fixed_ceiling(ibox.q.x + adjust.x)) - lst.bbox_left;
     if (vd_enabled) {
@@ -497,7 +500,7 @@
 	     * wider than 100 pixels.
 	     */
 	    lst.margin_set0.sect = (section *)gs_alloc_struct_array(pdev->memory, lst.bbox_width * 2, 
-						   section, &st_section, "section");
+						   section, &st_section, "gx_general_fill_path");
 	    if (lst.margin_set0.sect == 0)
 		return_error(gs_error_VMerror);
 	    lst.margin_set1.sect = lst.margin_set0.sect + lst.bbox_width;
@@ -506,11 +509,21 @@
 	    init_section(lst.margin_set0.sect, 0, lst.bbox_width);
 	    init_section(lst.margin_set1.sect, 0, lst.bbox_width);
 	}
+	if (CPSI_mode && is_character) {
+	    if (lst.contour_count > countof(lst.local_windings)) {
+		lst.windings = (int *)gs_alloc_byte_array(pdev->memory, lst.contour_count, 
+				sizeof(int), "gx_general_fill_path");
+	    } else
+		lst.windings = lst.local_windings;
+	    memset(lst.windings, 0, sizeof(lst.windings[0]) * lst.contour_count);
+	}
 	code = (*fill_loop)
 	    (&lst, (max_fill_band == 0 ? NO_BAND_MASK : int2fixed(-max_fill_band)));
 	if (lst.margin_set0.sect != lst.local_section0 && 
 	    lst.margin_set0.sect != lst.local_section1)
-	    gs_free_object(pdev->memory, min(lst.margin_set0.sect, lst.margin_set1.sect), "section");
+	    gs_free_object(pdev->memory, min(lst.margin_set0.sect, lst.margin_set1.sect), "gx_general_fill_path");
+	if (lst.windings != NULL && lst.windings != lst.local_windings)
+	    gs_free_object(pdev->memory, lst.windings, "gx_general_fill_path");
     }
   nope:if (lst.close_count != 0)
 	unclose_path(pfpath, lst.close_count);
@@ -677,6 +690,7 @@
 	INCR(fill_alloc);
     } else
 	ll->next_active++;
+    alp->contour_count = ll->contour_count;
     return alp;
 }
 
@@ -1075,6 +1089,7 @@
 	code = scan_contour(ll, &q);
 	if (code < 0)
 	    return code;
+	ll->contour_count++;
     }
     return close_count;
 }
@@ -1836,94 +1851,185 @@
     *y_top = y1;
 }
 
+static inline int sign(int a) 
+{
+    return a < 0 ? -1 : a > 0 ? 1 : 0;
+}
+
 /* ---------------- Trapezoid filling loop ---------------- */
 
 /* Generate specialized algorythms for the most important cases : */
 
+/* The smart winding counter advance operator : */
+#define signed_eo(a) ((a) < 0 ? -((a) & 1) : (a) > 0 ? ((a) & 1) : 0)
+#define ADVANCE_WINDING(inside, alp, ll) \
+		{   int k = alp->contour_count; \
+		    int v = ll->windings[k]; \
+		    inside -= signed_eo(v); \
+		    v = ll->windings[k] += alp->direction; \
+		    inside += signed_eo(v); \
+		}
+
+#define IS_SPOTAN 0
+#define PSEUDO_RASTERIZATION 1
+#define SMART_WINDING 1
+#define FILL_ADJUST 0
+#define FILL_DIRECT 1
+#define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__pr_fd_sw
+#include "gxfilltr.h"
+#undef IS_SPOTAN
+#undef PSEUDO_RASTERIZATION
+#undef SMART_WINDING
+#undef FILL_ADJUST
+#undef FILL_DIRECT
+#undef TEMPLATE_spot_into_trapezoids
+
+#define IS_SPOTAN 0
+#define PSEUDO_RASTERIZATION 1
+#define SMART_WINDING 1
+#define FILL_ADJUST 0
+#define FILL_DIRECT 0
+#define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__pr_nd_sw
+#include "gxfilltr.h"
+#undef IS_SPOTAN
+#undef PSEUDO_RASTERIZATION
+#undef SMART_WINDING
+#undef FILL_ADJUST
+#undef FILL_DIRECT
+#undef TEMPLATE_spot_into_trapezoids
+
+#define IS_SPOTAN 0
+#define PSEUDO_RASTERIZATION 0
+#define SMART_WINDING 1
+#define FILL_ADJUST 0
+#define FILL_DIRECT 1
+#define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__nj_fd_sw
+#include "gxfilltr.h"
+#undef IS_SPOTAN
+#undef PSEUDO_RASTERIZATION
+#undef SMART_WINDING
+#undef FILL_ADJUST
+#undef FILL_DIRECT
+#undef TEMPLATE_spot_into_trapezoids
+
+#define IS_SPOTAN 0
+#define PSEUDO_RASTERIZATION 0
+#define SMART_WINDING 1
+#define FILL_ADJUST 0
+#define FILL_DIRECT 0
+#define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__nj_nd_sw
+#include "gxfilltr.h"
+#undef IS_SPOTAN
+#undef PSEUDO_RASTERIZATION
+#undef SMART_WINDING
+#undef FILL_ADJUST
+#undef FILL_DIRECT
+#undef TEMPLATE_spot_into_trapezoids
+
+#undef signed_eo
+#undef ADVANCE_WINDING
+/* The simple winding counter advance operator : */
+#define ADVANCE_WINDING(inside, alp, ll) inside += alp->direction
+
 #define IS_SPOTAN 1
 #define PSEUDO_RASTERIZATION 0
+#define SMART_WINDING 0
 #define FILL_ADJUST 0
 #define FILL_DIRECT 1
 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__spotan
 #include "gxfilltr.h"
 #undef IS_SPOTAN
 #undef PSEUDO_RASTERIZATION
+#undef SMART_WINDING
 #undef FILL_ADJUST
 #undef FILL_DIRECT
 #undef TEMPLATE_spot_into_trapezoids
 
 #define IS_SPOTAN 0
 #define PSEUDO_RASTERIZATION 1
+#define SMART_WINDING 0
 #define FILL_ADJUST 0
 #define FILL_DIRECT 1
 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__pr_fd
 #include "gxfilltr.h"
 #undef IS_SPOTAN
 #undef PSEUDO_RASTERIZATION
+#undef SMART_WINDING
 #undef FILL_ADJUST
 #undef FILL_DIRECT
 #undef TEMPLATE_spot_into_trapezoids
 
 #define IS_SPOTAN 0
 #define PSEUDO_RASTERIZATION 1
+#define SMART_WINDING 0
 #define FILL_ADJUST 0
 #define FILL_DIRECT 0
 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__pr_nd
 #include "gxfilltr.h"
 #undef IS_SPOTAN
 #undef PSEUDO_RASTERIZATION
+#undef SMART_WINDING
 #undef FILL_ADJUST
 #undef FILL_DIRECT
 #undef TEMPLATE_spot_into_trapezoids
 
 #define IS_SPOTAN 0
 #define PSEUDO_RASTERIZATION 0
+#define SMART_WINDING 0
 #define FILL_ADJUST 1
 #define FILL_DIRECT 1
 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__aj_fd
 #include "gxfilltr.h"
 #undef IS_SPOTAN
 #undef PSEUDO_RASTERIZATION
+#undef SMART_WINDING
 #undef FILL_ADJUST
 #undef FILL_DIRECT
 #undef TEMPLATE_spot_into_trapezoids
 
 #define IS_SPOTAN 0
 #define PSEUDO_RASTERIZATION 0
+#define SMART_WINDING 0
 #define FILL_ADJUST 1
 #define FILL_DIRECT 0
 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__aj_nd
 #include "gxfilltr.h"
 #undef IS_SPOTAN
 #undef PSEUDO_RASTERIZATION
+#undef SMART_WINDING
 #undef FILL_ADJUST
 #undef FILL_DIRECT
 #undef TEMPLATE_spot_into_trapezoids
 
 #define IS_SPOTAN 0
 #define PSEUDO_RASTERIZATION 0
+#define SMART_WINDING 0
 #define FILL_ADJUST 0
 #define FILL_DIRECT 1
 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__nj_fd
 #include "gxfilltr.h"
 #undef IS_SPOTAN
 #undef PSEUDO_RASTERIZATION
+#undef SMART_WINDING
 #undef FILL_ADJUST
 #undef FILL_DIRECT
 #undef TEMPLATE_spot_into_trapezoids
 
 #define IS_SPOTAN 0
 #define PSEUDO_RASTERIZATION 0
+#define SMART_WINDING 0
 #define FILL_ADJUST 0
 #define FILL_DIRECT 0
 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__nj_nd
 #include "gxfilltr.h"
 #undef IS_SPOTAN
 #undef PSEUDO_RASTERIZATION
+#undef SMART_WINDING
 #undef FILL_ADJUST
 #undef FILL_DIRECT
 #undef TEMPLATE_spot_into_trapezoids
 
+#undef ADVANCE_WINDING
 
 /* Main filling loop.  Takes lines off of y_list and adds them to */
 /* x_list as needed.  band_mask limits the size of each band, */
@@ -1937,16 +2043,28 @@
     if (fo->is_spotan)
 	return spot_into_trapezoids__spotan(ll, band_mask);
     if (fo->pseudo_rasterization) {
-	if (fo->fill_direct)
-	    return spot_into_trapezoids__pr_fd(ll, band_mask);
-	else
-	    return spot_into_trapezoids__pr_nd(ll, band_mask);
+	if (ll->windings != NULL) {
+	    if (fo->fill_direct)
+		return spot_into_trapezoids__pr_fd_sw(ll, band_mask);
+	    else
+		return spot_into_trapezoids__pr_nd_sw(ll, band_mask);
+	} else {
+	    if (fo->fill_direct)
+		return spot_into_trapezoids__pr_fd(ll, band_mask);
+	    else
+		return spot_into_trapezoids__pr_nd(ll, band_mask);
+	}
     }
     if (fo->adjust_below | fo->adjust_above | fo->adjust_left | fo->adjust_right) {
 	if (fo->fill_direct)
 	    return spot_into_trapezoids__aj_fd(ll, band_mask);
 	else
 	    return spot_into_trapezoids__aj_nd(ll, band_mask);
+    } else if (ll->windings != NULL) {
+	if (fo->fill_direct)
+	    return spot_into_trapezoids__nj_fd_sw(ll, band_mask);
+	else
+	    return spot_into_trapezoids__nj_nd_sw(ll, band_mask);
     } else {
 	if (fo->fill_direct)
 	    return spot_into_trapezoids__nj_fd(ll, band_mask);

Modified: trunk/gs/src/gxfill.h
===================================================================
--- trunk/gs/src/gxfill.h	2007-01-10 02:15:52 UTC (rev 7593)
+++ trunk/gs/src/gxfill.h	2007-01-10 14:47:52 UTC (rev 7594)
@@ -76,6 +76,7 @@
     bool monotonic_y;		/* "false" means "don't know"; only for scanline. */
     gx_flattened_iterator fi;
     bool more_flattened;
+    int contour_count;
 /*
  * "Pending" lines (not reached in the Y ordering yet) use next and prev
  * to order lines by increasing starting Y.  "Active" lines (being scanned)
@@ -123,11 +124,13 @@
     active_line *h_list0, *h_list1; /* lists of horizontal lines for y, y1 */
     margin_set margin_set0, margin_set1;
     margin *free_margin_list; 
+    int *windings;
     int local_margin_alloc_count;
     int bbox_left, bbox_width;
     int main_dir;
     fixed y_break;
     const fill_options * const fo;
+    int contour_count;
     /* Put the arrays last so the scalars will have */
     /* small displacements. */
     /* Allocate a few active_lines locally */
@@ -143,6 +146,7 @@
     margin local_margins[MAX_LOCAL_ACTIVE];
     section local_section0[MAX_LOCAL_SECTION];
     section local_section1[MAX_LOCAL_SECTION];
+    int local_windings[MAX_LOCAL_ACTIVE];
 };
 
 #define LOOP_FILL_RECTANGLE_DIRECT(fo, x, y, w, h)\

Modified: trunk/gs/src/gxfilltr.h
===================================================================
--- trunk/gs/src/gxfilltr.h	2007-01-10 02:15:52 UTC (rev 7593)
+++ trunk/gs/src/gxfilltr.h	2007-01-10 14:47:52 UTC (rev 7594)
@@ -21,9 +21,12 @@
  * 
  *  IS_SPOTAN - is the target device a spot analyzer ("spotan").
  *  PSEUDO_RASTERIZATION - use pseudo-rasterization.
+ *  SMART_WINDING - even-odd filling rule for each contour independently.
  *  FILL_ADJUST - fill adjustment is not zero
  *  FILL_DIRECT - See LOOP_FILL_RECTANGLE_DIRECT.
  *  TEMPLATE_spot_into_trapezoids - the name of the procedure to generate.
+ *  ADVANCE_WINDING(inside, alp, ll) - a macro for advancing the winding counter.
+ *  INSIDE_PATH_P(inside, rule) - a macro for checking the winding rule.
 */
 
 /* ---------------- Trapezoid decomposition loop ---------------- */
@@ -165,6 +168,8 @@
 	    int inside = 0;
 	    active_line *flp = NULL;
 
+	    if (SMART_WINDING)
+		memset(ll->windings, 0, sizeof(ll->windings[0]) * ll->contour_count);
 	    INCR(band);
 	    /* Generate trapezoids */
 	    for (alp = ll->x_list; alp != 0; alp = alp->next) {
@@ -173,13 +178,13 @@
 		print_al("step", alp);
 		INCR(band_step);
 		if (!INSIDE_PATH_P(inside, rule)) { 	/* i.e., outside */
-		    inside += alp->direction;
+		    ADVANCE_WINDING(inside, alp, ll);
 		    if (INSIDE_PATH_P(inside, rule))	/* about to go in */
 			flp = alp;
 		    continue;
 		}
 		/* We're inside a region being filled. */
-		inside += alp->direction;
+		ADVANCE_WINDING(inside, alp, ll);
 		if (INSIDE_PATH_P(inside, rule))	/* not about to go out */
 		    continue;
 		/* We just went from inside to outside, 
@@ -201,7 +206,7 @@
 		       it may cause a shift when choosing a pixel 
 		       to paint with a narrow trapezoid. */
 		    alp = alp->next;
-		    inside += alp->direction;
+		    ADVANCE_WINDING(inside, alp, ll);
 		    continue;
 		}
 		/* We just went from inside to outside, so fill the region. */
@@ -303,15 +308,17 @@
 		active_line *flp = NULL;
 		int inside = 0;
 
+		if (SMART_WINDING)
+		    memset(ll->windings, 0, sizeof(ll->windings[0]) * ll->contour_count);
 		for (alp = ll->x_list; alp != 0; alp = alp->next) {
 		    if (!INSIDE_PATH_P(inside, rule)) {		/* i.e., outside */
-			inside += alp->direction;
+			ADVANCE_WINDING(inside, alp, ll);
 			if (INSIDE_PATH_P(inside, rule))	/* about to go in */
 			    flp = alp;
 			continue;
 		    }
 		    /* We're inside a region being filled. */
-		    inside += alp->direction;
+		    ADVANCE_WINDING(inside, alp, ll);
 		    if (INSIDE_PATH_P(inside, rule))	/* not about to go out */
 			continue;
 		    code = continue_margin(ll, flp, alp, y, y1);

Modified: trunk/gs/src/zchar1.c
===================================================================
--- trunk/gs/src/zchar1.c	2007-01-10 02:15:52 UTC (rev 7593)
+++ trunk/gs/src/zchar1.c	2007-01-10 14:47:52 UTC (rev 7594)
@@ -66,8 +66,7 @@
 /* *********************************************************************
  * Make this dynamic via a global (somewhat better than a COMPILE option
  ***********************************************************************/
-extern bool CPSI_mode;
-#define GS_CHAR_FILL (CPSI_mode ? gs_eofill : gs_fill)
+#define GS_CHAR_FILL gs_fill
 
 /* ---------------- Utilities ---------------- */
 



More information about the gs-cvs mailing list