Repository: fonttools/fonttools

Issue:
[varLib.mutator] Does not mutate weight/width/italicAngle
Because those are not in MVAR, but in standard axes. Quoting MVAR spec:

> Note: The OS/2.usWeightClass, OS/2.usWidthClass and post.italicAngle values are not supported by variation data in the 'MVAR' table. This is because values for these three fields correspond directly to input axis values for the 'wght', 'wdth' and 'slnt' variation axes. See the discussion of these axes in the OpenType Design-Variation Axis Tag Registry for details on the relationship between these fields and the corresponding design axes.

There's probably some binary flags that we can also tweak, re boldness, italicness, etc of the font.


Discussion:
> There's probably some binary flags that we can also tweak, re boldness, italicness, etc of the font

OK, it's clear what to do with OS/2.usWeightClass, usWidthClass and post.italicAngle.

But, about the `OS/2.fsSelection` or `head.macStyle` which @behdad is hinting at in his comment -- when exactly do we want to set the bold flags? Say, when the location on the `wght`
axis and the corresponding OS/2.usWeightClass is _exactly_ 700? But not when it's 699 or 900 or whatever?

And about the "italic" font selection flags, I think we should not set those based on "slnt" axis. The latter should only be correlated to the "post.italicAngle". The "ital" registered axis might be used instead, but again if we do that, where do we put the threshold? When it's 100% italic, or >= 50 %?
This all seem a bit arbitrary to me.

Resolving patch:
diff --git a/Lib/fontTools/varLib/mutator.py b/Lib/fontTools/varLib/mutator.py
--- a/Lib/fontTools/varLib/mutator.py
+++ b/Lib/fontTools/varLib/mutator.py
@@ -20,6 +20,13 @@
 
 log = logging.getLogger("fontTools.varlib.mutator")
 
+# map 'wdth' axis (1..200) to OS/2.usWidthClass (1..9), rounding to closest
+OS2_WIDTH_CLASS_VALUES = {}
+percents = [50.0, 62.5, 75.0, 87.5, 100.0, 112.5, 125.0, 150.0, 200.0]
+for i, (prev, curr) in enumerate(zip(percents[:-1], percents[1:]), start=1):
+	half = (prev + curr) / 2
+	OS2_WIDTH_CLASS_VALUES[half] = i
+
 
 def instantiateVariableFont(varfont, location, inplace=False):
 	""" Generate a static instance from a variable TTFont and a dictionary
@@ -123,6 +130,21 @@ def instantiateVariableFont(varfont, location, inplace=False):
 			if n.nameID not in exclude
 		]
 
+	if "wght" in location and "OS/2" in varfont:
+		varfont["OS/2"].usWeightClass = otRound(
+			max(1, min(location["wght"], 1000))
+		)
+	if "wdth" in location:
+		wdth = location["wdth"]
+		for percent, widthClass in sorted(OS2_WIDTH_CLASS_VALUES.items()):
+			if wdth < percent:
+				varfont["OS/2"].usWidthClass = widthClass
+				break
+		else:
+			varfont["OS/2"].usWidthClass = 9
+	if "slnt" in location and "post" in varfont:
+		varfont["post"].italicAngle = max(-90, min(location["slnt"], 90))
+
 	log.info("Removing variable tables")
 	for tag in ('avar','cvar','fvar','gvar','HVAR','MVAR','VVAR','STAT'):
 		if tag in varfont:


Test patch:
diff --git a/Tests/varLib/data/test_results/Mutator.ttx b/Tests/varLib/data/test_results/Mutator.ttx
--- a/Tests/varLib/data/test_results/Mutator.ttx
+++ b/Tests/varLib/data/test_results/Mutator.ttx
@@ -55,7 +55,7 @@
          will be recalculated by the compiler -->
     <version value="4"/>
     <xAvgCharWidth value="506"/>
-    <usWeightClass value="400"/>
+    <usWeightClass value="500"/>
     <usWidthClass value="5"/>
     <fsType value="00000000 00000100"/>
     <ySubscriptXSize value="650"/>
diff --git a/Tests/varLib/data/test_results/Mutator_IUP-instance.ttx b/Tests/varLib/data/test_results/Mutator_IUP-instance.ttx
--- a/Tests/varLib/data/test_results/Mutator_IUP-instance.ttx
+++ b/Tests/varLib/data/test_results/Mutator_IUP-instance.ttx
@@ -57,7 +57,7 @@
     <version value="3"/>
     <xAvgCharWidth value="347"/>
     <usWeightClass value="400"/>
-    <usWidthClass value="5"/>
+    <usWidthClass value="3"/>
     <fsType value="00000000 00000100"/>
     <ySubscriptXSize value="700"/>
     <ySubscriptYSize value="650"/>