///|
/// Source-over blend into a pixel at `offset` in a RGBA8 non-premultiplied
/// buffer.
///
/// `coverage` is an integer `0..=256` (256 == fully covered).
/// `global_alpha` multiplies the source alpha further (`0.0..=1.0`).
/// Fast paths:
/// - `coverage == 0` → early return (source is invisible).
/// - `src.a * coverage/256 * global_alpha <= 0` → early return.
pub fn blend_over(
  pixels : FixedArray[Byte],
  offset : Int,
  src : Color,
  coverage : Int,
  global_alpha : Double,
) -> Unit {
  if coverage == 0 {
    return
  }
  // Fast path: fully opaque source, full coverage, no alpha scaling
  if src.a >= 1.0 && coverage >= 256 && global_alpha >= 1.0 {
    pixels[offset] = src.r.to_byte()
    pixels[offset + 1] = src.g.to_byte()
    pixels[offset + 2] = src.b.to_byte()
    pixels[offset + 3] = b'\xFF'
    return
  }
  let src_a = src.a * (coverage.to_double() / 256.0) * global_alpha
  if src_a <= 0.0 {
    return
  }
  let dr = pixels[offset].to_int()
  let dg = pixels[offset + 1].to_int()
  let db = pixels[offset + 2].to_int()
  let da = pixels[offset + 3].to_int().to_double() / 255.0
  let sr = src.r.to_double()
  let sg = src.g.to_double()
  let sb = src.b.to_double()
  let one_minus_src_a = 1.0 - src_a
  let out_a = src_a + da * one_minus_src_a
  if out_a <= 0.0 {
    pixels[offset] = b'\x00'
    pixels[offset + 1] = b'\x00'
    pixels[offset + 2] = b'\x00'
    pixels[offset + 3] = b'\x00'
    return
  }
  let out_r = (sr * src_a + dr.to_double() * da * one_minus_src_a) / out_a
  let out_g = (sg * src_a + dg.to_double() * da * one_minus_src_a) / out_a
  let out_b = (sb * src_a + db.to_double() * da * one_minus_src_a) / out_a
  pixels[offset] = clamp_u8(out_r)
  pixels[offset + 1] = clamp_u8(out_g)
  pixels[offset + 2] = clamp_u8(out_b)
  pixels[offset + 3] = clamp_u8(out_a * 255.0)
}

///|
fn clamp_u8(v : Double) -> Byte {
  if v <= 0.0 {
    b'\x00'
  } else if v >= 255.0 {
    b'\xFF'
  } else {
    (v + 0.5).to_int().to_byte()
  }
}