Expand description
The coalescing span iterator for a scanner row. Coalescing span iterator over a scanner’s intersection row.
crate::ScanIterator mirrors SplashXPathScanIterator::getNextSpan from
splash/SplashXPathScanner.cc. It merges adjacent and overlapping
intersections into contiguous (x0, x1) spans (inclusive) and handles
both even-odd and non-zero winding fill rules via the eo_mask.
§Winding-rule semantics
The iterator maintains a running count — the sum of all
Intersect::count values consumed so far. Whether the current pixel
position is inside the path depends on the fill rule:
- Non-zero winding (
eo = false): inside whencount != 0.eo_mask = !0socount & eo_maskis non-zero iffcount != 0. - Even-odd (
eo = true): inside when the crossing count is odd.eo_mask = 1socount & eo_maskisolates the low bit (parity).
§Algorithm (next)
§Phase 1 — find the span start
Before consuming each entry, check count & eo_mask:
- Already non-zero → we are inside from a previous span’s count residue;
the current entry (
row[idx]) is the span start. Record itsx0and go to phase 2 without consuming it yet (phase 2 will consume it). - Zero → consume the entry (add its
count, advanceidx). If now non-zero → this entry is the span start; record itsx0(fromrow[idx - 1]) and go to phase 2 (the entry is already consumed). - Still zero → continue to the next entry.
§Phase 2 — collect the span
Starting from row[phase2_start_idx] (inclusive), consume entries, tracking
the maximum x1 seen, until count & eo_mask == 0. Emit (x0, x1).
Each Intersect entry’s count is accumulated exactly once across the
two phases. After next returns, count equals the winding number
immediately after the rightmost covered pixel x1.
Structs§
- Scan
Iterator - An iterator that yields
(x0, x1)inclusive pixel spans for one scanline.