// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
/// gvar support for glyf outlines.
///
/// Ported from `fontations/skrifa/src/outline/glyf/deltas.rs` and related
/// gvar parsing logic (Apache-2.0 OR MIT).
const TAG_GVAR : UInt = 0x67766172 // "gvar"

///|
fn gvar_read_u8(view : BytesView, offset : Int) -> Int? {
  if offset < 0 || offset >= view.length() {
    None
  } else {
    Some(view.at(offset).to_int())
  }
}

///|
fn gvar_read_u16_be(view : BytesView, offset : Int) -> Int? {
  if offset < 0 || offset + 2 > view.length() {
    None
  } else {
    let b0 = view.at(offset).to_int()
    let b1 = view.at(offset + 1).to_int()
    Some((b0 << 8) | b1)
  }
}

///|
fn gvar_read_i16_be(view : BytesView, offset : Int) -> Int? {
  match gvar_read_u16_be(view, offset) {
    None => None
    Some(u) => if u >= 0x8000 { Some(u - 0x10000) } else { Some(u) }
  }
}

///|
fn gvar_read_u32_be_int(view : BytesView, offset : Int) -> Int? {
  if offset < 0 || offset + 4 > view.length() {
    None
  } else {
    let b0 = view.at(offset).to_int()
    let b1 = view.at(offset + 1).to_int()
    let b2 = view.at(offset + 2).to_int()
    let b3 = view.at(offset + 3).to_int()
    Some((b0 << 24) | (b1 << 16) | (b2 << 8) | b3)
  }
}

///|
priv struct GvarCtx {
  gvar : BytesView
  axis_count : Int
  shared_tuple_count : Int
  shared_tuples_off : Int
  glyph_count : Int
  flags : Int
  data_array_off : Int
}

///|
fn gvar_ctx(font : @moon_skrifa.FontRef) -> GvarCtx? {
  let gvar = match font.table(TAG_GVAR) {
    None => return None
    Some(v) => v
  }
  // gvar header is 20 bytes.
  if gvar.length() < 20 {
    return None
  }
  let axis_count = gvar_read_u16_be(gvar, 4).unwrap_or(-1)
  let shared_tuple_count = gvar_read_u16_be(gvar, 6).unwrap_or(-1)
  let shared_tuples_off = gvar_read_u32_be_int(gvar, 8).unwrap_or(-1)
  let glyph_count = gvar_read_u16_be(gvar, 12).unwrap_or(-1)
  let flags = gvar_read_u16_be(gvar, 14).unwrap_or(-1)
  let data_array_off = gvar_read_u32_be_int(gvar, 16).unwrap_or(-1)
  if axis_count <= 0 || shared_tuple_count < 0 || glyph_count < 0 {
    return None
  }
  if shared_tuples_off < 0 || data_array_off < 0 {
    return None
  }
  if shared_tuples_off > gvar.length() || data_array_off > gvar.length() {
    return None
  }
  Some({
    gvar,
    axis_count,
    shared_tuple_count,
    shared_tuples_off,
    glyph_count,
    flags,
    data_array_off,
  })
}

///|
fn gvar_tuple_scalar(
  coords : ArrayView[@moon_skrifa.NormalizedCoord],
  peak : Array[Int],
  start : Array[Int]?,
  end : Array[Int]?,
) -> Double {
  let axis_count = peak.length()
  let mut scalar = 1.0
  for i in 0.. {
        let start_v = s.at(i)
        let end_v = e.at(i)
        if coord <= start_v || coord >= end_v {
          return 0.0
        }
        if coord < peak_v {
          if peak_v != start_v {
            scalar = scalar *
              (coord - start_v).to_double() /
              (peak_v - start_v).to_double()
          }
        } else if peak_v != end_v {
          scalar = scalar *
            (end_v - coord).to_double() /
            (end_v - peak_v).to_double()
        }
      }
      _ => {
        let min_v = if peak_v < 0 { peak_v } else { 0 }
        let max_v = if peak_v > 0 { peak_v } else { 0 }
        if coord < min_v || coord > max_v {
          return 0.0
        }
        scalar = scalar * coord.to_double() / peak_v.to_double()
      }
    }
  }
  scalar
}

///|
fn gvar_f2dot14_to_fixed16_16(bits : Int) -> Int {
  // F2Dot14 has 14 fractional bits; 16.16 has 16.
  bits << 2
}

