glyphWindingAt function

int glyphWindingAt(
  1. List<QuadCurve> curves,
  2. GlyphBands bands,
  3. double x,
  4. double y,
)

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;
}