xref: /plan9/sys/src/cmd/gs/src/gxfillts.h (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2002 artofcode LLC. All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: gxfillts.h,v 1.5 2004/10/26 04:08:59 giles Exp $ */
18 /* Configurable algorithm for filling a slanted trapezoid. */
19 
20 /*
21  * Since we need several statically defined variants of this agorithm,
22  * we store it in .h file and include it several times into gxfill.c .
23  * Configuration macros (template arguments) are :
24  *
25  *  FILL_DIRECT - See LOOP_FILL_RECTANGLE_DIRECT.
26  *  TEMPLATE_slant_into_trapezoids - the name of the procedure to generate.
27 */
28 
29 
30 private inline int
TEMPLATE_slant_into_trapezoids(const line_list * ll,const active_line * flp,const active_line * alp,fixed y,fixed y1)31 TEMPLATE_slant_into_trapezoids (const line_list *ll,
32 	const active_line *flp, const active_line *alp, fixed y, fixed y1)
33 {
34     /*
35      * We want to get the effect of filling an area whose
36      * outline is formed by dragging a square of side adj2
37      * along the border of the trapezoid.  This is *not*
38      * equivalent to simply expanding the corners by
39      * adjust: There are 3 cases needing different
40      * algorithms, plus rectangles as a fast special case.
41      */
42     const fill_options * const fo = ll->fo;
43     int xli = fixed2int_var_pixround(flp->x_next - fo->adjust_left);
44     gs_fixed_edge le, re;
45     int code = 0;
46     /*
47      * Define a faster test for
48      *	fixed2int_pixround(y - below) != fixed2int_pixround(y + above)
49      * where we know
50      *	0 <= below <= _fixed_pixround_v,
51      *	0 <= above <= min(fixed_half, fixed_1 - below).
52      * Subtracting out the integer parts, this is equivalent to
53      *	fixed2int_pixround(fixed_fraction(y) - below) !=
54      *	  fixed2int_pixround(fixed_fraction(y) + above)
55      * or to
56      *	fixed2int(fixed_fraction(y) + _fixed_pixround_v - below) !=
57      *	  fixed2int(fixed_fraction(y) + _fixed_pixround_v + above)
58      * Letting A = _fixed_pixround_v - below and B = _fixed_pixround_v + above,
59      * we can rewrite this as
60      *	fixed2int(fixed_fraction(y) + A) != fixed2int(fixed_fraction(y) + B)
61      * Because of the range constraints given above, this is true precisely when
62      *	fixed_fraction(y) + A < fixed_1 && fixed_fraction(y) + B >= fixed_1
63      * or equivalently
64      *	fixed_fraction(y + B) < B - A.
65      * i.e.
66      *	fixed_fraction(y + _fixed_pixround_v + above) < below + above
67      */
68     fixed y_span_delta = _fixed_pixround_v + fo->adjust_above;
69     fixed y_span_limit = fo->adjust_below + fo->adjust_above;
70     le.start.x = flp->start.x - fo->adjust_left;
71     le.end.x = flp->end.x - fo->adjust_left;
72     re.start.x = alp->start.x + fo->adjust_right;
73     re.end.x = alp->end.x + fo->adjust_right;
74 
75 #define ADJUSTED_Y_SPANS_PIXEL(y)\
76   (fixed_fraction((y) + y_span_delta) < y_span_limit)
77 
78     if (le.end.x <= le.start.x) {
79 	if (re.end.x >= re.start.x) {	/* Top wider than bottom. */
80 	    le.start.y = flp->start.y - fo->adjust_below;
81 	    le.end.y = flp->end.y - fo->adjust_below;
82 	    re.start.y = alp->start.y - fo->adjust_below;
83 	    re.end.y = alp->end.y - fo->adjust_below;
84 	    code = loop_fill_trap_np(ll, &le, &re, y - fo->adjust_below, y1 - fo->adjust_below);
85 	    if (ADJUSTED_Y_SPANS_PIXEL(y1)) {
86 		if (code < 0)
87 		    return code;
88 		INCR(afill);
89 		code = LOOP_FILL_RECTANGLE_DIRECT(fo,
90 		 xli, fixed2int_pixround(y1 - fo->adjust_below),
91 		     fixed2int_var_pixround(alp->x_next + fo->adjust_right) - xli, 1);
92 		vd_rect(flp->x_next - fo->adjust_left, y1 - fo->adjust_below,
93 			alp->x_next + fo->adjust_right, y1, 1, VD_TRAP_COLOR);
94 	    }
95 	} else {	/* Slanted trapezoid. */
96 	    code = fill_slant_adjust(ll, flp, alp, y, y1);
97 	}
98     } else {
99 	if (re.end.x <= re.start.x) {	/* Bottom wider than top. */
100 	    if (ADJUSTED_Y_SPANS_PIXEL(y)) {
101 		INCR(afill);
102 		xli = fixed2int_var_pixround(flp->x_current - fo->adjust_left);
103 		code = LOOP_FILL_RECTANGLE_DIRECT(fo,
104 		  xli, fixed2int_pixround(y - fo->adjust_below),
105 		     fixed2int_var_pixround(alp->x_current + fo->adjust_right) - xli, 1);
106 		vd_rect(flp->x_current - fo->adjust_left, y - fo->adjust_below,
107 			alp->x_current + fo->adjust_right, y, 1, VD_TRAP_COLOR);
108 		if (code < 0)
109 		    return code;
110 	    }
111 	    le.start.y = flp->start.y + fo->adjust_above;
112 	    le.end.y = flp->end.y + fo->adjust_above;
113 	    re.start.y = alp->start.y + fo->adjust_above;
114 	    re.end.y = alp->end.y + fo->adjust_above;
115 	    code = loop_fill_trap_np(ll, &le, &re, y + fo->adjust_above, y1 + fo->adjust_above);
116 	} else {	/* Slanted trapezoid. */
117 	    code = fill_slant_adjust(ll, flp, alp, y, y1);
118 	}
119     }
120     return code;
121 }
122 
123