xref: /plan9/sys/src/cmd/gs/src/gxfill.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 1989-2003 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: gxfill.c,v 1.122 2005/08/22 14:29:18 igor Exp $ */
18 /* A topological spot decomposition algorithm with dropout prevention. */
19 /*
20    This is a dramaticly reorganized and improved revision of the
21    filling algorithm, iwhich was nitially coded by Henry Stiles.
22    The main improvements are:
23 	1. A dropout prevention for character fill.
24 	2. The spot topology analysys support
25 	   for True Type grid fitting.
26 	3. Fixed the contiguty of a spot covering
27 	   for shading fills with no dropouts.
28 */
29 /* See PSEUDO_RASTERISATION and "pseudo_rasterization".
30    about the dropout previntion logics. */
31 /* See is_spotan about the spot topology analyzis support. */
32 /* Also defining lower-level path filling procedures */
33 
34 #include "gx.h"
35 #include "gserrors.h"
36 #include "gsstruct.h"
37 #include "gxfixed.h"
38 #include "gxdevice.h"
39 #include "gzpath.h"
40 #include "gzcpath.h"
41 #include "gxdcolor.h"
42 #include "gxhttile.h"
43 #include "gxistate.h"
44 #include "gxpaint.h"		/* for prototypes */
45 #include "gxfdrop.h"
46 #include "gxfill.h"
47 #include "gsptype2.h"
48 #include "gdevddrw.h"
49 #include "gzspotan.h" /* Only for gx_san_trap_store. */
50 #include "memory_.h"
51 #include "stdint_.h"
52 #include "vdtrace.h"
53 /*
54 #include "gxfilltr.h" - Do not remove this comment. "gxfilltr.h" is included below.
55 #include "gxfillsl.h" - Do not remove this comment. "gxfillsl.h" is included below.
56 #include "gxfillts.h" - Do not remove this comment. "gxfillts.h" is included below.
57 */
58 
59 #ifdef DEBUG
60 /* Define the statistics structure instance. */
61 stats_fill_t stats_fill;
62 #endif
63 
64 /* A predicate for spot insideness. */
65 /* rule = -1 for winding number rule, i.e. */
66 /* we are inside if the winding number is non-zero; */
67 /* rule = 1 for even-odd rule, i.e. */
68 /* we are inside if the winding number is odd. */
69 #define INSIDE_PATH_P(inside, rule) ((inside & rule) != 0)
70 
71 
72 /* ---------------- Active line management ---------------- */
73 
74 
75 /*
76  * Define the ordering criterion for active lines that overlap in Y.
77  * Return -1, 0, or 1 if lp1 precedes, coincides with, or follows lp2.
78  *
79  * The lines' x_current values are correct for some Y value that crosses
80  * both of them and that is not both the start of one and the end of the
81  * other.  (Neither line is horizontal.)  We want the ordering at this
82  * Y value, or, of the x_current values are equal, greater Y values
83  * (if any: this Y value might be the end of both lines).
84  */
85 private int
x_order(const active_line * lp1,const active_line * lp2)86 x_order(const active_line *lp1, const active_line *lp2)
87 {
88     bool s1;
89 
90     INCR(order);
91     if (lp1->x_current < lp2->x_current)
92 	return -1;
93     else if (lp1->x_current > lp2->x_current)
94 	return 1;
95     /*
96      * We need to compare the slopes of the lines.  Start by
97      * checking one fast case, where the slopes have opposite signs.
98      */
99     if ((s1 = lp1->start.x < lp1->end.x) != (lp2->start.x < lp2->end.x))
100 	return (s1 ? 1 : -1);
101     /*
102      * We really do have to compare the slopes.  Fortunately, this isn't
103      * needed very often.  We want the sign of the comparison
104      * dx1/dy1 - dx2/dy2, or (since we know dy1 and dy2 are positive)
105      * dx1 * dy2 - dx2 * dy1.  In principle, we can't simply do this using
106      * doubles, since we need complete accuracy and doubles don't have
107      * enough fraction bits.  However, with the usual 20+12-bit fixeds and
108      * 64-bit doubles, both of the factors would have to exceed 2^15
109      * device space pixels for the result to be inaccurate, so we
110      * simply disregard this possibility.  ****** FIX SOMEDAY ******
111      */
112     INCR(slow_order);
113     {
114 	fixed dx1 = lp1->end.x - lp1->start.x,
115 	    dy1 = lp1->end.y - lp1->start.y;
116 	fixed dx2 = lp2->end.x - lp2->start.x,
117 	    dy2 = lp2->end.y - lp2->start.y;
118 	double diff = (double)dx1 * dy2 - (double)dx2 * dy1;
119 
120 	return (diff < 0 ? -1 : diff > 0 ? 1 : 0);
121     }
122 }
123 
124 /*
125  * The active_line structure isn't really simple, but since its instances
126  * only exist temporarily during a fill operation, we don't have to
127  * worry about a garbage collection occurring.
128  */
129 gs_private_st_simple(st_active_line, active_line, "active_line");
130 
131 #ifdef DEBUG
132 /* Internal procedures for printing and checking active lines. */
133 private void
print_active_line(const char * label,const active_line * alp)134 print_active_line(const char *label, const active_line * alp)
135 {
136     dlprintf5("[f]%s 0x%lx(%d): x_current=%f x_next=%f\n",
137 	      label, (ulong) alp, alp->direction,
138 	      fixed2float(alp->x_current), fixed2float(alp->x_next));
139     dlprintf5("    start=(%f,%f) pt_end=0x%lx(%f,%f)\n",
140 	      fixed2float(alp->start.x), fixed2float(alp->start.y),
141 	      (ulong) alp->pseg,
142 	      fixed2float(alp->end.x), fixed2float(alp->end.y));
143     dlprintf2("    prev=0x%lx next=0x%lx\n",
144 	      (ulong) alp->prev, (ulong) alp->next);
145 }
146 private void
print_line_list(const active_line * flp)147 print_line_list(const active_line * flp)
148 {
149     const active_line *lp;
150 
151     for (lp = flp; lp != 0; lp = lp->next) {
152 	fixed xc = lp->x_current, xn = lp->x_next;
153 
154 	dlprintf3("[f]0x%lx(%d): x_current/next=%g",
155 		  (ulong) lp, lp->direction,
156 		  fixed2float(xc));
157 	if (xn != xc)
158 	    dprintf1("/%g", fixed2float(xn));
159 	dputc('\n');
160     }
161 }
162 inline private void
print_al(const char * label,const active_line * alp)163 print_al(const char *label, const active_line * alp)
164 {
165     if (gs_debug_c('F'))
166 	print_active_line(label, alp);
167 }
168 #else
169 #define print_al(label,alp) DO_NOTHING
170 #endif
171 
172 private inline bool
is_spotan_device(gx_device * dev)173 is_spotan_device(gx_device * dev)
174 {
175     return dev->memory != NULL &&
176 	    gs_object_type(dev->memory, dev) == &st_device_spot_analyzer;
177 }
178 
179 /* Forward declarations */
180 private void free_line_list(line_list *);
181 private int add_y_list(gx_path *, line_list *);
182 private int add_y_line_aux(const segment * prev_lp, const segment * lp,
183 	    const gs_fixed_point *curr, const gs_fixed_point *prev, int dir, line_list *ll);
184 private void insert_x_new(active_line *, line_list *);
185 private bool end_x_line(active_line *, const line_list *, bool);
186 private void step_al(active_line *alp, bool move_iterator);
187 
188 
189 #define FILL_LOOP_PROC(proc) int proc(line_list *, fixed band_mask)
190 private FILL_LOOP_PROC(spot_into_scan_lines);
191 private FILL_LOOP_PROC(spot_into_trapezoids);
192 
193 /*
194  * This is the general path filling algorithm.
195  * It uses the center-of-pixel rule for filling
196  * (except for pseudo_rasterization - see below).
197  * We can implement Microsoft's upper-left-corner-of-pixel rule
198  * by subtracting (0.5, 0.5) from all the coordinates in the path.
199  *
200  * The adjust parameters are a hack for keeping regions
201  * from coming out too faint: they specify an amount by which to expand
202  * the sides of every filled region.
203  * Setting adjust = fixed_half is supposed to produce the effect of Adobe's
204  * any-part-of-pixel rule, but it doesn't quite, because of the
205  * closed/open interval rule for regions.  We detect this as a special case
206  * and do the slightly ugly things necessary to make it work.
207  */
208 
209 /* Initialize the line list for a path. */
210 private inline void
init_line_list(line_list * ll,gs_memory_t * mem)211 init_line_list(line_list *ll, gs_memory_t * mem)
212 {
213     ll->memory = mem;
214     ll->active_area = 0;
215     ll->next_active = ll->local_active;
216     ll->limit = ll->next_active + MAX_LOCAL_ACTIVE;
217     ll->close_count = 0;
218     ll->y_list = 0;
219     ll->y_line = 0;
220     ll->h_list0 = ll->h_list1 = 0;
221     ll->margin_set0.margin_list = ll->margin_set1.margin_list = 0;
222     ll->margin_set0.margin_touched = ll->margin_set1.margin_touched = 0;
223     ll->margin_set0.y = ll->margin_set1.y = 0; /* A stub against indeterminism. Don't use it. */
224     ll->free_margin_list = 0;
225     ll->local_margin_alloc_count = 0;
226     ll->margin_set0.sect = ll->local_section0;
227     ll->margin_set1.sect = ll->local_section1;
228     /* Do not initialize ll->bbox_left, ll->bbox_width - they were set in advance. */
229     INCR(fill);
230 }
231 
232 
233 /* Unlink any line_close segments added temporarily. */
234 private inline void
unclose_path(gx_path * ppath,int count)235 unclose_path(gx_path * ppath, int count)
236 {
237     subpath *psub;
238 
239     for (psub = ppath->first_subpath; count != 0;
240 	 psub = (subpath *) psub->last->next
241 	)
242 	if (psub->last == (segment *) & psub->closer) {
243 	    segment *prev = psub->closer.prev, *next = psub->closer.next;
244 
245 	    prev->next = next;
246 	    if (next)
247 		next->prev = prev;
248 	    psub->last = prev;
249 	    count--;
250 	}
251 }
252 
253 /*
254  * Tweak the fill adjustment if necessary so that (nearly) empty
255  * rectangles are guaranteed to produce some output.  This is a hack
256  * to work around a bug in the Microsoft Windows PostScript driver,
257  * which draws thin lines by filling zero-width rectangles, and in
258  * some other drivers that try to fill epsilon-width rectangles.
259  */
260 void
gx_adjust_if_empty(const gs_fixed_rect * pbox,gs_fixed_point * adjust)261 gx_adjust_if_empty(const gs_fixed_rect * pbox, gs_fixed_point * adjust)
262 {
263     /*
264      * For extremely large coordinates, the obvious subtractions could
265      * overflow.  We can work around this easily by noting that since
266      * we know q.{x,y} >= p.{x,y}, the subtraction overflows iff the
267      * result is negative.
268      */
269     const fixed
270 	  dx = pbox->q.x - pbox->p.x, dy = pbox->q.y - pbox->p.y;
271 
272     if (dx < fixed_half && dx > 0 && (dy >= int2fixed(2) || dy < 0)) {
273 	adjust->x = arith_rshift_1(fixed_1 + fixed_epsilon - dx);
274 	if_debug1('f', "[f]thin adjust_x=%g\n",
275 		  fixed2float(adjust->x));
276     } else if (dy < fixed_half && dy > 0 && (dx >= int2fixed(2) || dx < 0)) {
277 	adjust->y = arith_rshift_1(fixed_1 + fixed_epsilon - dy);
278 	if_debug1('f', "[f]thin adjust_y=%g\n",
279 		  fixed2float(adjust->y));
280     }
281 }
282 
283 /*
284  * The general fill  path algorithm.
285  */
286 private int
gx_general_fill_path(gx_device * pdev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_device_color * pdevc,const gx_clip_path * pcpath)287 gx_general_fill_path(gx_device * pdev, const gs_imager_state * pis,
288 		     gx_path * ppath, const gx_fill_params * params,
289 		 const gx_device_color * pdevc, const gx_clip_path * pcpath)
290 {
291     gs_fixed_point adjust;
292     gs_logical_operation_t lop = pis->log_op;
293     gs_fixed_rect ibox, bbox, sbox;
294     gx_device_clip cdev;
295     gx_device *dev = pdev;
296     gx_device *save_dev = dev;
297     gx_path ffpath;
298     gx_path *pfpath;
299     int code;
300     int max_fill_band = dev->max_fill_band;
301 #define NO_BAND_MASK ((fixed)(-1) << (sizeof(fixed) * 8 - 1))
302     const bool is_character = params->adjust.x == -1; /* See gxistate.h */
303     bool fill_by_trapezoids;
304     bool pseudo_rasterization;
305     bool big_path = ppath->subpath_count > 50;
306     fill_options fo;
307     line_list lst;
308 
309     *(const fill_options **)&lst.fo = &fo; /* break 'const'. */
310     /*
311      * Compute the bounding box before we flatten the path.
312      * This can save a lot of time if the path has curves.
313      * If the path is neither fully within nor fully outside
314      * the quick-check boxes, we could recompute the bounding box
315      * and make the checks again after flattening the path,
316      * but right now we don't bother.
317      */
318     gx_path_bbox(ppath, &ibox);
319 #   define SMALL_CHARACTER 500
320     pseudo_rasterization = (is_character &&
321 			    !is_spotan_device(dev) &&
322 			    ibox.q.y - ibox.p.y < SMALL_CHARACTER * fixed_scale &&
323 			    ibox.q.x - ibox.p.x < SMALL_CHARACTER * fixed_scale);
324     if (is_character)
325 	adjust.x = adjust.y = 0;
326     else
327 	adjust = params->adjust;
328     if (params->fill_zero_width && !pseudo_rasterization)
329 	gx_adjust_if_empty(&ibox, &adjust);
330     lst.bbox_left = fixed2int(ibox.p.x - adjust.x - fixed_epsilon);
331     lst.bbox_width = fixed2int(fixed_ceiling(ibox.q.x + adjust.x)) - lst.bbox_left;
332     if (vd_enabled) {
333 	fixed x0 = int2fixed(fixed2int(ibox.p.x - adjust.x - fixed_epsilon));
334 	fixed x1 = int2fixed(fixed2int(ibox.q.x + adjust.x + fixed_scale - fixed_epsilon));
335 	fixed y0 = int2fixed(fixed2int(ibox.p.y - adjust.y - fixed_epsilon));
336 	fixed y1 = int2fixed(fixed2int(ibox.q.y + adjust.y + fixed_scale - fixed_epsilon)), k;
337 
338 	for (k = x0; k <= x1; k += fixed_scale)
339 	    vd_bar(k, y0, k, y1, 1, RGB(128, 128, 128));
340 	for (k = y0; k <= y1; k += fixed_scale)
341 	    vd_bar(x0, k, x1, k, 1, RGB(128, 128, 128));
342     }
343     /* Check the bounding boxes. */
344     if_debug6('f', "[f]adjust=%g,%g bbox=(%g,%g),(%g,%g)\n",
345 	      fixed2float(adjust.x), fixed2float(adjust.y),
346 	      fixed2float(ibox.p.x), fixed2float(ibox.p.y),
347 	      fixed2float(ibox.q.x), fixed2float(ibox.q.y));
348     if (pcpath)
349 	gx_cpath_inner_box(pcpath, &bbox);
350     else
351 	(*dev_proc(dev, get_clipping_box)) (dev, &bbox);
352     if (!rect_within(ibox, bbox)) {
353 	/*
354 	 * Intersect the path box and the clip bounding box.
355 	 * If the intersection is empty, this fill is a no-op.
356 	 */
357 	if (pcpath)
358 	    gx_cpath_outer_box(pcpath, &bbox);
359 	if_debug4('f', "   outer_box=(%g,%g),(%g,%g)\n",
360 		  fixed2float(bbox.p.x), fixed2float(bbox.p.y),
361 		  fixed2float(bbox.q.x), fixed2float(bbox.q.y));
362 	rect_intersect(ibox, bbox);
363 	if (ibox.p.x - adjust.x >= ibox.q.x + adjust.x ||
364 	    ibox.p.y - adjust.y >= ibox.q.y + adjust.y
365 	    ) { 		/* Intersection of boxes is empty! */
366 	    return 0;
367 	}
368 	/*
369 	 * The path is neither entirely inside the inner clip box
370 	 * nor entirely outside the outer clip box.
371 	 * If we had to flatten the path, this is where we would
372 	 * recompute its bbox and make the tests again,
373 	 * but we don't bother right now.
374 	 *
375 	 * If there is a clipping path, set up a clipping device.
376 	 */
377 	if (pcpath) {
378 	    dev = (gx_device *) & cdev;
379 	    gx_make_clip_device(&cdev, gx_cpath_list(pcpath));
380 	    cdev.target = save_dev;
381 	    cdev.max_fill_band = save_dev->max_fill_band;
382 	    (*dev_proc(dev, open_device)) (dev);
383 	}
384     }
385     /*
386      * Compute the proper adjustment values.
387      * To get the effect of the any-part-of-pixel rule,
388      * we may have to tweak them slightly.
389      * NOTE: We changed the adjust_right/above value from 0.5+epsilon
390      * to 0.5 in release 5.01; even though this does the right thing
391      * in every case we could imagine, we aren't confident that it's
392      * correct.  (The old values were definitely incorrect, since they
393      * caused 1-pixel-wide/high objects to color 2 pixels even if
394      * they fell exactly on pixel boundaries.)
395      */
396     if (adjust.x == fixed_half)
397 	fo.adjust_left = fixed_half - fixed_epsilon,
398 	    fo.adjust_right = fixed_half /* + fixed_epsilon */ ;	/* see above */
399     else
400 	fo.adjust_left = fo.adjust_right = adjust.x;
401     if (adjust.y == fixed_half)
402 	fo.adjust_below = fixed_half - fixed_epsilon,
403 	    fo.adjust_above = fixed_half /* + fixed_epsilon */ ;	/* see above */
404     else
405 	fo.adjust_below = fo.adjust_above = adjust.y;
406     /* Initialize the active line list. */
407     init_line_list(&lst, ppath->memory);
408     sbox.p.x = ibox.p.x - adjust.x;
409     sbox.p.y = ibox.p.y - adjust.y;
410     sbox.q.x = ibox.q.x + adjust.x;
411     sbox.q.y = ibox.q.y + adjust.y;
412     fo.pseudo_rasterization = pseudo_rasterization;
413     fo.pdevc = pdevc;
414     fo.lop = lop;
415     fo.fixed_flat = float2fixed(params->flatness);
416     fo.ymin = ibox.p.y;
417     fo.ymax = ibox.q.y;
418     fo.dev = dev;
419     fo.lop = lop;
420     fo.pbox = &sbox;
421     fo.rule = params->rule;
422     fo.is_spotan = is_spotan_device(dev);
423     fo.fill_direct = color_writes_pure(pdevc, lop);
424     fo.fill_rect = (fo.fill_direct ? dev_proc(dev, fill_rectangle) : NULL);
425     fo.fill_trap = dev_proc(dev, fill_trapezoid);
426 
427     /*
428      * We have a choice of two different filling algorithms:
429      * scan-line-based and trapezoid-based.  They compare as follows:
430      *
431      *	    Scan    Trap
432      *	    ----    ----
433      *	     skip   +draw   0-height horizontal lines
434      *	     slow   +fast   rectangles
435      *	    +fast    slow   curves
436      *	    +yes     no     write pixels at most once when adjust != 0
437      *
438      * Normally we use the scan line algorithm for characters, where curve
439      * speed is important, and for non-idempotent RasterOps, where double
440      * pixel writing must be avoided, and the trapezoid algorithm otherwise.
441      * However, we always use the trapezoid algorithm for rectangles.
442      */
443     fill_by_trapezoids =
444 	(pseudo_rasterization || !gx_path_has_curves(ppath) ||
445 	 params->flatness >= 1.0 || fo.is_spotan);
446     if (fill_by_trapezoids && !fo.is_spotan && !lop_is_idempotent(lop)) {
447 	gs_fixed_rect rbox;
448 
449 	if (gx_path_is_rectangular(ppath, &rbox)) {
450 	    int x0 = fixed2int_pixround(rbox.p.x - fo.adjust_left);
451 	    int y0 = fixed2int_pixround(rbox.p.y - fo.adjust_below);
452 	    int x1 = fixed2int_pixround(rbox.q.x + fo.adjust_right);
453 	    int y1 = fixed2int_pixround(rbox.q.y + fo.adjust_above);
454 
455 	    return gx_fill_rectangle_device_rop(x0, y0, x1 - x0, y1 - y0,
456 						pdevc, dev, lop);
457 	}
458 	if (fo.adjust_left | fo.adjust_right | fo.adjust_below | fo.adjust_above)
459 	    fill_by_trapezoids = false; /* avoid double writing pixels */
460     }
461     gx_path_init_local(&ffpath, ppath->memory);
462     if (!big_path && !gx_path_has_curves(ppath))	/* don't need to flatten */
463 	pfpath = ppath;
464     else if (is_spotan_device(dev))
465 	pfpath = ppath;
466     else if (!big_path && gx_path__check_curves(ppath, pco_small_curves, fo.fixed_flat))
467 	pfpath = ppath;
468     else {
469 	code = gx_path_copy_reducing(ppath, &ffpath, fo.fixed_flat, NULL,
470 			    pco_small_curves);
471 	if (code < 0)
472 	    return code;
473 	pfpath = &ffpath;
474 	if (big_path) {
475 	    code = gx_path_merge_contacting_contours(pfpath);
476 	    if (code < 0)
477 		return code;
478 	}
479     }
480     fo.fill_by_trapezoids = fill_by_trapezoids;
481     if ((code = add_y_list(pfpath, &lst)) < 0)
482 	goto nope;
483     {
484 	FILL_LOOP_PROC((*fill_loop));
485 
486 	/* Some short-sighted compilers won't allow a conditional here.... */
487 	if (fill_by_trapezoids)
488 	    fill_loop = spot_into_trapezoids;
489 	else
490 	    fill_loop = spot_into_scan_lines;
491 	if (lst.bbox_width > MAX_LOCAL_SECTION && fo.pseudo_rasterization) {
492 	    /*
493 	     * Note that execution pass here only for character size
494 	     * grater that MAX_LOCAL_SECTION and lesser than
495 	     * SMALL_CHARACTER. Therefore with !arch_small_memory
496 	     * the dynamic allocation only happens for characters
497 	     * wider than 100 pixels.
498 	     */
499 	    lst.margin_set0.sect = (section *)gs_alloc_struct_array(pdev->memory, lst.bbox_width * 2,
500 						   section, &st_section, "section");
501 	    if (lst.margin_set0.sect == 0)
502 		return_error(gs_error_VMerror);
503 	    lst.margin_set1.sect = lst.margin_set0.sect + lst.bbox_width;
504 	}
505 	if (fo.pseudo_rasterization) {
506 	    init_section(lst.margin_set0.sect, 0, lst.bbox_width);
507 	    init_section(lst.margin_set1.sect, 0, lst.bbox_width);
508 	}
509 	code = (*fill_loop)
510 	    (&lst, (max_fill_band == 0 ? NO_BAND_MASK : int2fixed(-max_fill_band)));
511 	if (lst.margin_set0.sect != lst.local_section0 &&
512 	    lst.margin_set0.sect != lst.local_section1)
513 	    gs_free_object(pdev->memory, min(lst.margin_set0.sect, lst.margin_set1.sect), "section");
514     }
515   nope:if (lst.close_count != 0)
516 	unclose_path(pfpath, lst.close_count);
517     free_line_list(&lst);
518     if (pfpath != ppath)	/* had to flatten */
519 	gx_path_free(pfpath, "gx_general_fill_path");
520 #ifdef DEBUG
521     if (gs_debug_c('f')) {
522 	dlputs("[f]  # alloc    up  down horiz step slowx  iter  find  band bstep bfill\n");
523 	dlprintf5(" %5ld %5ld %5ld %5ld %5ld",
524 		  stats_fill.fill, stats_fill.fill_alloc,
525 		  stats_fill.y_up, stats_fill.y_down,
526 		  stats_fill.horiz);
527 	dlprintf4(" %5ld %5ld %5ld %5ld",
528 		  stats_fill.x_step, stats_fill.slow_x,
529 		  stats_fill.iter, stats_fill.find_y);
530 	dlprintf3(" %5ld %5ld %5ld\n",
531 		  stats_fill.band, stats_fill.band_step,
532 		  stats_fill.band_fill);
533 	dlputs("[f]    afill slant shall sfill mqcrs order slowo\n");
534 	dlprintf7("       %5ld %5ld %5ld %5ld %5ld %5ld %5ld\n",
535 		  stats_fill.afill, stats_fill.slant,
536 		  stats_fill.slant_shallow, stats_fill.sfill,
537 		  stats_fill.mq_cross, stats_fill.order,
538 		  stats_fill.slow_order);
539     }
540 #endif
541     return code;
542 }
543 
544 /*
545  * Fill a path.  This is the default implementation of the driver
546  * fill_path procedure.
547  */
548 int
gx_default_fill_path(gx_device * pdev,const gs_imager_state * pis,gx_path * ppath,const gx_fill_params * params,const gx_device_color * pdevc,const gx_clip_path * pcpath)549 gx_default_fill_path(gx_device * pdev, const gs_imager_state * pis,
550 		     gx_path * ppath, const gx_fill_params * params,
551 		 const gx_device_color * pdevc, const gx_clip_path * pcpath)
552 {
553     int code;
554 
555     if (gx_dc_is_pattern2_color(pdevc)) {
556 	/*  Optimization for shading fill :
557 	    The general path filling algorithm subdivides fill region with
558 	    trapezoid or rectangle subregions and then paints each subregion
559 	    with given color. If the color is shading, each subregion to be
560 	    subdivided into areas of constant color. But with radial
561 	    shading each area is a high order polygon, being
562 	    subdivided into smaller subregions, so as total number of
563 	    subregions grows huge. Faster processing is done here by changing
564 	    the order of subdivision cycles : we first subdivide the shading into
565 	    areas of constant color, then apply the general path filling algorithm
566 	    (i.e. subdivide each area into trapezoids or rectangles), using the
567 	    filling path as clip mask.
568 	*/
569 
570 	gx_clip_path cpath_intersection;
571 	gx_path path_intersection;
572 
573 	/*  Shading fill algorithm uses "current path" parameter of the general
574 	    path filling algorithm as boundary of constant color area,
575 	    so we need to intersect the filling path with the clip path now,
576 	    reducing the number of pathes passed to it :
577 	*/
578 	gx_path_init_local(&path_intersection, pdev->memory);
579 	gx_cpath_init_local_shared(&cpath_intersection, pcpath, pdev->memory);
580 	if ((code = gx_cpath_intersect(&cpath_intersection, ppath, params->rule, (gs_imager_state *)pis)) >= 0)
581 	    code = gx_cpath_to_path(&cpath_intersection, &path_intersection);
582 
583 	/* Do fill : */
584 	if (code >= 0)
585 	    code = gx_dc_pattern2_fill_path(pdevc, &path_intersection, NULL,  pdev);
586 
587 	/* Destruct local data and return :*/
588 	gx_path_free(&path_intersection, "shading_fill_path_intersection");
589 	gx_cpath_free(&cpath_intersection, "shading_fill_cpath_intersection");
590     } else {
591 	bool got_dc = false;
592         vd_save;
593 	if (vd_allowed('F') || vd_allowed('f')) {
594 	    if (!vd_enabled) {
595 		vd_get_dc( (params->adjust.x | params->adjust.y)  ? 'F' : 'f');
596 		got_dc = vd_enabled;
597 	    }
598 	    if (vd_enabled) {
599 		vd_set_shift(0, 100);
600 		vd_set_scale(VD_SCALE);
601 		vd_set_origin(0, 0);
602 		vd_erase(RGB(192, 192, 192));
603 	    }
604 	} else
605 	    vd_disable;
606 	code = gx_general_fill_path(pdev, pis, ppath, params, pdevc, pcpath);
607 	if (got_dc)
608 	    vd_release_dc;
609 	vd_restore;
610     }
611     return code;
612 }
613 
614 /* Free the line list. */
615 private void
free_line_list(line_list * ll)616 free_line_list(line_list *ll)
617 {
618     /* Free any individually allocated active_lines. */
619     gs_memory_t *mem = ll->memory;
620     active_line *alp;
621 
622     while ((alp = ll->active_area) != 0) {
623 	active_line *next = alp->alloc_next;
624 
625 	gs_free_object(mem, alp, "active line");
626 	ll->active_area = next;
627     }
628     free_all_margins(ll);
629 }
630 
631 private inline active_line *
make_al(line_list * ll)632 make_al(line_list *ll)
633 {
634     active_line *alp = ll->next_active;
635 
636     if (alp == ll->limit) {	/* Allocate separately */
637 	alp = gs_alloc_struct(ll->memory, active_line,
638 			      &st_active_line, "active line");
639 	if (alp == 0)
640 	    return NULL;
641 	alp->alloc_next = ll->active_area;
642 	ll->active_area = alp;
643 	INCR(fill_alloc);
644     } else
645 	ll->next_active++;
646     return alp;
647 }
648 
649 /* Insert the new line in the Y ordering */
650 private void
insert_y_line(line_list * ll,active_line * alp)651 insert_y_line(line_list *ll, active_line *alp)
652 {
653     active_line *yp = ll->y_line;
654     active_line *nyp;
655     fixed y_start = alp->start.y;
656 
657     vd_bar(alp->start.x, alp->start.y, alp->end.x, alp->end.y, 0, RGB(255, 0, 0));
658     if (yp == 0) {
659 	alp->next = alp->prev = 0;
660 	ll->y_list = alp;
661     } else if (y_start >= yp->start.y) {	/* Insert the new line after y_line */
662 	while (INCR_EXPR(y_up),
663 	       ((nyp = yp->next) != NULL &&
664 		y_start > nyp->start.y)
665 	    )
666 	    yp = nyp;
667 	alp->next = nyp;
668 	alp->prev = yp;
669 	yp->next = alp;
670 	if (nyp)
671 	    nyp->prev = alp;
672     } else {		/* Insert the new line before y_line */
673 	while (INCR_EXPR(y_down),
674 	       ((nyp = yp->prev) != NULL &&
675 		y_start < nyp->start.y)
676 	    )
677 	    yp = nyp;
678 	alp->prev = nyp;
679 	alp->next = yp;
680 	yp->prev = alp;
681 	if (nyp)
682 	    nyp->next = alp;
683 	else
684 	    ll->y_list = alp;
685     }
686     ll->y_line = alp;
687     vd_bar(alp->start.x, alp->start.y, alp->end.x, alp->end.y, 1, RGB(0, 255, 0));
688     print_al("add ", alp);
689 }
690 
691 typedef struct contour_cursor_s {
692     segment *prev, *pseg, *pfirst, *plast;
693     gx_flattened_iterator *fi;
694     bool more_flattened;
695     bool first_flattened;
696     int dir;
697     bool monotonic_y;
698     bool monotonic_x;
699     bool crossing;
700 } contour_cursor;
701 
702 private inline int
compute_dir(const fill_options * fo,fixed y0,fixed y1)703 compute_dir(const fill_options *fo, fixed y0, fixed y1)
704 {
705     if (max(y0, y1) < fo->ymin)
706 	return 2;
707     if (min(y0, y1) > fo->ymax)
708 	return 2;
709     return (y0 < y1 ? DIR_UP :
710 	    y0 > y1 ? DIR_DOWN : DIR_HORIZONTAL);
711 }
712 
713 private inline int
add_y_curve_part(line_list * ll,segment * s0,segment * s1,int dir,gx_flattened_iterator * fi,bool more1,bool step_back,bool monotonic_x)714 add_y_curve_part(line_list *ll, segment *s0, segment *s1, int dir,
715     gx_flattened_iterator *fi, bool more1, bool step_back, bool monotonic_x)
716 {
717     active_line *alp = make_al(ll);
718 
719     if (alp == NULL)
720 	return_error(gs_error_VMerror);
721     alp->pseg = (dir == DIR_UP ? s1 : s0);
722     alp->direction = dir;
723     alp->fi = *fi;
724     alp->more_flattened = more1;
725     if (dir != DIR_UP && more1)
726 	gx_flattened_iterator__switch_to_backscan(&alp->fi, more1);
727     if (step_back) {
728 	do {
729 	    alp->more_flattened = gx_flattened_iterator__prev(&alp->fi);
730 	    if (compute_dir(ll->fo, alp->fi.ly0, alp->fi.ly1) != 2)
731 		break;
732 	} while (alp->more_flattened);
733     }
734     step_al(alp, false);
735     alp->monotonic_y = false;
736     alp->monotonic_x = monotonic_x;
737     insert_y_line(ll, alp);
738     return 0;
739 }
740 
741 private inline int
add_y_line(const segment * prev_lp,const segment * lp,int dir,line_list * ll)742 add_y_line(const segment * prev_lp, const segment * lp, int dir, line_list *ll)
743 {
744     return add_y_line_aux(prev_lp, lp, &lp->pt, &prev_lp->pt, dir, ll);
745 }
746 
747 private inline int
start_al_pair(line_list * ll,contour_cursor * q,contour_cursor * p)748 start_al_pair(line_list *ll, contour_cursor *q, contour_cursor *p)
749 {
750     int code;
751 
752     if (q->monotonic_y)
753 	code = add_y_line(q->prev, q->pseg, DIR_DOWN, ll);
754     else
755 	code = add_y_curve_part(ll, q->prev, q->pseg, DIR_DOWN, q->fi,
756 			    !q->first_flattened, false, q->monotonic_x);
757     if (code < 0)
758 	return code;
759     if (p->monotonic_y)
760 	code = add_y_line(p->prev, p->pseg, DIR_UP, ll);
761     else
762 	code = add_y_curve_part(ll, p->prev, p->pseg, DIR_UP, p->fi,
763 			    p->more_flattened, false, p->monotonic_x);
764     return code;
765 }
766 
767 /* Start active lines from a minimum of a possibly non-monotonic curve. */
768 private int
start_al_pair_from_min(line_list * ll,contour_cursor * q)769 start_al_pair_from_min(line_list *ll, contour_cursor *q)
770 {
771     int dir, code;
772     const fill_options * const fo = ll->fo;
773 
774     /* q stands at the first segment, which isn't last. */
775     do {
776 	q->more_flattened = gx_flattened_iterator__next(q->fi);
777 	dir = compute_dir(fo, q->fi->ly0, q->fi->ly1);
778 	if (q->fi->ly0 > fo->ymax && ll->y_break > q->fi->y0)
779 	    ll->y_break = q->fi->ly0;
780 	if (q->fi->ly1 > fo->ymax && ll->y_break > q->fi->ly1)
781 	    ll->y_break = q->fi->ly1;
782 	if (dir == DIR_UP && ll->main_dir == DIR_DOWN && q->fi->ly0 >= fo->ymin) {
783 	    code = add_y_curve_part(ll, q->prev, q->pseg, DIR_DOWN, q->fi,
784 			    true, true, q->monotonic_x);
785 	    if (code < 0)
786 		return code;
787 	    code = add_y_curve_part(ll, q->prev, q->pseg, DIR_UP, q->fi,
788 			    q->more_flattened, false, q->monotonic_x);
789 	    if (code < 0)
790 		return code;
791 	} else if (q->fi->ly0 < fo->ymin && q->fi->ly1 >= fo->ymin) {
792 	    code = add_y_curve_part(ll, q->prev, q->pseg, DIR_UP, q->fi,
793 			    q->more_flattened, false, q->monotonic_x);
794 	    if (code < 0)
795 		return code;
796 	} else if (q->fi->ly0 >= fo->ymin && q->fi->ly1 < fo->ymin) {
797 	    code = add_y_curve_part(ll, q->prev, q->pseg, DIR_DOWN, q->fi,
798 			    true, false, q->monotonic_x);
799 	    if (code < 0)
800 		return code;
801 	}
802 	q->first_flattened = false;
803         q->dir = dir;
804 	ll->main_dir = (dir == DIR_DOWN ? DIR_DOWN :
805 			dir == DIR_UP ? DIR_UP : ll->main_dir);
806 	if (!q->more_flattened)
807 	    break;
808     } while(q->more_flattened);
809     /* q stands at the last segment. */
810     return 0;
811     /* note : it doesn't depend on the number of curve minimums,
812        which may vary due to arithmetic errors. */
813 }
814 
815 private inline void
init_contour_cursor(line_list * ll,contour_cursor * q)816 init_contour_cursor(line_list *ll, contour_cursor *q)
817 {
818     const fill_options * const fo = ll->fo;
819 
820     if (q->pseg->type == s_curve) {
821 	curve_segment *s = (curve_segment *)q->pseg;
822 	fixed ymin = min(min(q->prev->pt.y, s->p1.y), min(s->p2.y, s->pt.y));
823 	fixed ymax = max(max(q->prev->pt.y, s->p1.y), max(s->p2.y, s->pt.y));
824 	bool in_band = ymin <= fo->ymax && ymax >= fo->ymin;
825 	q->crossing = ymin < fo->ymin && ymax >= fo->ymin;
826 	q->monotonic_y = !in_band ||
827 	    (!q->crossing &&
828 	    ((q->prev->pt.y <= s->p1.y && s->p1.y <= s->p2.y && s->p2.y <= s->pt.y) ||
829 	     (q->prev->pt.y >= s->p1.y && s->p1.y >= s->p2.y && s->p2.y >= s->pt.y)));
830 	q->monotonic_x =
831 	    ((q->prev->pt.x <= s->p1.x && s->p1.x <= s->p2.x && s->p2.x <= s->pt.x) ||
832 	     (q->prev->pt.x >= s->p1.x && s->p1.x >= s->p2.x && s->p2.x >= s->pt.x));
833     } else
834 	q->monotonic_y = true;
835     if (!q->monotonic_y) {
836 	curve_segment *s = (curve_segment *)q->pseg;
837 	int k = gx_curve_log2_samples(q->prev->pt.x, q->prev->pt.y, s, fo->fixed_flat);
838 
839 	gx_flattened_iterator__init(q->fi, q->prev->pt.x, q->prev->pt.y, s, k);
840     } else {
841 	q->dir = compute_dir(fo, q->prev->pt.y, q->pseg->pt.y);
842 	gx_flattened_iterator__init_line(q->fi,
843 	    q->prev->pt.x, q->prev->pt.y, q->pseg->pt.x, q->pseg->pt.y); /* fake for curves. */
844 	vd_bar(q->prev->pt.x, q->prev->pt.y, q->pseg->pt.x, q->pseg->pt.y, 1, RGB(0, 0, 255));
845     }
846     q->first_flattened = true;
847 }
848 
849 private int
scan_contour(line_list * ll,contour_cursor * q)850 scan_contour(line_list *ll, contour_cursor *q)
851 {
852     contour_cursor p;
853     gx_flattened_iterator fi, save_fi;
854     segment *pseg;
855     int code;
856     bool only_horizontal = true, saved = false;
857     const fill_options * const fo = ll->fo;
858     contour_cursor save_q;
859 
860     p.fi = &fi;
861     save_q.dir = 2;
862     ll->main_dir = DIR_HORIZONTAL;
863     for (; ; q->pseg = q->prev, q->prev = q->prev->prev) {
864 	init_contour_cursor(ll, q);
865 	while(gx_flattened_iterator__next(q->fi)) {
866 	    q->first_flattened = false;
867 	    q->dir = compute_dir(fo, q->fi->ly0, q->fi->ly1);
868 	    ll->main_dir = (q->dir == DIR_DOWN ? DIR_DOWN :
869 			    q->dir == DIR_UP ? DIR_UP : ll->main_dir);
870 	}
871 	q->dir = compute_dir(fo, q->fi->ly0, q->fi->ly1);
872 	q->more_flattened = false;
873 	ll->main_dir = (q->dir == DIR_DOWN ? DIR_DOWN :
874 			q->dir == DIR_UP ? DIR_UP : ll->main_dir);
875 	if (ll->main_dir != DIR_HORIZONTAL) {
876 	    only_horizontal = false;
877 	    break;
878 	}
879 	if (!saved && q->dir != 2) {
880 	    save_q = *q;
881 	    save_fi = *q->fi;
882 	    saved = true;
883 	}
884 	if (q->prev == q->pfirst)
885 	    break;
886     }
887     if (saved) {
888 	*q = save_q;
889 	*q->fi = save_fi;
890     }
891     for (pseg = q->pfirst; pseg != q->plast; pseg = pseg->next) {
892 	p.prev = pseg;
893 	p.pseg = pseg->next;
894 	if (!fo->pseudo_rasterization || only_horizontal
895 		|| p.prev->pt.x != p.pseg->pt.x || p.prev->pt.y != p.pseg->pt.y
896 		|| p.pseg->type == s_curve) {
897 	    init_contour_cursor(ll, &p);
898 	    p.more_flattened = gx_flattened_iterator__next(p.fi);
899 	    p.dir = compute_dir(fo, p.fi->ly0, p.fi->ly1);
900 	    if (p.fi->ly0 > fo->ymax && ll->y_break > p.fi->ly0)
901 		ll->y_break = p.fi->ly0;
902 	    if (p.fi->ly1 > fo->ymax && ll->y_break > p.fi->ly1)
903 		ll->y_break = p.fi->ly1;
904 	    if (p.monotonic_y && p.dir == DIR_HORIZONTAL &&
905 		    !fo->pseudo_rasterization &&
906 		    fixed2int_pixround(p.pseg->pt.y - fo->adjust_below) <
907 		    fixed2int_pixround(p.pseg->pt.y + fo->adjust_above)) {
908 		/* Add it here to avoid double processing in process_h_segments. */
909 		code = add_y_line(p.prev, p.pseg, DIR_HORIZONTAL, ll);
910 		if (code < 0)
911 		    return code;
912 	    }
913 	    if (p.monotonic_y && p.dir == DIR_HORIZONTAL &&
914 		    fo->pseudo_rasterization && only_horizontal) {
915 		/* Add it here to avoid double processing in process_h_segments. */
916 		code = add_y_line(p.prev, p.pseg, DIR_HORIZONTAL, ll);
917 		if (code < 0)
918 		    return code;
919 	    }
920 	    if (p.fi->ly0 >= fo->ymin && p.dir == DIR_UP && ll->main_dir == DIR_DOWN) {
921 		code = start_al_pair(ll, q, &p);
922 		if (code < 0)
923 		    return code;
924 	    }
925 	    if (p.fi->ly0 < fo->ymin && p.fi->ly1 >= fo->ymin) {
926 		if (p.monotonic_y)
927 		    code = add_y_line(p.prev, p.pseg, DIR_UP, ll);
928 		else
929 		    code = add_y_curve_part(ll, p.prev, p.pseg, DIR_UP, p.fi,
930 					p.more_flattened, false, p.monotonic_x);
931 		if (code < 0)
932 		    return code;
933 	    }
934 	    if (p.fi->ly0 >= fo->ymin && p.fi->ly1 < fo->ymin) {
935 		if (p.monotonic_y)
936 		    code = add_y_line(p.prev, p.pseg, DIR_DOWN, ll);
937 		else
938 		    code = add_y_curve_part(ll, p.prev, p.pseg, DIR_DOWN, p.fi,
939 					!p.first_flattened, false, p.monotonic_x);
940 		if (code < 0)
941 		    return code;
942 	    }
943 	    ll->main_dir = (p.dir == DIR_DOWN ? DIR_DOWN :
944 			    p.dir == DIR_UP ? DIR_UP : ll->main_dir);
945 	    if (!p.monotonic_y && p.more_flattened) {
946 		code = start_al_pair_from_min(ll, &p);
947 		if (code < 0)
948 		    return code;
949 	    }
950 	    if (p.dir == DIR_DOWN || p.dir == DIR_HORIZONTAL) {
951 		gx_flattened_iterator *fi1 = q->fi;
952 		q->prev = p.prev;
953 		q->pseg = p.pseg;
954 		q->monotonic_y = p.monotonic_y;
955 		q->more_flattened = p.more_flattened;
956 		q->first_flattened = p.first_flattened;
957 		q->fi = p.fi;
958 		q->dir = p.dir;
959 		p.fi = fi1;
960 	    }
961 	}
962     }
963     q->fi = NULL; /* safety. */
964     return 0;
965 }
966 
967 /*
968  * Construct a Y-sorted list of segments for rasterizing a path.  We assume
969  * the path is non-empty.  Only include non-horizontal lines or (monotonic)
970  * curve segments where one endpoint is locally Y-minimal, and horizontal
971  * lines that might color some additional pixels.
972  */
973 private int
add_y_list(gx_path * ppath,line_list * ll)974 add_y_list(gx_path * ppath, line_list *ll)
975 {
976     subpath *psub = ppath->first_subpath;
977     int close_count = 0;
978     int code;
979     contour_cursor q;
980     gx_flattened_iterator fi;
981 
982     ll->y_break = max_fixed;
983 
984     for (;psub; psub = (subpath *)psub->last->next) {
985 	/* We know that pseg points to a subpath head (s_start). */
986 	segment *pfirst = (segment *)psub;
987 	segment *plast = psub->last, *prev;
988 
989 	q.fi = &fi;
990 	if (plast->type != s_line_close) {
991 	    /* Create a fake s_line_close */
992 	    line_close_segment *lp = &psub->closer;
993 	    segment *next = plast->next;
994 
995 	    lp->next = next;
996 	    lp->prev = plast;
997 	    plast->next = (segment *) lp;
998 	    if (next)
999 		next->prev = (segment *) lp;
1000 	    lp->type = s_line_close;
1001 	    lp->pt = psub->pt;
1002 	    lp->sub = psub;
1003 	    psub->last = plast = (segment *) lp;
1004 	    ll->close_count++;
1005 	}
1006 	prev = plast->prev;
1007 	if (ll->fo->pseudo_rasterization && prev != pfirst &&
1008 		prev->pt.x == plast->pt.x && prev->pt.y == plast->pt.y) {
1009 	    plast = prev;
1010 	    prev = prev->prev;
1011 	}
1012 	q.prev = prev;
1013 	q.pseg = plast;
1014 	q.pfirst = pfirst;
1015 	q.plast = plast;
1016 	code = scan_contour(ll, &q);
1017 	if (code < 0)
1018 	    return code;
1019     }
1020     return close_count;
1021 }
1022 
1023 
1024 private void
step_al(active_line * alp,bool move_iterator)1025 step_al(active_line *alp, bool move_iterator)
1026 {
1027     bool forth = (alp->direction == DIR_UP || !alp->fi.curve);
1028 
1029     if (move_iterator) {
1030 	if (forth)
1031 	    alp->more_flattened = gx_flattened_iterator__next(&alp->fi);
1032 	else
1033 	    alp->more_flattened = gx_flattened_iterator__prev(&alp->fi);
1034     } else
1035 	vd_bar(alp->fi.lx0, alp->fi.ly0, alp->fi.lx1, alp->fi.ly1, 1, RGB(0, 0, 255));
1036     /* Note that we can get alp->fi.ly0 == alp->fi.ly1
1037        if the curve tangent is horizontal. */
1038     alp->start.x = (forth ? alp->fi.lx0 : alp->fi.lx1);
1039     alp->start.y = (forth ? alp->fi.ly0 : alp->fi.ly1);
1040     alp->end.x = (forth ? alp->fi.lx1 : alp->fi.lx0);
1041     alp->end.y = (forth ? alp->fi.ly1 : alp->fi.ly0);
1042     alp->diff.x = alp->end.x - alp->start.x;
1043     alp->diff.y = alp->end.y - alp->start.y;
1044     SET_NUM_ADJUST(alp);
1045     (alp)->y_fast_max = MAX_MINUS_NUM_ADJUST(alp) /
1046       ((alp->diff.x >= 0 ? alp->diff.x : -alp->diff.x) | 1) + alp->start.y;
1047 }
1048 
1049 private void
init_al(active_line * alp,const segment * s0,const segment * s1,const line_list * ll)1050 init_al(active_line *alp, const segment *s0, const segment *s1, const line_list *ll)
1051 {
1052     const segment *ss = (alp->direction == DIR_UP ? s1 : s0);
1053     /* Warning : p0 may be equal to &alp->end. */
1054     bool curve = (ss != NULL && ss->type == s_curve);
1055 
1056     if (curve) {
1057 	if (alp->direction == DIR_UP) {
1058 	    const curve_segment *cs = (const curve_segment *)s1;
1059 	    int k = gx_curve_log2_samples(s0->pt.x, s0->pt.y, cs, ll->fo->fixed_flat);
1060 
1061 	    gx_flattened_iterator__init(&alp->fi,
1062 		s0->pt.x, s0->pt.y, (const curve_segment *)s1, k);
1063 	    step_al(alp, true);
1064 	    if (!ll->fo->fill_by_trapezoids) {
1065 		alp->monotonic_y = (s0->pt.y <= cs->p1.y && cs->p1.y <= cs->p2.y && cs->p2.y <= cs->pt.y);
1066 		alp->monotonic_x = (s0->pt.x <= cs->p1.x && cs->p1.x <= cs->p2.x && cs->p2.x <= cs->pt.x) ||
1067 				   (s0->pt.x >= cs->p1.x && cs->p1.x >= cs->p2.x && cs->p2.x >= cs->pt.x);
1068 	    }
1069 	} else {
1070 	    const curve_segment *cs = (const curve_segment *)s0;
1071 	    int k = gx_curve_log2_samples(s1->pt.x, s1->pt.y, cs, ll->fo->fixed_flat);
1072 	    bool more;
1073 
1074 	    gx_flattened_iterator__init(&alp->fi,
1075 		s1->pt.x, s1->pt.y, (const curve_segment *)s0, k);
1076 	    alp->more_flattened = false;
1077 	    do {
1078 		more = gx_flattened_iterator__next(&alp->fi);
1079 		alp->more_flattened |= more;
1080 	    } while(more);
1081 	    gx_flattened_iterator__switch_to_backscan(&alp->fi, alp->more_flattened);
1082 	    step_al(alp, false);
1083 	    if (!ll->fo->fill_by_trapezoids) {
1084 		alp->monotonic_y = (s0->pt.y >= cs->p1.y && cs->p1.y >= cs->p2.y && cs->p2.y >= cs->pt.y);
1085 		alp->monotonic_x = (s0->pt.x <= cs->p1.x && cs->p1.x <= cs->p2.x && cs->p2.x <= cs->pt.x) ||
1086 				   (s0->pt.x >= cs->p1.x && cs->p1.x >= cs->p2.x && cs->p2.x >= cs->pt.x);
1087 	    }
1088 	}
1089     } else {
1090 	gx_flattened_iterator__init_line(&alp->fi,
1091 		s0->pt.x, s0->pt.y, s1->pt.x, s1->pt.y);
1092 	step_al(alp, true);
1093 	alp->monotonic_x = alp->monotonic_y = true;
1094     }
1095     alp->pseg = s1;
1096 }
1097 /*
1098  * Internal routine to test a segment and add it to the pending list if
1099  * appropriate.
1100  */
1101 private int
add_y_line_aux(const segment * prev_lp,const segment * lp,const gs_fixed_point * curr,const gs_fixed_point * prev,int dir,line_list * ll)1102 add_y_line_aux(const segment * prev_lp, const segment * lp,
1103 	    const gs_fixed_point *curr, const gs_fixed_point *prev, int dir, line_list *ll)
1104 {
1105     active_line *alp = make_al(ll);
1106     if (alp == NULL)
1107 	return_error(gs_error_VMerror);
1108     alp->more_flattened = false;
1109     switch ((alp->direction = dir)) {
1110 	case DIR_UP:
1111 	    init_al(alp, prev_lp, lp, ll);
1112 	    break;
1113 	case DIR_DOWN:
1114 	    init_al(alp, lp, prev_lp, ll);
1115 	    break;
1116 	case DIR_HORIZONTAL:
1117 	    alp->start = *prev;
1118 	    alp->end = *curr;
1119 	    /* Don't need to set dx or y_fast_max */
1120 	    alp->pseg = prev_lp;	/* may not need this either */
1121 	    break;
1122 	default:		/* can't happen */
1123 	    return_error(gs_error_unregistered);
1124     }
1125     insert_y_line(ll, alp);
1126     return 0;
1127 }
1128 
1129 
1130 /* ---------------- Filling loop utilities ---------------- */
1131 
1132 /* Insert a newly active line in the X ordering. */
1133 private void
insert_x_new(active_line * alp,line_list * ll)1134 insert_x_new(active_line * alp, line_list *ll)
1135 {
1136     active_line *next;
1137     active_line *prev = &ll->x_head;
1138 
1139     vd_bar(alp->start.x, alp->start.y, alp->end.x, alp->end.y, 1, RGB(128, 128, 0));
1140     alp->x_current = alp->start.x;
1141     alp->x_next = alp->start.x; /*	If the spot starts with a horizontal segment,
1142 				    we need resort_x_line to work properly
1143 				    in the very beginning. */
1144     while (INCR_EXPR(x_step),
1145 	   (next = prev->next) != 0 && x_order(next, alp) < 0
1146 	)
1147 	prev = next;
1148     alp->next = next;
1149     alp->prev = prev;
1150     if (next != 0)
1151 	next->prev = alp;
1152     prev->next = alp;
1153 }
1154 
1155 /* Insert a newly active line in the h list. */
1156 /* h list isn't ordered because x intervals may overlap. */
1157 /* todo : optimize with maintaining ordered interval list;
1158    Unite contacting inrevals, like we did in add_margin.
1159  */
1160 private inline void
insert_h_new(active_line * alp,line_list * ll)1161 insert_h_new(active_line * alp, line_list *ll)
1162 {
1163     alp->next = ll->h_list0;
1164     alp->prev = 0;
1165     if (ll->h_list0 != 0)
1166 	ll->h_list0->prev = alp;
1167     ll->h_list0 = alp;
1168     /*
1169      * h list keeps horizontal lines for a given y.
1170      * There are 2 lists, corresponding to upper and lower ends
1171      * of the Y-interval, which spot_into_trapezoids currently proceeds.
1172      * Parts of horizontal lines, which do not contact a filled trapezoid,
1173      * are parts of the spot bondairy. They to be marked in
1174      * the 'sect' array.  - see process_h_lists.
1175      */
1176 }
1177 
1178 private inline void
remove_al(const line_list * ll,active_line * alp)1179 remove_al(const line_list *ll, active_line *alp)
1180 {
1181     active_line *nlp = alp->next;
1182 
1183     alp->prev->next = nlp;
1184     if (nlp)
1185 	nlp->prev = alp->prev;
1186     if_debug1('F', "[F]drop 0x%lx\n", (ulong) alp);
1187 }
1188 
1189 /*
1190  * Handle a line segment that just ended.  Return true iff this was
1191  * the end of a line sequence.
1192  */
1193 private bool
end_x_line(active_line * alp,const line_list * ll,bool update)1194 end_x_line(active_line *alp, const line_list *ll, bool update)
1195 {
1196     const segment *pseg = alp->pseg;
1197     /*
1198      * The computation of next relies on the fact that
1199      * all subpaths have been closed.  When we cycle
1200      * around to the other end of a subpath, we must be
1201      * sure not to process the start/end point twice.
1202      */
1203     const segment *next =
1204 	(alp->direction == DIR_UP ?
1205 	 (			/* Upward line, go forward along path. */
1206 	  pseg->type == s_line_close ?	/* end of subpath */
1207 	  ((const line_close_segment *)pseg)->sub->next :
1208 	  pseg->next) :
1209 	 (			/* Downward line, go backward along path. */
1210 	  pseg->type == s_start ?	/* start of subpath */
1211 	  ((const subpath *)pseg)->last->prev :
1212 	  pseg->prev)
1213 	);
1214 
1215     if (alp->end.y < alp->start.y) {
1216 	/* fixme: The condition above causes a horizontal
1217 	   part of a curve near an Y maximum to process twice :
1218 	   once scanning the left spot boundary and once scanning the right one.
1219 	   In both cases it will go to the H list.
1220 	   However the dropout prevention logic isn't
1221 	   sensitive to that, and such segments does not affect
1222 	   trapezoids. Thus the resulting raster doesn't depend on that.
1223 	   However it would be nice to improve someday.
1224 	 */
1225 	remove_al(ll, alp);
1226 	return true;
1227     } else if (alp->more_flattened)
1228 	return false;
1229     init_al(alp, pseg, next, ll);
1230     if (alp->start.y > alp->end.y) {
1231 	/* See comment above. */
1232 	remove_al(ll, alp);
1233 	return true;
1234     }
1235     alp->x_current = alp->x_next = alp->start.x;
1236     vd_bar(alp->start.x, alp->start.y, alp->end.x, alp->end.y, 1, RGB(128, 0, 128));
1237     print_al("repl", alp);
1238     return false;
1239 }
1240 
1241 private inline int
add_margin(line_list * ll,active_line * flp,active_line * alp,fixed y0,fixed y1)1242 add_margin(line_list * ll, active_line * flp, active_line * alp, fixed y0, fixed y1)
1243 {   vd_bar(alp->start.x, alp->start.y, alp->end.x, alp->end.y, 1, RGB(255, 255, 255));
1244     vd_bar(flp->start.x, flp->start.y, flp->end.x, flp->end.y, 1, RGB(255, 255, 255));
1245     return continue_margin_common(ll, &ll->margin_set0, flp, alp, y0, y1);
1246 }
1247 
1248 private inline int
continue_margin(line_list * ll,active_line * flp,active_line * alp,fixed y0,fixed y1)1249 continue_margin(line_list * ll, active_line * flp, active_line * alp, fixed y0, fixed y1)
1250 {
1251     return continue_margin_common(ll, &ll->margin_set0, flp, alp, y0, y1);
1252 }
1253 
1254 private inline int
complete_margin(line_list * ll,active_line * flp,active_line * alp,fixed y0,fixed y1)1255 complete_margin(line_list * ll, active_line * flp, active_line * alp, fixed y0, fixed y1)
1256 {
1257     return continue_margin_common(ll, &ll->margin_set1, flp, alp, y0, y1);
1258 }
1259 
1260 /*
1261  * Handle the case of a slanted trapezoid with adjustment.
1262  * To do this exactly right requires filling a central trapezoid
1263  * (or rectangle) plus two horizontal almost-rectangles.
1264  */
1265 private int
fill_slant_adjust(const line_list * ll,const active_line * flp,const active_line * alp,fixed y,fixed y1)1266 fill_slant_adjust(const line_list *ll,
1267 	const active_line *flp, const active_line *alp, fixed y, fixed y1)
1268 {
1269     const fill_options * const fo = ll->fo;
1270     const fixed Yb = y - fo->adjust_below;
1271     const fixed Ya = y + fo->adjust_above;
1272     const fixed Y1b = y1 - fo->adjust_below;
1273     const fixed Y1a = y1 + fo->adjust_above;
1274     const gs_fixed_edge *plbot, *prbot, *pltop, *prtop;
1275     gs_fixed_edge vert_left, slant_left, vert_right, slant_right;
1276     int code;
1277 
1278     INCR(slant);
1279     vd_quad(flp->x_current, y, alp->x_current, y,
1280 	    alp->x_next, y1, flp->x_next, y1, 1, VD_TRAP_COLOR); /* fixme: Wrong X. */
1281 
1282     /* Set up all the edges, even though we may not need them all. */
1283 
1284     if (flp->start.x < flp->end.x) {
1285 	vert_left.start.x = vert_left.end.x = flp->x_current - fo->adjust_left;
1286 	vert_left.start.y = Yb, vert_left.end.y = Ya;
1287 	vert_right.start.x = vert_right.end.x = alp->x_next + fo->adjust_right;
1288 	vert_right.start.y = Y1b, vert_right.end.y = Y1a;
1289 	slant_left.start.y = flp->start.y + fo->adjust_above;
1290 	slant_left.end.y = flp->end.y + fo->adjust_above;
1291 	slant_right.start.y = alp->start.y - fo->adjust_below;
1292 	slant_right.end.y = alp->end.y - fo->adjust_below;
1293 	plbot = &vert_left, prbot = &slant_right;
1294 	pltop = &slant_left, prtop = &vert_right;
1295     } else {
1296 	vert_left.start.x = vert_left.end.x = flp->x_next - fo->adjust_left;
1297 	vert_left.start.y = Y1b, vert_left.end.y = Y1a;
1298 	vert_right.start.x = vert_right.end.x = alp->x_current + fo->adjust_right;
1299 	vert_right.start.y = Yb, vert_right.end.y = Ya;
1300 	slant_left.start.y = flp->start.y - fo->adjust_below;
1301 	slant_left.end.y = flp->end.y - fo->adjust_below;
1302 	slant_right.start.y = alp->start.y + fo->adjust_above;
1303 	slant_right.end.y = alp->end.y + fo->adjust_above;
1304 	plbot = &slant_left, prbot = &vert_right;
1305 	pltop = &vert_left, prtop = &slant_right;
1306     }
1307     slant_left.start.x = flp->start.x - fo->adjust_left;
1308     slant_left.end.x = flp->end.x - fo->adjust_left;
1309     slant_right.start.x = alp->start.x + fo->adjust_right;
1310     slant_right.end.x = alp->end.x + fo->adjust_right;
1311 
1312     if (Ya >= Y1b) {
1313 	/*
1314 	 * The upper and lower adjustment bands overlap.
1315 	 * Since the entire entity is less than 2 pixels high
1316 	 * in this case, we could handle it very efficiently
1317 	 * with no more than 2 rectangle fills, but for right now
1318 	 * we don't attempt to do this.
1319 	 */
1320 	int iYb = fixed2int_var_pixround(Yb);
1321 	int iYa = fixed2int_var_pixround(Ya);
1322 	int iY1b = fixed2int_var_pixround(Y1b);
1323 	int iY1a = fixed2int_var_pixround(Y1a);
1324 
1325 	INCR(slant_shallow);
1326 	if (iY1b > iYb) {
1327 	    code = fo->fill_trap(fo->dev, plbot, prbot,
1328 				 Yb, Y1b, false, fo->pdevc, fo->lop);
1329 	    if (code < 0)
1330 		return code;
1331 	}
1332 	if (iYa > iY1b) {
1333 	    int ix = fixed2int_var_pixround(vert_left.start.x);
1334 	    int iw = fixed2int_var_pixround(vert_right.start.x) - ix;
1335 
1336 	    code = gx_fill_rectangle_device_rop(ix, iY1b, iw, iYa - iY1b,
1337 			fo->pdevc, fo->dev, fo->lop);
1338 	    if (code < 0)
1339 		return code;
1340 	}
1341 	if (iY1a > iYa)
1342 	    code = fo->fill_trap(fo->dev, pltop, prtop,
1343 				 Ya, Y1a, false, fo->pdevc, fo->lop);
1344 	else
1345 	    code = 0;
1346     } else {
1347 	/*
1348 	 * Clip the trapezoid if possible.  This can save a lot
1349 	 * of work when filling paths that cross band boundaries.
1350 	 */
1351 	fixed Yac;
1352 
1353 	if (fo->pbox->p.y < Ya) {
1354 	    code = fo->fill_trap(fo->dev, plbot, prbot,
1355 				 Yb, Ya, false, fo->pdevc, fo->lop);
1356 	    if (code < 0)
1357 		return code;
1358 	    Yac = Ya;
1359 	} else
1360 	    Yac = fo->pbox->p.y;
1361 	if (fo->pbox->q.y > Y1b) {
1362 	    code = fo->fill_trap(fo->dev, &slant_left, &slant_right,
1363 				 Yac, Y1b, false, fo->pdevc, fo->lop);
1364 	    if (code < 0)
1365 		return code;
1366 	    code = fo->fill_trap(fo->dev, pltop, prtop,
1367 				 Y1b, Y1a, false, fo->pdevc, fo->lop);
1368 	} else
1369 	    code = fo->fill_trap(fo->dev, &slant_left, &slant_right,
1370 				 Yac, fo->pbox->q.y, false, fo->pdevc, fo->lop);
1371     }
1372     return code;
1373 }
1374 
1375 /* Re-sort the x list by moving alp backward to its proper spot. */
1376 private inline void
resort_x_line(active_line * alp)1377 resort_x_line(active_line * alp)
1378 {
1379     active_line *prev = alp->prev;
1380     active_line *next = alp->next;
1381 
1382     prev->next = next;
1383     if (next)
1384 	next->prev = prev;
1385     while (x_order(prev, alp) > 0) {
1386 	if_debug2('F', "[F]swap 0x%lx,0x%lx\n",
1387 		  (ulong) alp, (ulong) prev);
1388 	next = prev, prev = prev->prev;
1389     }
1390     alp->next = next;
1391     alp->prev = prev;
1392     /* next might be null, if alp was in the correct spot already. */
1393     if (next)
1394 	next->prev = alp;
1395     prev->next = alp;
1396 }
1397 
1398 /* Move active lines by Y. */
1399 private inline void
move_al_by_y(line_list * ll,fixed y1)1400 move_al_by_y(line_list *ll, fixed y1)
1401 {
1402     fixed x;
1403     active_line *alp, *nlp;
1404 
1405     for (x = min_fixed, alp = ll->x_list; alp != 0; alp = nlp) {
1406 	bool notend = false;
1407 	alp->x_current = alp->x_next;
1408 
1409 	nlp = alp->next;
1410 	if (alp->end.y == y1 && alp->more_flattened) {
1411 	    step_al(alp, true);
1412 	    alp->x_current = alp->x_next = alp->start.x;
1413 	    notend = (alp->end.y >= alp->start.y);
1414 	}
1415 	if (alp->end.y > y1 || notend || !end_x_line(alp, ll, true)) {
1416 	    if (alp->x_next <= x)
1417 		resort_x_line(alp);
1418 	    else
1419 		x = alp->x_next;
1420 	}
1421     }
1422     if (ll->x_list != 0 && ll->fo->pseudo_rasterization) {
1423 	/* Ensure that contacting vertical stems are properly ordered.
1424 	   We don't want to unite contacting stems into
1425 	   a single margin, because it can cause a dropout :
1426 	   narrow stems are widened against a dropout, but
1427 	   an united wide one may be left unwidened.
1428 	 */
1429 	for (alp = ll->x_list; alp->next != 0; ) {
1430 	    if (alp->start.x == alp->end.x &&
1431 		alp->start.x == alp->next->start.x &&
1432 		alp->next->start.x == alp->next->end.x &&
1433 		alp->direction > alp->next->direction) {
1434 		/* Exchange. */
1435 		active_line *prev = alp->prev;
1436 		active_line *next = alp->next;
1437 		active_line *next2 = next->next;
1438 		if (prev)
1439 		    prev->next = next;
1440 		else
1441 		    ll->x_list = next;
1442 		next->prev = prev;
1443 		alp->prev = next;
1444 		alp->next = next2;
1445 		next->next = alp;
1446 		if (next2)
1447 		    next2->prev = alp;
1448 	    } else
1449 		alp = alp->next;
1450 	}
1451     }
1452 }
1453 
1454 /* Process horizontal segment of curves. */
1455 private inline int
process_h_segments(line_list * ll,fixed y)1456 process_h_segments(line_list *ll, fixed y)
1457 {
1458     active_line *alp, *nlp;
1459     int code, inserted = 0;
1460 
1461     for (alp = ll->x_list; alp != 0; alp = nlp) {
1462 	nlp = alp->next;
1463 	if (alp->start.y == y && alp->end.y == y) {
1464 	    if (ll->fo->pseudo_rasterization) {
1465 		code = add_y_line_aux(NULL, NULL, &alp->start, &alp->end, DIR_HORIZONTAL, ll);
1466 		if (code < 0)
1467 		    return code;
1468 	    }
1469 	    inserted = 1;
1470 	}
1471     }
1472     return inserted;
1473     /* After this should call move_al_by_y and step to the next band. */
1474 }
1475 
1476 private inline int
loop_fill_trap_np(const line_list * ll,const gs_fixed_edge * le,const gs_fixed_edge * re,fixed y,fixed y1)1477 loop_fill_trap_np(const line_list *ll, const gs_fixed_edge *le, const gs_fixed_edge *re, fixed y, fixed y1)
1478 {
1479     const fill_options * const fo = ll->fo;
1480     fixed ybot = max(y, fo->pbox->p.y);
1481     fixed ytop = min(y1, fo->pbox->q.y);
1482 
1483     if (ybot >= ytop)
1484 	return 0;
1485     vd_quad(le->start.x, ybot, re->start.x, ybot, re->end.x, ytop, le->end.x, ytop, 1, VD_TRAP_COLOR);
1486     return (*fo->fill_trap)
1487 	(fo->dev, le, re, ybot, ytop, false, fo->pdevc, fo->lop);
1488 }
1489 
1490 /* Define variants of the algorithm for filling a slanted trapezoid. */
1491 #define TEMPLATE_slant_into_trapezoids slant_into_trapezoids__fd
1492 #define FILL_DIRECT 1
1493 #include "gxfillts.h"
1494 #undef TEMPLATE_slant_into_trapezoids
1495 #undef FILL_DIRECT
1496 
1497 #define TEMPLATE_slant_into_trapezoids slant_into_trapezoids__nd
1498 #define FILL_DIRECT 0
1499 #include "gxfillts.h"
1500 #undef TEMPLATE_slant_into_trapezoids
1501 #undef FILL_DIRECT
1502 
1503 
1504 #define COVERING_PIXEL_CENTERS(y, y1, adjust_below, adjust_above)\
1505     (fixed_pixround(y - adjust_below) < fixed_pixround(y1 + adjust_above))
1506 
1507 /* Find an intersection within y, y1. */
1508 /* lp->x_current, lp->x_next must be set for y, y1. */
1509 private bool
intersect(active_line * endp,active_line * alp,fixed y,fixed y1,fixed * p_y_new)1510 intersect(active_line *endp, active_line *alp, fixed y, fixed y1, fixed *p_y_new)
1511 {
1512     fixed y_new, dy;
1513     fixed dx_old = alp->x_current - endp->x_current;
1514     fixed dx_den = dx_old + endp->x_next - alp->x_next;
1515 
1516     if (dx_den <= dx_old)
1517 	return false; /* Intersection isn't possible. */
1518     dy = y1 - y;
1519     if_debug3('F', "[F]cross: dy=%g, dx_old=%g, dx_new=%g\n",
1520 	      fixed2float(dy), fixed2float(dx_old),
1521 	      fixed2float(dx_den - dx_old));
1522     /* Do the computation in single precision */
1523     /* if the values are small enough. */
1524     y_new =
1525 	((dy | dx_old) < 1L << (size_of(fixed) * 4 - 1) ?
1526 	 dy * dx_old / dx_den :
1527 	 (INCR_EXPR(mq_cross), fixed_mult_quo(dy, dx_old, dx_den)))
1528 	+ y;
1529     /* The crossing value doesn't have to be */
1530     /* very accurate, but it does have to be */
1531     /* greater than y and less than y1. */
1532     if_debug3('F', "[F]cross y=%g, y_new=%g, y1=%g\n",
1533 	      fixed2float(y), fixed2float(y_new),
1534 	      fixed2float(y1));
1535     if (y_new <= y) {
1536 	/*
1537 	 * This isn't possible.  Recompute the intersection
1538 	 * accurately.
1539 	 */
1540 	fixed ys, xs0, xs1, ye, xe0, xe1, dy, dx0, dx1;
1541 
1542 	INCR(cross_slow);
1543 	if (endp->start.y < alp->start.y)
1544 	    ys = alp->start.y,
1545 		xs0 = AL_X_AT_Y(endp, ys), xs1 = alp->start.x;
1546 	else
1547 	    ys = endp->start.y,
1548 		xs0 = endp->start.x, xs1 = AL_X_AT_Y(alp, ys);
1549 	if (endp->end.y > alp->end.y)
1550 	    ye = alp->end.y,
1551 		xe0 = AL_X_AT_Y(endp, ye), xe1 = alp->end.x;
1552 	else
1553 	    ye = endp->end.y,
1554 		xe0 = endp->end.x, xe1 = AL_X_AT_Y(alp, ye);
1555 	dy = ye - ys;
1556 	dx0 = xe0 - xs0;
1557 	dx1 = xe1 - xs1;
1558 	/* We need xs0 + cross * dx0 == xs1 + cross * dx1. */
1559 	if (dx0 == dx1) {
1560 	    /* The two lines are coincident.  Do nothing. */
1561 	    y_new = y1;
1562 	} else {
1563 	    double cross = (double)(xs0 - xs1) / (dx1 - dx0);
1564 
1565 	    y_new = (fixed)(ys + cross * dy);
1566 	    if (y_new <= y) {
1567 		/*
1568 		 * This can only happen through some kind of
1569 		 * numeric disaster, but we have to check.
1570 		 */
1571 		INCR(cross_low);
1572 		y_new = y + fixed_epsilon;
1573 	    }
1574 	}
1575     }
1576     *p_y_new = y_new;
1577     return true;
1578 }
1579 
1580 private inline void
set_x_next(active_line * endp,active_line * alp,fixed x)1581 set_x_next(active_line *endp, active_line *alp, fixed x)
1582 {
1583     while(endp != alp) {
1584 	endp->x_next = x;
1585 	endp = endp->next;
1586     }
1587 }
1588 
1589 private inline int
coord_weight(const active_line * alp)1590 coord_weight(const active_line *alp)
1591 {
1592     return 1 + min(any_abs((int)((int64_t)alp->diff.y * 8 / alp->diff.x)), 256);
1593 }
1594 
1595 
1596 /* Find intersections of active lines within the band.
1597    Intersect and reorder them, and correct the bund top. */
1598 private void
intersect_al(line_list * ll,fixed y,fixed * y_top,int draw,bool all_bands)1599 intersect_al(line_list *ll, fixed y, fixed *y_top, int draw, bool all_bands)
1600 {
1601     fixed x = min_fixed, y1 = *y_top;
1602     active_line *alp, *stopx = NULL;
1603     active_line *endp = NULL;
1604 
1605     /* don't bother if no pixels with no pseudo_rasterization */
1606     if (y == y1) {
1607 	/* Rather the intersection algorithm can handle this case with
1608 	   retrieving x_next equal to x_current,
1609 	   we bypass it for safety reason.
1610 	 */
1611     } else if (ll->fo->pseudo_rasterization || draw >= 0 || all_bands) {
1612 	/*
1613 	 * Loop invariants:
1614 	 *	alp = endp->next;
1615 	 *	for all lines lp from stopx up to alp,
1616 	 *	  lp->x_next = AL_X_AT_Y(lp, y1).
1617 	 */
1618 	for (alp = stopx = ll->x_list;
1619 	     INCR_EXPR(find_y), alp != 0;
1620 	     endp = alp, alp = alp->next
1621 	    ) {
1622 	    fixed nx = AL_X_AT_Y(alp, y1);
1623 	    fixed y_new;
1624 
1625 	    alp->x_next = nx;
1626 	    /* Check for intersecting lines. */
1627 	    if (nx >= x)
1628 		x = nx;
1629 	    else if (alp->x_current >= endp->x_current &&
1630 		     intersect(endp, alp, y, y1, &y_new)) {
1631 		if (y_new <= y1) {
1632 		    stopx = endp;
1633 		    y1 = y_new;
1634 		    if (endp->diff.x == 0)
1635 			nx = endp->start.x;
1636 		    else if (alp->diff.x == 0)
1637 			nx = alp->start.x;
1638 		    else {
1639 			fixed nx0 = AL_X_AT_Y(endp, y1);
1640 			fixed nx1 = AL_X_AT_Y(alp, y1);
1641 			if (nx0 != nx1) {
1642 			    /* Different results due to arithmetic errors.
1643 			       Choose an imtermediate point.
1644 			       We don't like to use floating numbners here,
1645 			       but the code with int64_t isn't much better. */
1646 			    int64_t w0 = coord_weight(endp);
1647 			    int64_t w1 = coord_weight(alp);
1648 
1649 			    nx = (fixed)((w0 * nx0 + w1 * nx1) / (w0 + w1));
1650 			} else
1651 			    nx = nx0;
1652 		    }
1653 		    endp->x_next = alp->x_next = nx;  /* Ensure same X. */
1654 		    draw = 0;
1655 		    /* Can't guarantee same x for triple intersections here.
1656 		       Will take care below */
1657 		}
1658 		if (nx > x)
1659 		    x = nx;
1660 	    }
1661 	}
1662 	/* Recompute next_x for lines before the intersection. */
1663 	for (alp = ll->x_list; alp != stopx; alp = alp->next)
1664 	    alp->x_next = AL_X_AT_Y(alp, y1);
1665 	/* Ensure X monotonity (particularly imporoves triple intersections). */
1666 	if (ll->x_list != NULL) {
1667 	    for (;;) {
1668 		fixed x1;
1669 		double sx = 0xbaadf00d; /* 'fixed' can overflow. We operate 7-bytes integers. */
1670 		int k = 0xbaadf00d, n;
1671 
1672 		endp = ll->x_list;
1673 		x1 = endp->x_next;
1674 		for (alp = endp->next; alp != NULL; x1 = alp->x_next, alp = alp->next)
1675 		    if (alp->x_next < x1)
1676 			break;
1677 		if (alp == NULL)
1678 		    break;
1679 		x1 = endp->x_next;
1680 		n = 0;
1681 		for (alp = endp->next; alp != NULL; alp = alp->next) {
1682 		     x = alp->x_next;
1683 		     if (x < x1) {
1684 			if (n == 0) {
1685 			    if (endp->diff.x == 0) {
1686 				k = -1;
1687 				sx = x1;
1688 			    } else {
1689 				k = coord_weight(endp);
1690 				sx = (double)x1 * k;
1691 			    }
1692 			    n = 1;
1693 			}
1694 			n++;
1695 			if (alp->diff.x == 0) {
1696 			    /* Vertical lines have a higher priority. */
1697 			    if (k <= -1) {
1698 				sx += x;
1699 				k--;
1700 			    } else {
1701 				k = -1;
1702 				sx = x;
1703 			    }
1704 			} else if (k > 0) {
1705 			    int w = coord_weight(alp);
1706 
1707 			    sx += (double)x * w;
1708 			    k += w;
1709 			}
1710 		     } else {
1711 			if (n > 1) {
1712 			    k = any_abs(k);
1713 			    set_x_next(endp, alp, (fixed)((sx + k / 2) / k));
1714 			}
1715 			x1 = alp->x_next;
1716 			n = 0;
1717 			endp = alp;
1718 		     }
1719 		}
1720 		if (n > 1) {
1721 		    k = any_abs(k);
1722     		    set_x_next(endp, alp, (fixed)((sx + k / 2) / k));
1723 		}
1724 	    }
1725 	}
1726     } else {
1727 	/* Recompute next_x for lines before the intersection. */
1728 	for (alp = ll->x_list; alp != stopx; alp = alp->next)
1729 	    alp->x_next = AL_X_AT_Y(alp, y1);
1730     }
1731 #ifdef DEBUG
1732     if (gs_debug_c('F')) {
1733 	dlprintf1("[F]after loop: y1=%f\n", fixed2float(y1));
1734 	print_line_list(ll->x_list);
1735     }
1736 #endif
1737     *y_top = y1;
1738 }
1739 
1740 /* ---------------- Trapezoid filling loop ---------------- */
1741 
1742 /* Generate specialized algorythms for the most important cases : */
1743 
1744 #define IS_SPOTAN 1
1745 #define PSEUDO_RASTERIZATION 0
1746 #define FILL_ADJUST 0
1747 #define FILL_DIRECT 1
1748 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__spotan
1749 #include "gxfilltr.h"
1750 #undef IS_SPOTAN
1751 #undef PSEUDO_RASTERIZATION
1752 #undef FILL_ADJUST
1753 #undef FILL_DIRECT
1754 #undef TEMPLATE_spot_into_trapezoids
1755 
1756 #define IS_SPOTAN 0
1757 #define PSEUDO_RASTERIZATION 1
1758 #define FILL_ADJUST 0
1759 #define FILL_DIRECT 1
1760 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__pr_fd
1761 #include "gxfilltr.h"
1762 #undef IS_SPOTAN
1763 #undef PSEUDO_RASTERIZATION
1764 #undef FILL_ADJUST
1765 #undef FILL_DIRECT
1766 #undef TEMPLATE_spot_into_trapezoids
1767 
1768 #define IS_SPOTAN 0
1769 #define PSEUDO_RASTERIZATION 1
1770 #define FILL_ADJUST 0
1771 #define FILL_DIRECT 0
1772 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__pr_nd
1773 #include "gxfilltr.h"
1774 #undef IS_SPOTAN
1775 #undef PSEUDO_RASTERIZATION
1776 #undef FILL_ADJUST
1777 #undef FILL_DIRECT
1778 #undef TEMPLATE_spot_into_trapezoids
1779 
1780 #define IS_SPOTAN 0
1781 #define PSEUDO_RASTERIZATION 0
1782 #define FILL_ADJUST 1
1783 #define FILL_DIRECT 1
1784 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__aj_fd
1785 #include "gxfilltr.h"
1786 #undef IS_SPOTAN
1787 #undef PSEUDO_RASTERIZATION
1788 #undef FILL_ADJUST
1789 #undef FILL_DIRECT
1790 #undef TEMPLATE_spot_into_trapezoids
1791 
1792 #define IS_SPOTAN 0
1793 #define PSEUDO_RASTERIZATION 0
1794 #define FILL_ADJUST 1
1795 #define FILL_DIRECT 0
1796 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__aj_nd
1797 #include "gxfilltr.h"
1798 #undef IS_SPOTAN
1799 #undef PSEUDO_RASTERIZATION
1800 #undef FILL_ADJUST
1801 #undef FILL_DIRECT
1802 #undef TEMPLATE_spot_into_trapezoids
1803 
1804 #define IS_SPOTAN 0
1805 #define PSEUDO_RASTERIZATION 0
1806 #define FILL_ADJUST 0
1807 #define FILL_DIRECT 1
1808 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__nj_fd
1809 #include "gxfilltr.h"
1810 #undef IS_SPOTAN
1811 #undef PSEUDO_RASTERIZATION
1812 #undef FILL_ADJUST
1813 #undef FILL_DIRECT
1814 #undef TEMPLATE_spot_into_trapezoids
1815 
1816 #define IS_SPOTAN 0
1817 #define PSEUDO_RASTERIZATION 0
1818 #define FILL_ADJUST 0
1819 #define FILL_DIRECT 0
1820 #define TEMPLATE_spot_into_trapezoids spot_into_trapezoids__nj_nd
1821 #include "gxfilltr.h"
1822 #undef IS_SPOTAN
1823 #undef PSEUDO_RASTERIZATION
1824 #undef FILL_ADJUST
1825 #undef FILL_DIRECT
1826 #undef TEMPLATE_spot_into_trapezoids
1827 
1828 
1829 /* Main filling loop.  Takes lines off of y_list and adds them to */
1830 /* x_list as needed.  band_mask limits the size of each band, */
1831 /* by requiring that ((y1 - 1) & band_mask) == (y0 & band_mask). */
1832 private int
spot_into_trapezoids(line_list * ll,fixed band_mask)1833 spot_into_trapezoids(line_list *ll, fixed band_mask)
1834 {
1835     /* For better porformance, choose a specialized algorithm : */
1836     const fill_options * const fo = ll->fo;
1837 
1838     if (fo->is_spotan)
1839 	return spot_into_trapezoids__spotan(ll, band_mask);
1840     if (fo->pseudo_rasterization) {
1841 	if (fo->fill_direct)
1842 	    return spot_into_trapezoids__pr_fd(ll, band_mask);
1843 	else
1844 	    return spot_into_trapezoids__pr_nd(ll, band_mask);
1845     }
1846     if (fo->adjust_below | fo->adjust_above | fo->adjust_left | fo->adjust_right) {
1847 	if (fo->fill_direct)
1848 	    return spot_into_trapezoids__aj_fd(ll, band_mask);
1849 	else
1850 	    return spot_into_trapezoids__aj_nd(ll, band_mask);
1851     } else {
1852 	if (fo->fill_direct)
1853 	    return spot_into_trapezoids__nj_fd(ll, band_mask);
1854 	else
1855 	    return spot_into_trapezoids__nj_nd(ll, band_mask);
1856     }
1857 }
1858 
1859 /* ---------------- Range list management ---------------- */
1860 
1861 /*
1862  * We originally thought we would store fixed values in coordinate ranges,
1863  * but it turned out we want to store integers.
1864  */
1865 typedef int coord_value_t;
1866 #define MIN_COORD_VALUE min_int
1867 #define MAX_COORD_VALUE max_int
1868 /*
1869  * The invariant for coord_range_ts in a coord_range_list_t:
1870  *	if prev == 0:
1871  *		next != 0
1872  *		rmin == rmax == MIN_COORD_VALUE
1873  *	else if next == 0:
1874  *		prev != 0
1875  *		rmin == rmax == MAX_COORD_VALUE
1876  *	else
1877  *		rmin < rmax
1878  *	if prev != 0:
1879  *		prev->next == this
1880  *		prev->rmax < rmin
1881  *	if next != 0:
1882  *		next->prev = this
1883  *		next->rmin > rmax
1884  * A coord_range_list_t has a boundary element at each end to avoid having
1885  * to test for null pointers in the insertion loop.  The boundary elements
1886  * are the only empty ranges.
1887  */
1888 typedef struct coord_range_s coord_range_t;
1889 struct coord_range_s {
1890     coord_value_t rmin, rmax;
1891     coord_range_t *prev, *next;
1892     coord_range_t *alloc_next;
1893 };
1894 /* We declare coord_range_ts as simple because they only exist transiently. */
1895 gs_private_st_simple(st_coord_range, coord_range_t, "coord_range_t");
1896 
1897 typedef struct coord_range_list_s {
1898     gs_memory_t *memory;
1899     struct rl_ {
1900 	coord_range_t *first, *next, *limit;
1901     } local;
1902     coord_range_t *allocated;
1903     coord_range_t *freed;
1904     coord_range_t *current;
1905     coord_range_t first, last;
1906 } coord_range_list_t;
1907 
1908 private coord_range_t *
range_alloc(coord_range_list_t * pcrl)1909 range_alloc(coord_range_list_t *pcrl)
1910 {
1911     coord_range_t *pcr;
1912 
1913     if (pcrl->freed) {
1914 	pcr = pcrl->freed;
1915 	pcrl->freed = pcr->next;
1916     } else if (pcrl->local.next < pcrl->local.limit)
1917 	pcr = pcrl->local.next++;
1918     else {
1919 	pcr = gs_alloc_struct(pcrl->memory, coord_range_t, &st_coord_range,
1920 			      "range_alloc");
1921 	if (pcr == 0)
1922 	    return 0;
1923 	pcr->alloc_next = pcrl->allocated;
1924 	pcrl->allocated = pcr;
1925     }
1926     return pcr;
1927 }
1928 
1929 private void
range_delete(coord_range_list_t * pcrl,coord_range_t * pcr)1930 range_delete(coord_range_list_t *pcrl, coord_range_t *pcr)
1931 {
1932     if_debug3('Q', "[Qr]delete 0x%lx: [%d,%d)\n", (ulong)pcr, pcr->rmin,
1933 	      pcr->rmax);
1934     pcr->prev->next = pcr->next;
1935     pcr->next->prev = pcr->prev;
1936     pcr->next = pcrl->freed;
1937     pcrl->freed = pcr;
1938 }
1939 
1940 private void
range_list_clear(coord_range_list_t * pcrl)1941 range_list_clear(coord_range_list_t *pcrl)
1942 {
1943     if_debug0('Q', "[Qr]clearing\n");
1944     pcrl->first.next = &pcrl->last;
1945     pcrl->last.prev = &pcrl->first;
1946     pcrl->current = &pcrl->last;
1947 }
1948 
1949 /* ------ "Public" procedures ------ */
1950 
1951 /* Initialize a range list.  We require num_local >= 2. */
1952 private void range_list_clear(coord_range_list_t *);
1953 private void
range_list_init(coord_range_list_t * pcrl,coord_range_t * pcr_local,int num_local,gs_memory_t * mem)1954 range_list_init(coord_range_list_t *pcrl, coord_range_t *pcr_local,
1955 		int num_local, gs_memory_t *mem)
1956 {
1957     pcrl->memory = mem;
1958     pcrl->local.first = pcrl->local.next = pcr_local;
1959     pcrl->local.limit = pcr_local + num_local;
1960     pcrl->allocated = pcrl->freed = 0;
1961     pcrl->first.rmin = pcrl->first.rmax = MIN_COORD_VALUE;
1962     pcrl->first.prev = 0;
1963     pcrl->last.rmin = pcrl->last.rmax = MAX_COORD_VALUE;
1964     pcrl->last.next = 0;
1965     range_list_clear(pcrl);
1966 }
1967 
1968 /* Reset an initialized range list to the empty state. */
1969 private void
range_list_reset(coord_range_list_t * pcrl)1970 range_list_reset(coord_range_list_t *pcrl)
1971 {
1972     if (pcrl->first.next != &pcrl->last) {
1973 	pcrl->last.prev->next = pcrl->freed;
1974 	pcrl->freed = pcrl->first.next;
1975 	range_list_clear(pcrl);
1976     }
1977 }
1978 
1979 /*
1980  * Move the cursor to the beginning of a range list, in the belief that
1981  * the next added ranges will roughly parallel the existing ones.
1982  * (Only affects performance, not function.)
1983  */
1984 inline private void
range_list_rescan(coord_range_list_t * pcrl)1985 range_list_rescan(coord_range_list_t *pcrl)
1986 {
1987     pcrl->current = pcrl->first.next;
1988 }
1989 
1990 /* Free a range list. */
1991 private void
range_list_free(coord_range_list_t * pcrl)1992 range_list_free(coord_range_list_t *pcrl)
1993 {
1994     coord_range_t *pcr;
1995 
1996     while ((pcr = pcrl->allocated) != 0) {
1997 	coord_range_t *next = pcr->alloc_next;
1998 
1999 	gs_free_object(pcrl->memory, pcr, "range_list_free");
2000 	pcrl->allocated = next;
2001     }
2002 }
2003 
2004 /* Add a range. */
2005 private int
range_list_add(coord_range_list_t * pcrl,coord_value_t rmin,coord_value_t rmax)2006 range_list_add(coord_range_list_t *pcrl, coord_value_t rmin, coord_value_t rmax)
2007 {
2008     coord_range_t *pcr = pcrl->current;
2009 
2010     if (rmin >= rmax)
2011 	return 0;
2012     /*
2013      * Usually, ranges are added in increasing order within each scan line,
2014      * and overlapping ranges don't differ much.  Optimize accordingly.
2015      */
2016  top:
2017     if (rmax < pcr->rmin) {
2018 	if (rmin > pcr->prev->rmax)
2019 	    goto ins;
2020 	pcr = pcr->prev;
2021 	goto top;
2022     }
2023     if (rmin > pcr->rmax) {
2024 	pcr = pcr->next;
2025 	if (rmax < pcr->rmin)
2026 	    goto ins;
2027 	goto top;
2028     }
2029     /*
2030      * Now we know that (rmin,rmax) overlaps (pcr->rmin,pcr->rmax).
2031      * Don't delete or merge into the special min and max ranges.
2032      */
2033     while (rmin <= pcr->prev->rmax) {
2034 	/* Merge the range below pcr into this one. */
2035 	if (!pcr->prev->prev)
2036 	    break;		/* don't merge into the min range */
2037 	pcr->rmin = pcr->prev->rmin;
2038 	range_delete(pcrl, pcr->prev);
2039     }
2040     while (rmax >= pcr->next->rmin) {
2041 	/* Merge the range above pcr into this one. */
2042 	if (!pcr->next->next)
2043 	    break;		/* don't merge into the max range */
2044 	pcr->rmax = pcr->next->rmax;
2045 	range_delete(pcrl, pcr->next);
2046     }
2047     /*
2048      * Now we know that the union of (rmin,rmax) and (pcr->rmin,pcr->rmax)
2049      * doesn't overlap or abut either adjacent range, except that it may
2050      * abut if the adjacent range is the special min or max range.
2051      */
2052     if (rmin < pcr->rmin) {
2053 	if_debug3('Q', "[Qr]update 0x%lx => [%d,%d)\n", (ulong)pcr, rmin,
2054 		  pcr->rmax);
2055 	pcr->rmin = rmin;
2056     }
2057     if (rmax > pcr->rmax) {
2058 	if_debug3('Q', "[Qr]update 0x%lx => [%d,%d)\n", (ulong)pcr, pcr->rmin,
2059 		  rmax);
2060 	pcr->rmax = rmax;
2061     }
2062     pcrl->current = pcr->next;
2063     return 0;
2064  ins:
2065     /* Insert a new range below pcr. */
2066     {
2067 	coord_range_t *prev = range_alloc(pcrl);
2068 
2069 	if (prev == 0)
2070 	    return_error(gs_error_VMerror);
2071 	if_debug3('Q', "[Qr]insert 0x%lx: [%d,%d)\n", (ulong)prev, rmin, rmax);
2072 	prev->rmin = rmin, prev->rmax = rmax;
2073 	(prev->prev = pcr->prev)->next = prev;
2074 	prev->next = pcr;
2075 	pcr->prev = prev;
2076     }
2077     pcrl->current = pcr;
2078     return 0;
2079 }
2080 
2081 /*
2082  * Merge regions for active segments starting at a given Y, or all active
2083  * segments, up to the end of the sampling band or the end of the segment,
2084  * into the range list.
2085  */
2086 private int
merge_ranges(coord_range_list_t * pcrl,const line_list * ll,fixed y_min,fixed y_top)2087 merge_ranges(coord_range_list_t *pcrl, const line_list *ll, fixed y_min, fixed y_top)
2088 {
2089     active_line *alp, *nlp;
2090     int code = 0;
2091 
2092     range_list_rescan(pcrl);
2093     for (alp = ll->x_list; alp != 0 && code >= 0; alp = nlp) {
2094 	fixed x0 = alp->x_current, x1, xt;
2095 
2096 	nlp = alp->next;
2097 	if (alp->start.y < y_min)
2098 	    continue;
2099 	if (alp->monotonic_x && alp->monotonic_y && alp->fi.y3 <= y_top) {
2100     	    vd_bar(alp->start.x, alp->start.y, alp->end.x, alp->end.y, 0, RGB(255, 0, 0));
2101 	    x1 = alp->fi.x3;
2102 	    if (x0 > x1)
2103 		xt = x0, x0 = x1, x1 = xt;
2104 	    code = range_list_add(pcrl,
2105 				  fixed2int_pixround(x0 - ll->fo->adjust_left),
2106 				  fixed2int_rounded(x1 + ll->fo->adjust_right));
2107 	    alp->more_flattened = false; /* Skip all the segments left. */
2108 	} else {
2109 	    x1 = x0;
2110 	    for (;;) {
2111 		if (alp->end.y <= y_top)
2112 		    xt = alp->end.x;
2113 		else
2114 		    xt = AL_X_AT_Y(alp, y_top);
2115 		x0 = min(x0, xt);
2116 		x1 = max(x1, xt);
2117 		if (!alp->more_flattened || alp->end.y > y_top)
2118 		    break;
2119 		step_al(alp, true);
2120 		if (alp->end.y < alp->start.y) {
2121 		    remove_al(ll, alp); /* End of a monotonic part of a curve. */
2122 		    break;
2123 		}
2124 	    }
2125 	    code = range_list_add(pcrl,
2126 				  fixed2int_pixround(x0 - ll->fo->adjust_left),
2127 				  fixed2int_rounded(x1 + ll->fo->adjust_right));
2128 	}
2129 
2130     }
2131     return code;
2132 }
2133 
2134 /* ---------------- Scan line filling loop ---------------- */
2135 
2136 /* defina specializations of the scanline algorithm. */
2137 
2138 #define FILL_DIRECT 1
2139 #define TEMPLATE_spot_into_scanlines spot_into_scan_lines_fd
2140 #include "gxfillsl.h"
2141 #undef FILL_DIRECT
2142 #undef TEMPLATE_spot_into_scanlines
2143 
2144 #define FILL_DIRECT 0
2145 #define TEMPLATE_spot_into_scanlines spot_into_scan_lines_nd
2146 #include "gxfillsl.h"
2147 #undef FILL_DIRECT
2148 #undef TEMPLATE_spot_into_scanlines
2149 
2150 private int
spot_into_scan_lines(line_list * ll,fixed band_mask)2151 spot_into_scan_lines(line_list *ll, fixed band_mask)
2152 {
2153     if (ll->fo->fill_direct)
2154 	return spot_into_scan_lines_fd(ll, band_mask);
2155     else
2156 	return spot_into_scan_lines_nd(ll, band_mask);
2157 }
2158 
2159