+
+static void insert_point_into_segment(status_t*status, segment_t*s, point_t p)
+{
+ assert(s->pos.x != p.x || s->pos.y != p.y);
+
+#ifdef CHECKS
+ if(!dict_contains(status->segs_with_point, s))
+ dict_put(status->segs_with_point, s, 0);
+ assert(s->fs_out_ok);
+#endif
+
+ if(s->fs_out) {
+#ifdef DEBUG
+ fprintf(stderr, "[%d] receives next point (%d,%d)->(%d,%d) (drawing)\n", s->nr,
+ s->pos.x, s->pos.y, p.x, p.y);
+#endif
+ /* XXX we probably will never output circular/anticircular polygons, but if
+ we do, we would need to set the segment direction here */
+ fillstyle_t*fs = s->fs_out;
+
+ // omit horizontal lines
+ if(s->pos.y != p.y) {
+ point_t a = s->pos;
+ point_t b = p;
+ assert(a.y != b.y);
+
+ gfxpolystroke_t*stroke = status->strokes;
+ while(stroke) {
+ point_t p = stroke->points[stroke->num_points-1];
+ if(p.x == a.x && p.y == a.y && stroke->fs == fs)
+ break;
+ stroke = stroke->next;
+ }
+ if(!stroke) {
+ stroke = rfx_calloc(sizeof(gfxpolystroke_t));
+ stroke->dir = DIR_DOWN;
+ stroke->fs = fs;
+ stroke->next = status->strokes;
+ status->strokes = stroke;
+ stroke->points_size = 2;
+ stroke->points = rfx_calloc(sizeof(point_t)*stroke->points_size);
+ stroke->points[0] = a;
+ stroke->num_points = 1;
+ } else if(stroke->num_points == stroke->points_size) {
+ stroke->points_size *= 2;
+ stroke->points = rfx_realloc(stroke->points, sizeof(point_t)*stroke->points_size);
+ }
+ stroke->points[stroke->num_points++] = b;
+ }
+ } else {
+#ifdef DEBUG
+ fprintf(stderr, "[%d] receives next point (%d,%d) (omitting)\n", s->nr, p.x, p.y);
+#endif
+ }
+ s->pos = p;
+}
+
+typedef struct _segrange {
+ double xmin;
+ segment_t*segmin;
+ double xmax;
+ segment_t*segmax;
+} segrange_t;
+
+static void segrange_adjust_endpoints(segrange_t*range, int32_t y)
+{
+#define XPOS_EQ(s1,s2,ypos) (XPOS((s1),(ypos))==XPOS((s2),(ypos)))
+ segment_t*min = range->segmin;
+ segment_t*max = range->segmax;
+
+ /* we need this because if two segments intersect exactly on
+ the scanline, segrange_test_segment_{min,max} can't tell which
+ one is smaller/larger */
+ if(min) while(min->left && XPOS_EQ(min, min->left, y)) {
+ min = min->left;
+ }
+ if(max) while(max->right && XPOS_EQ(max, max->right, y)) {
+ max = max->right;
+ }
+ range->segmin = min;
+ range->segmax = max;
+}
+static void segrange_test_segment_min(segrange_t*range, segment_t*seg, int32_t y)
+{
+ if(!seg) return;
+ /* we need to calculate the xpos anew (and can't use start coordinate or
+ intersection coordinate), because we need the xpos exactly at the end of
+ this scanline.
+ */
+ double x = XPOS(seg, y);
+ if(!range->segmin || x<range->xmin) {
+ range->segmin = seg;
+ range->xmin = x;
+ }
+}
+static void segrange_test_segment_max(segrange_t*range, segment_t*seg, int32_t y)
+{
+ if(!seg) return;
+ double x = XPOS(seg, y);
+ if(!range->segmax || x>range->xmax) {
+ range->segmax = seg;
+ range->xmax = x;
+ }
+}
+