+/* by restricting the recalculation of line segments to a range between the lowest
+ and the highest modified segment, we only do about a 33% overprocessing of fill
+ styles. (update: that statistic might be outdated now that xmin/xmax are double) */
+typedef struct _segrange {
+ double xmin;
+ segment_t*segmin;
+ double xmax;
+ segment_t*segmax;
+} segrange_t;
+
+static inline char xpos_eq(segment_t*s1, segment_t*s2, int y)
+{
+ if(XPOS_EQ(s1, s2, y)) {
+ return 1;
+ }
+ return 0;
+}
+
+void segrange_adjust_endpoints(segrange_t*range, int y)
+{
+#ifdef CHECK
+ /* this would mean that the segment left/right of the minimum/maximum
+ intersects the current segment exactly at the scanline, but somehow
+ wasn't found to be passing through the same snapping box */
+ assert(!min || !min->left || !XPOS_EQ(min, min->left, y));
+ assert(!max || !max->right || !XPOS_EQ(max, max->right, y));
+#endif
+
+ segment_t*min = range->segmin;
+ segment_t*max = range->segmax;
+ 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;
+}
+void segrange_test_segment_min(segrange_t*range, segment_t*seg, int 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.
+ TODO: might be faster to use XPOS_COMPARE here (see also _max)
+ */
+ double x = XPOS(seg, y);
+ if(!range->segmin || x<range->xmin) {
+ range->segmin = seg;
+ range->xmin = x;
+ }
+}
+void segrange_test_segment_max(segrange_t*range, segment_t*seg, int y)
+{
+ if(!seg) return;
+ double x = XPOS(seg, y);
+ if(!range->segmax || x>range->xmax) {
+ range->segmax = seg;
+ range->xmax = x;
+ }
+}
+