+ /*
+ |..| |...........| | |
+ |..| |...........| | |
+ |..+ + +..| +--+ +--+
+ |...........| |..| | |
+ |...........| |..| | |
+ */
+
+#ifdef DEBUG
+ fprintf(stderr, "========================================================================\n");
+#endif
+ hqueue_t hqueue;
+ hqueue_init(&hqueue);
+ gfxpoly_enqueue(poly, 0, &hqueue, 0);
+
+ actlist_t* actlist = actlist_new();
+
+ event_t*e = hqueue_get(&hqueue);
+ while(e) {
+ int32_t y = e->p.y;
+ int32_t x = 0;
+#ifdef DEBUG
+ fprintf(stderr, "HORIZONTALS ----------------------------------- %d\n", y);
+ actlist_dump(actlist, y-1);
+#endif
+#ifdef CHECKS
+ actlist_verify(actlist, y-1);
+#endif
+ edgestyle_t*fill = 0;
+ int dir_up = 0;
+ int dir_down = 0;
+
+ do {
+ assert(e->s1->fs);
+ if(fill && x != e->p.x) {
+#ifdef DEBUG
+ fprintf(stderr, "%d) draw horizontal line from %d to %d\n", y, x, e->p.x);
+#endif
+ assert(x<e->p.x);
+ assert(dir_up || dir_down);
+
+ gfxpolystroke_t*stroke = rfx_calloc(sizeof(gfxpolystroke_t));
+ stroke->next = poly->strokes;
+ poly->strokes = stroke;
+
+ stroke->num_points = 2;
+ stroke->points = malloc(sizeof(point_t)*2);
+ if(dir_up < 0 || dir_down > 0) {
+ stroke->dir = DIR_UP;
+ } else {
+ stroke->dir = DIR_DOWN;
+ }
+
+ stroke->fs = fill;
+ point_t a,b;
+ a.y = b.y = y;
+ /* we draw from low x to high x so that left/right fillstyles add up
+ (because the horizontal line's fill style controls the area *below* the line)
+ */
+ a.x = e->p.x;
+ b.x = x;
+ stroke->points[0] = a;
+ stroke->points[1] = b;
+#ifdef CHECKS
+ /* the output should always be intersection free polygons, so check this horizontal
+ line isn't puncturing any segments in the active list */
+ segment_t* start = actlist_find(actlist, b, b);
+ segment_t* s = actlist_find(actlist, a, a);
+ while(s!=start) {
+ assert(s->a.y == y || s->b.y == y);
+ s = s->left;
+ }
+#endif
+ }
+
+ segment_t*s = e->s1;
+
+ segment_t*left = 0;
+ switch(e->type) {
+ case EVENT_START: {
+ assert(e->p.x == s->a.x && e->p.y == s->a.y);
+ actlist_insert(actlist, s->a, s->b, s);
+ event_t* e = event_new();
+ e->type = EVENT_END;
+ e->p = s->b;
+ e->s1 = s;
+ e->s2 = 0;
+ hqueue_put(&hqueue, e);
+ left = actlist_left(actlist, s);
+ dir_down += e->s1->dir==DIR_UP?1:-1;
+ break;
+ }
+ case EVENT_END: {
+ left = actlist_left(actlist, s);
+ actlist_delete(actlist, s);
+ advance_stroke(0, &hqueue, s->stroke, s->polygon_nr, s->stroke_pos);
+ dir_up += e->s1->dir==DIR_UP?1:-1;
+ break;
+ }
+ default: assert(0);
+ }
+
+ x = e->p.x;
+
+ fill = fill?0:&edgestyle_default;
+#if 0
+ if(windrule==&windrule_evenodd) {
+ if(!!fill != !!fill2) {
+ segment_dump(s);
+ event_dump(e);
+ printf("at y=%d x=%d (hline:%p)\n", e->p.y, x, old_fill);
+ if(e->type==EVENT_END) {
+ printf(" %9p\n", s->fs);
+ printf(" |\n");
+ }
+ printf(" %3d %c%2d \n", before1.is_filled, e->type==EVENT_END?'|':' ', after1.is_filled);
+ printf("%12p -----+----- %p\n", old_fill, fill2);
+ printf(" %3d %c%2d \n", before2.is_filled, e->type==EVENT_START?'|':' ', after2.is_filled);
+ if(e->type==EVENT_START) {
+ printf(" |\n");
+ printf(" %9p\n", s->fs);
+ }
+ }
+ assert(!!fill == !!fill2);
+ }
+#endif
+
+#ifdef DEBUG
+ fprintf(stderr, "%d) event=%s[%d] left:[%d] x:%d\n",
+ y, e->type==EVENT_START?"start":"end",
+ s->nr,
+ left?left->nr:-1,
+ x);
+#endif
+
+ if(e->type == EVENT_END)
+ segment_destroy(s);
+
+ event_free(e);
+ e = hqueue_get(&hqueue);
+ } while(e && y == e->p.y);
+
+#ifdef CHECKS
+ edgestyle_t*bleeding = fill;
+ assert(!bleeding);
+#endif
+ }
+
+ actlist_destroy(actlist);
+ hqueue_destroy(&hqueue);
+}
+
+gfxpoly_t* gfxpoly_process(gfxpoly_t*poly1, gfxpoly_t*poly2, windrule_t*windrule, windcontext_t*context)
+{
+ current_polygon = poly1;