///|
fn gvar_tuple_scalar_fixed16_16(
  coords : ArrayView[@moon_skrifa.NormalizedCoord],
  peak : Array[Int],
  start : Array[Int]?,
  end : Array[Int]?,
) -> Int {
  let axis_count = peak.length()
  let mut scalar = 0x10000
  for i in 0.. {
        let start_v = s.at(i)
        let end_v = e.at(i)
        if coord <= start_v || coord >= end_v {
          return 0
        }
        let coord_f = gvar_f2dot14_to_fixed16_16(coord)
        let peak_f = gvar_f2dot14_to_fixed16_16(peak_v)
        if coord_f < peak_f {
          let start_f = gvar_f2dot14_to_fixed16_16(start_v)
          scalar = tt_hint_mul_div_16_16(
            scalar,
            coord_f - start_f,
            peak_f - start_f,
          )
        } else {
          let end_f = gvar_f2dot14_to_fixed16_16(end_v)
          scalar = tt_hint_mul_div_16_16(
            scalar,
            end_f - coord_f,
            end_f - peak_f,
          )
        }
      }
      _ => {
        let min_v = if peak_v < 0 { peak_v } else { 0 }
        let max_v = if peak_v > 0 { peak_v } else { 0 }
        if coord < min_v || coord > max_v {
          return 0
        }
        scalar = tt_hint_mul_div_16_16(
          scalar,
          gvar_f2dot14_to_fixed16_16(coord),
          gvar_f2dot14_to_fixed16_16(peak_v),
        )
      }
    }
  }
  scalar
}

///|
/// Decodes a point number run list.
fn gvar_points(
  gvar : BytesView,
  offset : Int,
  total_points : Int,
) -> (Array[Int]?, Int)? {
  let b0 = gvar_read_u8(gvar, offset).unwrap_or(-1)
  if b0 < 0 {
    return None
  }
  let mut count = 0
  let mut off = offset
  if (b0 & 0x80) == 0 {
    count = b0
    off = off + 1
  } else {
    let b1 = gvar_read_u8(gvar, offset + 1).unwrap_or(-1)
    if b1 < 0 {
      return None
    }
    count = ((b0 & 0x7F) << 8) | b1
    off = off + 2
  }
  if count == 0 {
    return Some((None, off))
  }
  let points : Array[Int] = Array::new()
  let mut last = 0
  while points.length() < count {
    let ctrl = gvar_read_u8(gvar, off).unwrap_or(-1)
    if ctrl < 0 {
      return None
    }
    off = off + 1
    let run_len = (ctrl & 0x7F) + 1
    let words = (ctrl & 0x80) != 0
    for _ in 0..= count {
        break
      }
      let delta = if words {
        gvar_read_u16_be(gvar, off).unwrap_or(-1)
      } else {
        gvar_read_u8(gvar, off).unwrap_or(-1)
      }
      if delta < 0 {
        return None
      }
      off = off + (if words { 2 } else { 1 })
      last = last + delta
      if last < 0 || last >= total_points {
        return None
      }
      points.push(last)
    }
  }
  Some((Some(points), off))
}

