glyphWindingAt function
Winding number of the horizontal ray x' > x at em-space point
(x, y), evaluated exactly the way the B3 shader will: pick the band
for y, walk its (max-x descending) curve list with the early-out, and
accumulate signed ray crossings from the quadratic roots of
Y(t) = y, t in [0, 1).
Implementation
int glyphWindingAt(
List<QuadCurve> curves, GlyphBands bands, double x, double y) {
if (bands.bandCount == 0) return 0;
if (y < bands.minY || y > bands.maxY) return 0;
var winding = 0;
for (final index in bands.bands[bands.bandFor(y)]) {
final c = curves[index];
if (c.maxX <= x) break; // sorted descending: nothing further can cross
if (y < c.minY || y >= c.maxY) continue;
// Y(t) - y = a t^2 + b t + cc
final a = c.y0 - 2 * c.cy + c.y1;
final b = 2 * (c.cy - c.y0);
final cc = c.y0 - y;
if (a.abs() < 1e-12) {
// (near-)linear in y
if (b.abs() < 1e-12) continue; // horizontal: no crossing
final t = -cc / b;
if (t >= 0 && t < 1) {
final xt = _quadX(c, t);
if (xt > x) winding += b > 0 ? 1 : -1;
}
continue;
}
final disc = b * b - 4 * a * cc;
if (disc < 0) continue;
final sq = math.sqrt(disc);
for (final t in [(-b - sq) / (2 * a), (-b + sq) / (2 * a)]) {
if (t < 0 || t >= 1) continue;
final xt = _quadX(c, t);
if (xt <= x) continue;
final dy = 2 * a * t + b;
if (dy > 0) {
winding += 1;
} else if (dy < 0) {
winding -= 1;
}
}
}
return winding;
}