the lack of rounding within the delta computation can lead to deltas that are off-by-one by the time they are eventually ot-rounded to i16, as it is shown in Gelasio's MVAR table (from which the reproducer is drawn).
The commits that follow will apply the fix for #1043 as well as for #235, and add more tests borrowed from fonttools models_test.py
Basically we need to apply the rounding within the very same loop in which deltas get subtracted away from the absolute master values. This is to make sure that the rounding errors are accounted for and don't accummulate beyond 0.5 when multiple regions overlap.
The use of the banker's "round half to even" method (round_ties_even in Rust) matches the fonttools varLib's choice of Python's built-in round() function. The latter is preferred over OtRound for relative values such as deltas primarily because of its symmetry: e.g. round(1.5) == 2 and round(-1.5) == -2, not -1. OtRound ((v + 0.5).floor()) is biased towards higher, positive values and makes more sense for absolute coordinates.
the first commit is a repro for https://github.com/googlefonts/fontc/issues/1043#issuecomment-2426907952
the lack of rounding within the delta computation can lead to deltas that are off-by-one by the time they are eventually ot-rounded to i16, as it is shown in Gelasio's MVAR table (from which the reproducer is drawn).
The commits that follow will apply the fix for #1043 as well as for #235, and add more tests borrowed from fonttools models_test.py
Basically we need to apply the rounding within the very same loop in which deltas get subtracted away from the absolute master values. This is to make sure that the rounding errors are accounted for and don't accummulate beyond 0.5 when multiple regions overlap.
The use of the banker's "round half to even" method (
round_ties_even
in Rust) matches the fonttools varLib's choice of Python's built-inround()
function. The latter is preferred over OtRound for relative values such as deltas primarily because of its symmetry: e.g. round(1.5) == 2 and round(-1.5) == -2, not -1. OtRound ((v + 0.5).floor()
) is biased towards higher, positive values and makes more sense for absolute coordinates./cc @behdad