diff --git a/src/fontra_compile/builder.py b/src/fontra_compile/builder.py index 67a9202..99a61f5 100644 --- a/src/fontra_compile/builder.py +++ b/src/fontra_compile/builder.py @@ -834,8 +834,29 @@ def applyAxisMapToAxisValues(axis) -> tuple[float, float, float]: return (minValue, defaultValue, maxValue) -def axisTuple(axis) -> tuple[float, float, float]: - return (axis.minValue, axis.defaultValue, axis.maxValue) +def axisTuple(axis, fixAsymmetricAxes=True) -> tuple[float, float, float]: + minValue, defaultValue, maxValue = axis.minValue, axis.defaultValue, axis.maxValue + if fixAsymmetricAxes and minValue < defaultValue < maxValue: + # Variable component axis values can interpolate across the "default" border. + # For example if an axis goes from 0 to 1000 with the default at 200, a variable + # component may interpolate this from 100 to 600. In the VARC table, all axis + # values will be normalized to (-1, 0, +1). So 100 would normalize to -0.5 and 600 + # would normalize to +0.5. But this means that interpolation does not work the + # same in the normalized space. For example, the midpoint between -0.5 and +0.5 + # is 0, but the midpoint between 100 and 600 is 350, which would normalize to + # 0.1875. This is obviously a problem. + # To work around it, we extend either side of the axis so the distance between + # minValue and defaultValue becomes the same as the distance between defaultValue + # and maxValue. + # The downside of this approach is that axis values will no longer be clipped to + # their original minimum or maximum, so we may create new edge cases here. + minDiff = defaultValue - minValue + maxDiff = maxValue - defaultValue + if minDiff > maxDiff: + maxValue = defaultValue + minDiff + elif minDiff < maxDiff: + minValue = defaultValue - maxDiff + return minValue, defaultValue, maxValue def newAxisDescriptor( diff --git a/tests/data/notosanscjksc.otf.ttx b/tests/data/notosanscjksc.otf.ttx index 4c077a2..509535c 100644 --- a/tests/data/notosanscjksc.otf.ttx +++ b/tests/data/notosanscjksc.otf.ttx @@ -21,12 +21,12 @@ - + - - + + @@ -539,7 +539,7 @@ - + @@ -2053,6 +2053,78 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -2124,7 +2196,7 @@ - + @@ -2196,7 +2268,7 @@ - + @@ -2268,7 +2340,7 @@ - + @@ -2340,7 +2412,7 @@ - + @@ -2412,7 +2484,7 @@ - + @@ -2484,7 +2556,7 @@ - + @@ -2556,7 +2628,7 @@ - + @@ -2628,7 +2700,7 @@ - + @@ -2700,7 +2772,7 @@ - + @@ -2772,7 +2844,7 @@ - + @@ -2844,7 +2916,7 @@ - + @@ -2916,7 +2988,7 @@ - + @@ -2988,7 +3060,7 @@ - + @@ -3060,7 +3132,7 @@ - + @@ -3132,7 +3204,7 @@ - + @@ -3204,7 +3276,7 @@ - + @@ -3276,7 +3348,7 @@ - + @@ -3348,7 +3420,7 @@ - + @@ -3420,7 +3492,7 @@ - + @@ -3492,7 +3564,79 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -3564,7 +3708,7 @@ - + @@ -3681,9 +3825,9 @@ - - - + + + @@ -3702,22 +3846,22 @@ - + - - - + + + - - - - - - - - - + + + + + + + + + @@ -3725,7 +3869,7 @@ - + @@ -3733,7 +3877,7 @@ - + @@ -3741,9 +3885,9 @@ - + - + @@ -3752,10 +3896,10 @@ - - - - + + + + @@ -3765,15 +3909,15 @@ - + - - + + @@ -3783,17 +3927,17 @@ - + - - - - + + + + @@ -3928,8 +4072,8 @@ - - + + @@ -4072,7 +4216,7 @@ - + @@ -4095,9 +4239,9 @@ - + - +