///|
/// Decodes a delta run list.
fn gvar_deltas(
  gvar : BytesView,
  offset : Int,
  count : Int,
) -> (Array[Int], Int)? {
  let mut off = offset
  let mut idx = 0
  let out : Array[Int] = Array::new()
  while idx < count {
    let ctrl = gvar_read_u8(gvar, off).unwrap_or(-1)
    if ctrl < 0 {
      return None
    }
    off = off + 1
    let run_len = (ctrl & 0x3F) + 1
    if idx + run_len > count {
      return None
    }
    // Match read-fonts' PackedDeltas:
    // - bit 7 (0x80): deltas are zero (no payload bytes)
    // - bit 6 (0x40): deltas are i16 (payload is big-endian i16)
    // - both bits set: deltas are i32 (payload is big-endian i32, used by VARC)
    // - neither set: deltas are i8 (payload is signed byte)
    let zeros = (ctrl & 0x80) != 0
    let words = (ctrl & 0x40) != 0
    if zeros && !words {
      for _ in 0..= 128 { b - 256 } else { b }
        out.push(v)
        idx = idx + 1
      }
    } else {
      // i32 values (rare; primarily for VARC). Keep as Int.
      for _ in 0.. Bool {
  if ref_ix < range_start || ref_ix > range_end {
    return false
  }
  let dx = out_x.at(ref_ix) - orig_x.at(ref_ix)
  let dy = out_y.at(ref_ix) - orig_y.at(ref_ix)
  if dx == 0.0 && dy == 0.0 {
    return true
  }
  for i in range_start.. Bool {
  if range_start > range_end {
    return true
  }
  let mut ref1_ix = ref1_ix_in
  let mut ref2_ix = ref2_ix_in
  if orig.at(ref1_ix) > orig.at(ref2_ix) {
    let tmp = ref1_ix
    ref1_ix = ref2_ix
    ref2_ix = tmp
  }
  let in1 = orig.at(ref1_ix)
  let in2 = orig.at(ref2_ix)
  let out1 = out.at(ref1_ix)
  let out2 = out.at(ref2_ix)
  // If the reference points have the same coordinate but different delta,
  // inferred delta is zero. Otherwise interpolate.
  if in1 != in2 || out1 == out2 {
    let scale = if in1 != in2 { (out2 - out1) / (in2 - in1) } else { 0.0 }
    let d1 = out1 - in1
    let d2 = out2 - in2
    for i in range_start..<(range_end + 1) {
      let mut v = orig.at(i)
      if v <= in1 {
        v = v + d1
      } else if v >= in2 {
        v = v + d2
      } else {
        v = out1 + (v - in1) * scale
      }
      out.set(i, v)
    }
  }
  true
}

///|
fn gvar_interpolate_deltas(
  orig_x : Array[Double],
  orig_y : Array[Double],
  out_x : Array[Double],
  out_y : Array[Double],
  has_delta : Array[Bool],
  contours : Array[Int],
  point_count : Int,
) -> Bool {
  let mut point_ix = 0
  for end_point_ix in contours.iter() {
    let end_ix = end_point_ix
    let first_ix = point_ix
    // Search for first point that has a delta.
    while point_ix <= end_ix &&
          point_ix < point_count &&
          !has_delta.at(point_ix) {
      point_ix = point_ix + 1
    }
    if point_ix > end_ix {
      // No deltas for this contour.
      continue
    }
    let first_delta_ix = point_ix
    let mut cur_delta_ix = point_ix
    point_ix = point_ix + 1
    // Search for next point that has a delta...
    while point_ix <= end_ix && point_ix < point_count {
      if has_delta.at(point_ix) {
        // ... and interpolate intermediate points.
        if !gvar_interp_coord(
            orig_x,
            out_x,
            cur_delta_ix + 1,
            point_ix - 1,
            cur_delta_ix,
            point_ix,
          ) {
          return false
        }
        if !gvar_interp_coord(
            orig_y,
            out_y,
            cur_delta_ix + 1,
            point_ix - 1,
            cur_delta_ix,
            point_ix,
          ) {
          return false
        }
        cur_delta_ix = point_ix
      }
      point_ix = point_ix + 1
    }
    // If we only have a single delta, shift the contour.
    if cur_delta_ix == first_delta_ix {
      if !gvar_shift_contour(
          orig_x, orig_y, out_x, out_y, first_ix, end_ix, cur_delta_ix,
        ) {
        return false
      }
    } else {
      // Otherwise, handle remaining points at beginning and end of contour.
      if !gvar_interp_coord(
          orig_x,
          out_x,
          cur_delta_ix + 1,
          end_ix,
          cur_delta_ix,
          first_delta_ix,
        ) {
        return false
      }
      if !gvar_interp_coord(
          orig_y,
          out_y,
          cur_delta_ix + 1,
          end_ix,
          cur_delta_ix,
          first_delta_ix,
        ) {
        return false
      }
      if first_delta_ix > first_ix {
        if !gvar_interp_coord(
            orig_x,
            out_x,
            first_ix,
            first_delta_ix - 1,
            cur_delta_ix,
            first_delta_ix,
          ) {
          return false
        }
        if !gvar_interp_coord(
            orig_y,
            out_y,
            first_ix,
            first_delta_ix - 1,
            cur_delta_ix,
            first_delta_ix,
          ) {
          return false
        }
      }
    }
  }
  true
}

///|
fn gvar_shift_contour_fixed(
  orig_x : Array[Int],
  orig_y : Array[Int],
  out_x : Array[Int],
  out_y : Array[Int],
  range_start : Int,
  range_end : Int,
  ref_ix : Int,
) -> Bool {
  if ref_ix < range_start || ref_ix > range_end {
    return false
  }
  let dx = out_x.at(ref_ix) - orig_x.at(ref_ix)
  let dy = out_y.at(ref_ix) - orig_y.at(ref_ix)
  if dx == 0 && dy == 0 {
    return true
  }
  for i in range_start.. Bool {
  if range_start > range_end {
    return true
  }
  let mut ref1_ix = ref1_ix_in
  let mut ref2_ix = ref2_ix_in
  if orig.at(ref1_ix) > orig.at(ref2_ix) {
    let tmp = ref1_ix
    ref1_ix = ref2_ix
    ref2_ix = tmp
  }
  let in1 = orig.at(ref1_ix)
  let in2 = orig.at(ref2_ix)
  let out1 = out.at(ref1_ix)
  let out2 = out.at(ref2_ix)
  // If the reference points have the same coordinate but different delta,
  // inferred delta is zero. Otherwise interpolate.
  if in1 != in2 || out1 == out2 {
    let scale = if in1 != in2 {
      tt_hint_div_16_16(out2 - out1, in2 - in1)
    } else {
      0
    }
    let d1 = out1 - in1
    let d2 = out2 - in2
    for i in range_start..<(range_end + 1) {
      let v0 = orig.at(i)
      let v = if v0 <= in1 {
        v0 + d1
      } else if v0 >= in2 {
        v0 + d2
      } else {
        out1 + tt_hint_mul_16_16(v0 - in1, scale)
      }
      out.set(i, v)
    }
  }
  true
}

///|
fn gvar_interpolate_deltas_fixed(
  orig_x : Array[Int],
  orig_y : Array[Int],
  out_x : Array[Int],
  out_y : Array[Int],
  has_delta : Array[Bool],
  contours : Array[Int],
  point_count : Int,
) -> Bool {
  let mut point_ix = 0
  for end_point_ix in contours.iter() {
    let end_ix = end_point_ix
    let first_ix = point_ix
    // Search for first point that has a delta.
    while point_ix <= end_ix &&
          point_ix < point_count &&
          !has_delta.at(point_ix) {
      point_ix = point_ix + 1
    }
    if point_ix > end_ix {
      // No deltas for this contour.
      continue
    }
    let first_delta_ix = point_ix
    let mut cur_delta_ix = point_ix
    point_ix = point_ix + 1
    // Search for next point that has a delta...
    while point_ix <= end_ix && point_ix < point_count {
      if has_delta.at(point_ix) {
        // ... and interpolate intermediate points.
        if !gvar_interp_coord_fixed(
            orig_x,
            out_x,
            cur_delta_ix + 1,
            point_ix - 1,
            cur_delta_ix,
            point_ix,
          ) {
          return false
        }
        if !gvar_interp_coord_fixed(
            orig_y,
            out_y,
            cur_delta_ix + 1,
            point_ix - 1,
            cur_delta_ix,
            point_ix,
          ) {
          return false
        }
        cur_delta_ix = point_ix
      }
      point_ix = point_ix + 1
    }
    // If we only have a single delta, shift the contour.
    if cur_delta_ix == first_delta_ix {
      if !gvar_shift_contour_fixed(
          orig_x, orig_y, out_x, out_y, first_ix, end_ix, cur_delta_ix,
        ) {
        return false
      }
    } else {
      // Otherwise, handle remaining points at beginning and end of contour.
      if !gvar_interp_coord_fixed(
          orig_x,
          out_x,
          cur_delta_ix + 1,
          end_ix,
          cur_delta_ix,
          first_delta_ix,
        ) {
        return false
      }
      if !gvar_interp_coord_fixed(
          orig_y,
          out_y,
          cur_delta_ix + 1,
          end_ix,
          cur_delta_ix,
          first_delta_ix,
        ) {
        return false
      }
      if first_delta_ix > first_ix {
        if !gvar_interp_coord_fixed(
            orig_x,
            out_x,
            first_ix,
            first_delta_ix - 1,
            cur_delta_ix,
            first_delta_ix,
          ) {
          return false
        }
        if !gvar_interp_coord_fixed(
            orig_y,
            out_y,
            first_ix,
            first_delta_ix - 1,
            cur_delta_ix,
            first_delta_ix,
          ) {
          return false
        }
      }
    }
  }
  true
}

///|
/// Applies gvar deltas (if present) to the given simple glyf point list in
/// font units.
fn glyf_apply_gvar_simple(
  font : @moon_skrifa.FontRef,
  gid : @moon_skrifa.GlyphId,
  coords : ArrayView[@moon_skrifa.NormalizedCoord],
  end_pts : Array[Int],
  xs : Array[Double],
  ys : Array[Double],
) -> Unit {
  if coords.is_empty() {
    return
  }
  let ctx = match gvar_ctx(font) {
    None => return
    Some(c) => c
  }
  let gid_i = gid.to_uint64().to_int()
  if gid_i < 0 || gid_i >= ctx.glyph_count {
    return
  }
  let point_count = xs.length()
  if ys.length() != point_count {
    return
  }
  let total_points = point_count + 4
  if total_points <= 0 {
    return
  }
  // Offsets array starts at 20.
  let offsets_off = 20
  let long_offsets = (ctx.flags & 1) != 0
  let entry_size = if long_offsets { 4 } else { 2 }
  let need = offsets_off + (ctx.glyph_count + 1) * entry_size
  if need < 0 || need > ctx.gvar.length() {
    return
  }
  let off0 = if long_offsets {
    gvar_read_u32_be_int(ctx.gvar, offsets_off + gid_i * 4).unwrap_or(-1)
  } else {
    gvar_read_u16_be(ctx.gvar, offsets_off + gid_i * 2).unwrap_or(-1) * 2
  }
  let off1 = if long_offsets {
    gvar_read_u32_be_int(ctx.gvar, offsets_off + (gid_i + 1) * 4).unwrap_or(-1)
  } else {
    gvar_read_u16_be(ctx.gvar, offsets_off + (gid_i + 1) * 2).unwrap_or(-1) * 2
  }
  if off0 < 0 || off1 < off0 {
    return
  }
  let start = ctx.data_array_off + off0
  let end = ctx.data_array_off + off1
  if start < 0 || end < start || end > ctx.gvar.length() {
    return
  }
  if start == end {
    return
  }
  let tuple_count_flags = gvar_read_u16_be(ctx.gvar, start).unwrap_or(0)
  let tuple_count = tuple_count_flags & 0x0FFF
  let shared_points = (tuple_count_flags & 0x8000) != 0
  let data_rel = gvar_read_u16_be(ctx.gvar, start + 2).unwrap_or(-1)
  if tuple_count <= 0 || data_rel < 0 {
    return
  }
  let sizes : Array[Int] = Array::new()
  let tuple_indexes : Array[Int] = Array::new()
  let axis_count = ctx.axis_count
  let scalars : Array[Double] = Array::new()

  // TupleVariationHeader is variable-length: the fixed fields are followed
  // by optional embedded peak and intermediate tuples.
  let mut header_off = start + 4
  for _ in 0.. end {
        return
      }
      for ax in 0..= ctx.shared_tuple_count {
        return
      }
      let base = ctx.shared_tuples_off + shared_ix * axis_count * 2
      let need = base + axis_count * 2
      if base < 0 || need < base || need > ctx.gvar.length() {
        return
      }
      for ax in 0.. end {
        return
      }
      for ax in 0.. end {
    return
  }
  // Accumulate deltas across tuples.
  let accum_x : Array[Double] = Array::make(point_count, 0.0)
  let accum_y : Array[Double] = Array::make(point_count, 0.0)
  let mut cursor = data_off
  let mut shared_points_list : Array[Int]? = None
  if shared_points {
    let (pts, off2) = match gvar_points(ctx.gvar, cursor, total_points) {
      None => return
      Some(v) => v
    }
    shared_points_list = pts
    cursor = off2
  }
  for i in 0.. end {
      return
    }
    let scalar = scalars.at(i)
    if scalar == 0.0 {
      cursor = tuple_end
      continue
    }
    // PRIVATE_POINT_NUMBERS = 0x2000.
    let private_points = (ti & 0x2000) != 0
    let mut points_list : Array[Int]? = None
    let mut after_points = cursor
    if private_points || !shared_points {
      let (pts, off2) = match gvar_points(ctx.gvar, cursor, total_points) {
        None => return
        Some(v) => v
      }
      points_list = pts
      after_points = off2
    } else {
      points_list = shared_points_list
      after_points = cursor
    }
    let count = match points_list {
      None => total_points
      Some(arr) => arr.length()
    }
    let (dxs, after_x) = match gvar_deltas(ctx.gvar, after_points, count) {
      None => return
      Some(v) => v
    }
    let (dys, after_y) = match gvar_deltas(ctx.gvar, after_x, count) {
      None => return
      Some(v) => v
    }
    if after_y > tuple_end {
      return
    }
    // Prepare IUP working buffers for this tuple (only for real points).
    let orig_x : Array[Double] = Array::make(point_count, 0.0)
    let orig_y : Array[Double] = Array::make(point_count, 0.0)
    let out_x : Array[Double] = Array::make(point_count, 0.0)
    let out_y : Array[Double] = Array::make(point_count, 0.0)
    for p_ix in 0..
        // Dense: deltas are for all points (including phantoms). Apply first point_count.
        for p_ix in 0..
        for j in 0..= 0 && pt < point_count {
            out_x.set(pt, out_x.at(pt) + dxs.at(j).to_double() * scalar)
            out_y.set(pt, out_y.at(pt) + dys.at(j).to_double() * scalar)
            has_delta.set(pt, true)
          }
        }
    }
    if !gvar_interpolate_deltas(
        orig_x, orig_y, out_x, out_y, has_delta, end_pts, point_count,
      ) {
      return
    }
    for p_ix in 0.. (Array[Double], Array[Double])? {
  if coords.is_empty() {
    return None
  }
  if component_count <= 0 {
    return None
  }
  let ctx = match gvar_ctx(font) {
    None => return None
    Some(c) => c
  }
  let gid_i = gid.to_uint64().to_int()
  if gid_i < 0 || gid_i >= ctx.glyph_count {
    return None
  }
  let total_points = component_count + 4
  if total_points <= 0 {
    return None
  }
  // Offsets array starts at 20.
  let offsets_off = 20
  let long_offsets = (ctx.flags & 1) != 0
  let entry_size = if long_offsets { 4 } else { 2 }
  let need = offsets_off + (ctx.glyph_count + 1) * entry_size
  if need < 0 || need > ctx.gvar.length() {
    return None
  }
  let off0 = if long_offsets {
    gvar_read_u32_be_int(ctx.gvar, offsets_off + gid_i * 4).unwrap_or(-1)
  } else {
    gvar_read_u16_be(ctx.gvar, offsets_off + gid_i * 2).unwrap_or(-1) * 2
  }
  let off1 = if long_offsets {
    gvar_read_u32_be_int(ctx.gvar, offsets_off + (gid_i + 1) * 4).unwrap_or(-1)
  } else {
    gvar_read_u16_be(ctx.gvar, offsets_off + (gid_i + 1) * 2).unwrap_or(-1) * 2
  }
  if off0 < 0 || off1 < off0 {
    return None
  }
  let start = ctx.data_array_off + off0
  let end = ctx.data_array_off + off1
  if start < 0 || end < start || end > ctx.gvar.length() {
    return None
  }
  if start == end {
    return None
  }
  let tuple_count_flags = gvar_read_u16_be(ctx.gvar, start).unwrap_or(0)
  let tuple_count = tuple_count_flags & 0x0FFF
  let shared_points = (tuple_count_flags & 0x8000) != 0
  let data_rel = gvar_read_u16_be(ctx.gvar, start + 2).unwrap_or(-1)
  if tuple_count <= 0 || data_rel < 0 {
    return None
  }
  let sizes : Array[Int] = Array::new()
  let tuple_indexes : Array[Int] = Array::new()
  let axis_count = ctx.axis_count
  let scalars : Array[Double] = Array::new()
  let mut header_off = start + 4
  for _ in 0.. end {
        return None
      }
      for ax in 0..= ctx.shared_tuple_count {
        return None
      }
      let base = ctx.shared_tuples_off + shared_ix * axis_count * 2
      let need = base + axis_count * 2
      if base < 0 || need < base || need > ctx.gvar.length() {
        return None
      }
      for ax in 0.. end {
        return None
      }
      for ax in 0.. end {
    return None
  }
  let accum_x : Array[Double] = Array::make(component_count, 0.0)
  let accum_y : Array[Double] = Array::make(component_count, 0.0)
  let mut cursor = data_off
  let mut shared_points_list : Array[Int]? = None
  if shared_points {
    let (pts, off2) = match gvar_points(ctx.gvar, cursor, total_points) {
      None => return None
      Some(v) => v
    }
    shared_points_list = pts
    cursor = off2
  }
  for i in 0.. end {
      return None
    }
    let scalar = scalars.at(i)
    if scalar == 0.0 {
      cursor = tuple_end
      continue
    }
    // PRIVATE_POINT_NUMBERS = 0x2000.
    let private_points = (ti & 0x2000) != 0
    let mut points_list : Array[Int]? = None
    let mut after_points = cursor
    if private_points || !shared_points {
      let (pts, off2) = match gvar_points(ctx.gvar, cursor, total_points) {
        None => return None
        Some(v) => v
      }
      points_list = pts
      after_points = off2
    } else {
      points_list = shared_points_list
      after_points = cursor
    }
    let count = match points_list {
      None => total_points
      Some(arr) => arr.length()
    }
    let (dxs, after_x) = match gvar_deltas(ctx.gvar, after_points, count) {
      None => return None
      Some(v) => v
    }
    let (dys, after_y) = match gvar_deltas(ctx.gvar, after_x, count) {
      None => return None
      Some(v) => v
    }
    if after_y > tuple_end {
      return None
    }
    match points_list {
      None =>
        for pt in 0..
        for j in 0..= 0 && pt < component_count {
            accum_x.set(pt, accum_x.at(pt) + dxs.at(j).to_double() * scalar)
            accum_y.set(pt, accum_y.at(pt) + dys.at(j).to_double() * scalar)
          }
        }
    }
    cursor = tuple_end
  }
  Some((accum_x, accum_y))
}

///|
/// Rounds a 16.16 fixed value to i32, matching FreeType-style rounding.
fn gvar_fixed16_16_to_i32(bits : Int) -> Int {
  // Matches `font_types::Fixed::to_i32()` rounding.
  ((bits.to_int64() + (0x8000).to_int64()) >> 16).to_int()
}

///|
fn gvar_scale_funit_delta_to_fixed16_16(delta : Int, scalar_bits : Int) -> Int {
  let bits = delta << 16
  if scalar_bits == 0x10000 {
    bits
  } else {
    tt_hint_mul_16_16(bits, scalar_bits)
  }
}

///|
fn gvar_zero_deltas(total_points : Int) -> (Array[Int], Array[Int]) {
  (Array::make(total_points, 0), Array::make(total_points, 0))
}

///|
/// Computes gvar point deltas for a simple glyph suitable for embedded hinting.
///
/// Returns 16.16 fixed deltas for all points, including the four phantom
/// points, with IUP interpolation applied to missing real-point deltas.
fn glyf_gvar_simple_hint_deltas(
  font : @moon_skrifa.FontRef,
  gid : @moon_skrifa.GlyphId,
  coords : ArrayView[@moon_skrifa.NormalizedCoord],
  end_pts : Array[Int],
  xs : Array[Double],
  ys : Array[Double],
) -> (Array[Int], Array[Int])? {
  if coords.is_empty() {
    return None
  }
  let ctx = match gvar_ctx(font) {
    None => return None
    Some(c) => c
  }
  let gid_i = gid.to_uint64().to_int()
  if gid_i < 0 || gid_i >= ctx.glyph_count {
    return None
  }
  let point_count = xs.length()
  if ys.length() != point_count {
    return None
  }
  let total_points = point_count + 4
  if total_points <= 0 {
    return None
  }
  // Offsets array starts at 20.
  let offsets_off = 20
  let long_offsets = (ctx.flags & 1) != 0
  let entry_size = if long_offsets { 4 } else { 2 }
  let need = offsets_off + (ctx.glyph_count + 1) * entry_size
  if need < 0 || need > ctx.gvar.length() {
    return Some(gvar_zero_deltas(total_points))
  }
  let off0 = if long_offsets {
    gvar_read_u32_be_int(ctx.gvar, offsets_off + gid_i * 4).unwrap_or(-1)
  } else {
    gvar_read_u16_be(ctx.gvar, offsets_off + gid_i * 2).unwrap_or(-1) * 2
  }
  let off1 = if long_offsets {
    gvar_read_u32_be_int(ctx.gvar, offsets_off + (gid_i + 1) * 4).unwrap_or(-1)
  } else {
    gvar_read_u16_be(ctx.gvar, offsets_off + (gid_i + 1) * 2).unwrap_or(-1) * 2
  }
  if off0 < 0 || off1 < off0 {
    return Some(gvar_zero_deltas(total_points))
  }
  let start = ctx.data_array_off + off0
  let end = ctx.data_array_off + off1
  if start < 0 || end < start || end > ctx.gvar.length() {
    return Some(gvar_zero_deltas(total_points))
  }
  if start == end {
    return Some(gvar_zero_deltas(total_points))
  }
  let tuple_count_flags = gvar_read_u16_be(ctx.gvar, start).unwrap_or(0)
  let tuple_count = tuple_count_flags & 0x0FFF
  let shared_points = (tuple_count_flags & 0x8000) != 0
  let data_rel = gvar_read_u16_be(ctx.gvar, start + 2).unwrap_or(-1)
  if tuple_count <= 0 || data_rel < 0 {
    return Some(gvar_zero_deltas(total_points))
  }
  let sizes : Array[Int] = Array::new()
  let tuple_indexes : Array[Int] = Array::new()
  let axis_count = ctx.axis_count
  let scalars : Array[Int] = Array::new()
  let mut header_off = start + 4
  for _ in 0.. end {
        return Some(gvar_zero_deltas(total_points))
      }
      for ax in 0..= ctx.shared_tuple_count {
        return Some(gvar_zero_deltas(total_points))
      }
      let base = ctx.shared_tuples_off + shared_ix * axis_count * 2
      let need = base + axis_count * 2
      if base < 0 || need < base || need > ctx.gvar.length() {
        return Some(gvar_zero_deltas(total_points))
      }
      for ax in 0.. end {
        return Some(gvar_zero_deltas(total_points))
      }
      for ax in 0.. end {
    return Some(gvar_zero_deltas(total_points))
  }
  let accum_x : Array[Int] = Array::make(total_points, 0)
  let accum_y : Array[Int] = Array::make(total_points, 0)
  let mut cursor = data_off
  let mut shared_points_list : Array[Int]? = None
  if shared_points {
    let (pts, off2) = match gvar_points(ctx.gvar, cursor, total_points) {
      None => return Some(gvar_zero_deltas(total_points))
      Some(v) => v
    }
    shared_points_list = pts
    cursor = off2
  }
  for i in 0.. end {
      return Some(gvar_zero_deltas(total_points))
    }
    let scalar = scalars.at(i)
    if scalar == 0 {
      cursor = tuple_end
      continue
    }
    // PRIVATE_POINT_NUMBERS = 0x2000.
    let private_points = (ti & 0x2000) != 0
    let mut points_list : Array[Int]? = None
    let mut after_points = cursor
    if private_points || !shared_points {
      let (pts, off2) = match gvar_points(ctx.gvar, cursor, total_points) {
        None => return Some(gvar_zero_deltas(total_points))
        Some(v) => v
      }
      points_list = pts
      after_points = off2
    } else {
      points_list = shared_points_list
      after_points = cursor
    }
    let count = match points_list {
      None => total_points
      Some(arr) => arr.length()
    }
    let (dxs, after_x) = match gvar_deltas(ctx.gvar, after_points, count) {
      None => return Some(gvar_zero_deltas(total_points))
      Some(v) => v
    }
    let (dys, after_y) = match gvar_deltas(ctx.gvar, after_x, count) {
      None => return Some(gvar_zero_deltas(total_points))
      Some(v) => v
    }
    if after_y > tuple_end {
      return Some(gvar_zero_deltas(total_points))
    }
    // Prepare IUP buffers for real points for this tuple (16.16 coords).
    let orig_x : Array[Int] = Array::make(point_count, 0)
    let orig_y : Array[Int] = Array::make(point_count, 0)
    let out_x : Array[Int] = Array::make(point_count, 0)
    let out_y : Array[Int] = Array::make(point_count, 0)
    for p_ix in 0.. {
        // Dense: apply real points and phantom points.
        for p_ix in 0..
        for j in 0..= 0 && pt < point_count {
            out_x.set(
              pt,
              out_x.at(pt) +
              gvar_scale_funit_delta_to_fixed16_16(dxs.at(j), scalar),
            )
            out_y.set(
              pt,
              out_y.at(pt) +
              gvar_scale_funit_delta_to_fixed16_16(dys.at(j), scalar),
            )
            has_delta.set(pt, true)
          } else if pt >= point_count && pt < total_points {
            accum_x.set(
              pt,
              accum_x.at(pt) +
              gvar_scale_funit_delta_to_fixed16_16(dxs.at(j), scalar),
            )
            accum_y.set(
              pt,
              accum_y.at(pt) +
              gvar_scale_funit_delta_to_fixed16_16(dys.at(j), scalar),
            )
          }
        }
    }
    if !gvar_interpolate_deltas_fixed(
        orig_x, orig_y, out_x, out_y, has_delta, end_pts, point_count,
      ) {
      return Some(gvar_zero_deltas(total_points))
    }
    for p_ix in 0.. (Array[Int], Array[Int])? {
  if coords.is_empty() {
    return None
  }
  if component_count <= 0 {
    return None
  }
  let ctx = match gvar_ctx(font) {
    None => return None
    Some(c) => c
  }
  let gid_i = gid.to_uint64().to_int()
  if gid_i < 0 || gid_i >= ctx.glyph_count {
    return None
  }
  let total_points = component_count + 4
  if total_points <= 0 {
    return None
  }
  // Offsets array starts at 20.
  let offsets_off = 20
  let long_offsets = (ctx.flags & 1) != 0
  let entry_size = if long_offsets { 4 } else { 2 }
  let need = offsets_off + (ctx.glyph_count + 1) * entry_size
  if need < 0 || need > ctx.gvar.length() {
    return Some(gvar_zero_deltas(total_points))
  }
  let off0 = if long_offsets {
    gvar_read_u32_be_int(ctx.gvar, offsets_off + gid_i * 4).unwrap_or(-1)
  } else {
    gvar_read_u16_be(ctx.gvar, offsets_off + gid_i * 2).unwrap_or(-1) * 2
  }
  let off1 = if long_offsets {
    gvar_read_u32_be_int(ctx.gvar, offsets_off + (gid_i + 1) * 4).unwrap_or(-1)
  } else {
    gvar_read_u16_be(ctx.gvar, offsets_off + (gid_i + 1) * 2).unwrap_or(-1) * 2
  }
  if off0 < 0 || off1 < off0 {
    return Some(gvar_zero_deltas(total_points))
  }
  let start = ctx.data_array_off + off0
  let end = ctx.data_array_off + off1
  if start < 0 || end < start || end > ctx.gvar.length() {
    return Some(gvar_zero_deltas(total_points))
  }
  if start == end {
    return Some(gvar_zero_deltas(total_points))
  }
  let tuple_count_flags = gvar_read_u16_be(ctx.gvar, start).unwrap_or(0)
  let tuple_count = tuple_count_flags & 0x0FFF
  let shared_points = (tuple_count_flags & 0x8000) != 0
  let data_rel = gvar_read_u16_be(ctx.gvar, start + 2).unwrap_or(-1)
  if tuple_count <= 0 || data_rel < 0 {
    return Some(gvar_zero_deltas(total_points))
  }
  let sizes : Array[Int] = Array::new()
  let tuple_indexes : Array[Int] = Array::new()
  let axis_count = ctx.axis_count
  let scalars : Array[Int] = Array::new()
  let mut header_off = start + 4
  for _ in 0.. end {
        return Some(gvar_zero_deltas(total_points))
      }
      for ax in 0..= ctx.shared_tuple_count {
        return Some(gvar_zero_deltas(total_points))
      }
      let base = ctx.shared_tuples_off + shared_ix * axis_count * 2
      let need = base + axis_count * 2
      if base < 0 || need < base || need > ctx.gvar.length() {
        return Some(gvar_zero_deltas(total_points))
      }
      for ax in 0.. end {
        return Some(gvar_zero_deltas(total_points))
      }
      for ax in 0.. end {
    return Some(gvar_zero_deltas(total_points))
  }
  let accum_x : Array[Int] = Array::make(total_points, 0)
  let accum_y : Array[Int] = Array::make(total_points, 0)
  let mut cursor = data_off
  let mut shared_points_list : Array[Int]? = None
  if shared_points {
    let (pts, off2) = match gvar_points(ctx.gvar, cursor, total_points) {
      None => return Some(gvar_zero_deltas(total_points))
      Some(v) => v
    }
    shared_points_list = pts
    cursor = off2
  }
  for i in 0.. end {
      return Some(gvar_zero_deltas(total_points))
    }
    let scalar = scalars.at(i)
    if scalar == 0 {
      cursor = tuple_end
      continue
    }
    // PRIVATE_POINT_NUMBERS = 0x2000.
    let private_points = (ti & 0x2000) != 0
    let mut points_list : Array[Int]? = None
    let mut after_points = cursor
    if private_points || !shared_points {
      let (pts, off2) = match gvar_points(ctx.gvar, cursor, total_points) {
        None => return Some(gvar_zero_deltas(total_points))
        Some(v) => v
      }
      points_list = pts
      after_points = off2
    } else {
      points_list = shared_points_list
      after_points = cursor
    }
    let count = match points_list {
      None => total_points
      Some(arr) => arr.length()
    }
    let (dxs, after_x) = match gvar_deltas(ctx.gvar, after_points, count) {
      None => return Some(gvar_zero_deltas(total_points))
      Some(v) => v
    }
    let (dys, after_y) = match gvar_deltas(ctx.gvar, after_x, count) {
      None => return Some(gvar_zero_deltas(total_points))
      Some(v) => v
    }
    if after_y > tuple_end {
      return Some(gvar_zero_deltas(total_points))
    }
    match points_list {
      None =>
        for pt in 0..
        for j in 0..= 0 && pt < total_points {
            accum_x.set(
              pt,
              accum_x.at(pt) +
              gvar_scale_funit_delta_to_fixed16_16(dxs.at(j), scalar),
            )
            accum_y.set(
              pt,
              accum_y.at(pt) +
              gvar_scale_funit_delta_to_fixed16_16(dys.at(j), scalar),
            )
          }
        }
    }
    cursor = tuple_end
  }
  Some((accum_x, accum_y))
}