From a3e14643a1b297aeb3dcde4adc20581f911c8f84 Mon Sep 17 00:00:00 2001 From: Nikolaus Waxweiler Date: Thu, 30 Jun 2022 18:56:03 +0100 Subject: [PATCH 1/6] Set RIBBI bits when cutting instances --- Lib/fontTools/varLib/instancer/__init__.py | 44 +++++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/Lib/fontTools/varLib/instancer/__init__.py b/Lib/fontTools/varLib/instancer/__init__.py index 91dd586ff..44044a76f 100644 --- a/Lib/fontTools/varLib/instancer/__init__.py +++ b/Lib/fontTools/varLib/instancer/__init__.py @@ -90,12 +90,10 @@ from fontTools.varLib import builder from fontTools.varLib.mvar import MVAR_ENTRIES from fontTools.varLib.merger import MutatorMerger from fontTools.varLib.instancer import names -from contextlib import contextmanager import collections from copy import deepcopy from enum import IntEnum import logging -from itertools import islice import os import re @@ -1273,9 +1271,51 @@ def instantiateVariableFont( }, ) + if "fvar" not in varfont: + # For statics, we should set various bits to mark them as + # Regular/Italic/Bold/BoldItalic as appropriate. + setRibbiBits(varfont) + return varfont +def setRibbiBits(staticFont): + """Set the `head.macStyle` and `OS/2.fsSelection` style bits + appropriately.""" + + english_ribbi_style = staticFont["name"].getName(2, 3, 1, 0x409) + if english_ribbi_style is None: + log.warning( + "Cannot set RIBBI bits because there is no Windows Unicode BMP name ID 2." + ) + return + + styleMapStyleName = english_ribbi_style.toStr().lower() + if styleMapStyleName == "bold": + staticFont["head"].macStyle = 0b01 + elif styleMapStyleName == "bold italic": + staticFont["head"].macStyle = 0b11 + elif styleMapStyleName == "italic": + staticFont["head"].macStyle = 0b10 + + selection = staticFont["OS/2"].fsSelection + # First clear... + selection &= ~(1 << 0) + selection &= ~(1 << 5) + selection &= ~(1 << 6) + # ...then re-set the bits. + if styleMapStyleName == "regular": + selection |= 1 << 6 + elif styleMapStyleName == "bold": + selection |= 1 << 5 + elif styleMapStyleName == "italic": + selection |= 1 << 0 + elif styleMapStyleName == "bold italic": + selection |= 1 << 0 + selection |= 1 << 5 + staticFont["OS/2"].fsSelection = selection + + def splitAxisLocationAndRanges(axisLimits, rangeType=AxisRange): location, axisRanges = {}, {} for axisTag, value in axisLimits.items(): From 16d899a2bea30c9a9cb7d8a9674d94701f2e68ed Mon Sep 17 00:00:00 2001 From: Nikolaus Waxweiler Date: Tue, 5 Jul 2022 15:45:44 +0100 Subject: [PATCH 2/6] Apply RIBBI bits to all kinds of fonts --- Lib/fontTools/varLib/instancer/__init__.py | 34 +- .../instancer/data/STATInstancerTest.ttx | 1830 +++++++++++++++++ Tests/varLib/instancer/instancer_test.py | 32 + 3 files changed, 1882 insertions(+), 14 deletions(-) create mode 100644 Tests/varLib/instancer/data/STATInstancerTest.ttx diff --git a/Lib/fontTools/varLib/instancer/__init__.py b/Lib/fontTools/varLib/instancer/__init__.py index 44044a76f..bc64874cc 100644 --- a/Lib/fontTools/varLib/instancer/__init__.py +++ b/Lib/fontTools/varLib/instancer/__init__.py @@ -1271,19 +1271,18 @@ def instantiateVariableFont( }, ) - if "fvar" not in varfont: - # For statics, we should set various bits to mark them as - # Regular/Italic/Bold/BoldItalic as appropriate. - setRibbiBits(varfont) + # Set Regular/Italic/Bold/Bold Italic bits as appropriate, after the name + # table has been updated. + setRibbiBits(varfont) return varfont -def setRibbiBits(staticFont): +def setRibbiBits(font): """Set the `head.macStyle` and `OS/2.fsSelection` style bits appropriately.""" - english_ribbi_style = staticFont["name"].getName(2, 3, 1, 0x409) + english_ribbi_style = font["name"].getName(2, 3, 1, 0x409) if english_ribbi_style is None: log.warning( "Cannot set RIBBI bits because there is no Windows Unicode BMP name ID 2." @@ -1291,14 +1290,21 @@ def setRibbiBits(staticFont): return styleMapStyleName = english_ribbi_style.toStr().lower() - if styleMapStyleName == "bold": - staticFont["head"].macStyle = 0b01 - elif styleMapStyleName == "bold italic": - staticFont["head"].macStyle = 0b11 - elif styleMapStyleName == "italic": - staticFont["head"].macStyle = 0b10 + if styleMapStyleName not in {"regular", "bold", "italic", "bold italic"}: + log.warning( + "Cannot set RIBBI bits because the Windows Unicode BMP name ID 2 is " + "something other than Regular/Italic/Bold/Bold Italic." + ) + return - selection = staticFont["OS/2"].fsSelection + if styleMapStyleName == "bold": + font["head"].macStyle = 0b01 + elif styleMapStyleName == "bold italic": + font["head"].macStyle = 0b11 + elif styleMapStyleName == "italic": + font["head"].macStyle = 0b10 + + selection = font["OS/2"].fsSelection # First clear... selection &= ~(1 << 0) selection &= ~(1 << 5) @@ -1313,7 +1319,7 @@ def setRibbiBits(staticFont): elif styleMapStyleName == "bold italic": selection |= 1 << 0 selection |= 1 << 5 - staticFont["OS/2"].fsSelection = selection + font["OS/2"].fsSelection = selection def splitAxisLocationAndRanges(axisLimits, rangeType=AxisRange): diff --git a/Tests/varLib/instancer/data/STATInstancerTest.ttx b/Tests/varLib/instancer/data/STATInstancerTest.ttx new file mode 100644 index 000000000..eee24d821 --- /dev/null +++ b/Tests/varLib/instancer/data/STATInstancerTest.ttx @@ -0,0 +1,1830 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Weight + + + Width + + + Italic + + + Cd Hair + + + NewFont-CdHair + + + Cd Hair Italic + + + NewFont-CdHairItalic + + + Hair + + + NewFont-Hair + + + Hair Italic + + + NewFont-HairItalic + + + Ex Hair + + + NewFont-ExHair + + + Ex Hair Italic + + + NewFont-ExHairItalic + + + Cd Thin + + + NewFont-CdThin + + + Cd Thin Italic + + + NewFont-CdThinItalic + + + Thin + + + NewFont-Thin + + + Thin Italic + + + NewFont-ThinItalic + + + Ex Thin + + + NewFont-ExThin + + + Ex Thin Italic + + + NewFont-ExThinItalic + + + Cd Light + + + NewFont-CdLight + + + Cd Light Italic + + + NewFont-CdLightItalic + + + Light + + + NewFont-Light + + + Light Italic + + + NewFont-LightItalic + + + Ex Light + + + NewFont-ExLight + + + Ex Light Italic + + + NewFont-ExLightItalic + + + Cd + + + NewFont-Cd + + + Cd Italic + + + NewFont-CdItalic + + + + + + NewFont- + + + NewFont-Italic + + + Ex + + + NewFont-Ex + + + Ex Italic + + + NewFont-ExItalic + + + Cd Medium + + + NewFont-CdMedium + + + Cd Medium Italic + + + NewFont-CdMediumItalic + + + Medium + + + NewFont-Medium + + + Medium Italic + + + NewFont-MediumItalic + + + Ex Medium + + + NewFont-ExMedium + + + Ex Medium Italic + + + NewFont-ExMediumItalic + + + Cd SemiBold + + + NewFont-CdSemiBold + + + Cd SemiBold Italic + + + NewFont-CdSemiBoldItalic + + + SemiBold + + + NewFont-SemiBold + + + SemiBold Italic + + + NewFont-SemiBoldItalic + + + Ex SemiBold + + + NewFont-ExSemiBold + + + Ex SemiBold Italic + + + NewFont-ExSemiBoldItalic + + + Cd Bold + + + NewFont-CdBold + + + Cd Bold Italic + + + NewFont-CdBoldItalic + + + Bold + + + NewFont-Bold + + + Bold Italic + + + NewFont-BoldItalic + + + Ex Bold + + + NewFont-ExBold + + + Ex Bold Italic + + + NewFont-ExBoldItalic + + + Cd XBold + + + NewFont-CdXBold + + + Cd XBold Italic + + + NewFont-CdXBoldItalic + + + XBold + + + NewFont-XBold + + + XBold Italic + + + NewFont-XBoldItalic + + + Ex XBold + + + NewFont-ExXBold + + + Ex XBold Italic + + + NewFont-ExXBoldItalic + + + Cd Black + + + NewFont-CdBlack + + + Cd Black Italic + + + NewFont-CdBlackItalic + + + Black + + + NewFont-Black + + + Black Italic + + + NewFont-BlackItalic + + + Ex Black + + + NewFont-ExBlack + + + Ex Black Italic + + + NewFont-ExBlackItalic + + + Regular + + + Normal + + + Upright + + + New Font + + + Regular + + + 0.000;NONE;NewFont-Regular + + + New Font Regular + + + Version 0.000 + + + NewFont-Regular + + + Weight + + + Width + + + Italic + + + Cd Hair + + + NewFont-CdHair + + + Cd Hair Italic + + + NewFont-CdHairItalic + + + Hair + + + NewFont-Hair + + + Hair Italic + + + NewFont-HairItalic + + + Ex Hair + + + NewFont-ExHair + + + Ex Hair Italic + + + NewFont-ExHairItalic + + + Cd Thin + + + NewFont-CdThin + + + Cd Thin Italic + + + NewFont-CdThinItalic + + + Thin + + + NewFont-Thin + + + Thin Italic + + + NewFont-ThinItalic + + + Ex Thin + + + NewFont-ExThin + + + Ex Thin Italic + + + NewFont-ExThinItalic + + + Cd Light + + + NewFont-CdLight + + + Cd Light Italic + + + NewFont-CdLightItalic + + + Light + + + NewFont-Light + + + Light Italic + + + NewFont-LightItalic + + + Ex Light + + + NewFont-ExLight + + + Ex Light Italic + + + NewFont-ExLightItalic + + + Cd + + + NewFont-Cd + + + Cd Italic + + + NewFont-CdItalic + + + + + + NewFont- + + + NewFont-Italic + + + Ex + + + NewFont-Ex + + + Ex Italic + + + NewFont-ExItalic + + + Cd Medium + + + NewFont-CdMedium + + + Cd Medium Italic + + + NewFont-CdMediumItalic + + + Medium + + + NewFont-Medium + + + Medium Italic + + + NewFont-MediumItalic + + + Ex Medium + + + NewFont-ExMedium + + + Ex Medium Italic + + + NewFont-ExMediumItalic + + + Cd SemiBold + + + NewFont-CdSemiBold + + + Cd SemiBold Italic + + + NewFont-CdSemiBoldItalic + + + SemiBold + + + NewFont-SemiBold + + + SemiBold Italic + + + NewFont-SemiBoldItalic + + + Ex SemiBold + + + NewFont-ExSemiBold + + + Ex SemiBold Italic + + + NewFont-ExSemiBoldItalic + + + Cd Bold + + + NewFont-CdBold + + + Cd Bold Italic + + + NewFont-CdBoldItalic + + + Bold + + + NewFont-Bold + + + Bold Italic + + + NewFont-BoldItalic + + + Ex Bold + + + NewFont-ExBold + + + Ex Bold Italic + + + NewFont-ExBoldItalic + + + Cd XBold + + + NewFont-CdXBold + + + Cd XBold Italic + + + NewFont-CdXBoldItalic + + + XBold + + + NewFont-XBold + + + XBold Italic + + + NewFont-XBoldItalic + + + Ex XBold + + + NewFont-ExXBold + + + Ex XBold Italic + + + NewFont-ExXBoldItalic + + + Cd Black + + + NewFont-CdBlack + + + Cd Black Italic + + + NewFont-CdBlackItalic + + + Black + + + NewFont-Black + + + Black Italic + + + NewFont-BlackItalic + + + Ex Black + + + NewFont-ExBlack + + + Ex Black Italic + + + NewFont-ExBlackItalic + + + Regular + + + Normal + + + Upright + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + wght + 0x0 + 100.0 + 400.0 + 900.0 + 256 + + + + + wdth + 0x0 + 75.0 + 100.0 + 125.0 + 257 + + + + + ital + 0x0 + 0.0 + 0.0 + 1.0 + 258 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Tests/varLib/instancer/instancer_test.py b/Tests/varLib/instancer/instancer_test.py index c3b6f71d9..cd6787d5d 100644 --- a/Tests/varLib/instancer/instancer_test.py +++ b/Tests/varLib/instancer/instancer_test.py @@ -1975,3 +1975,35 @@ def test_main_exit_multiple_limits(varfont, tmpdir, capsys): captured = capsys.readouterr() assert "Specified multiple limits for the same axis" in captured.err + + +def test_set_ribbi_bits(): + varfont = ttLib.TTFont() + varfont.importXML(os.path.join(TESTDATA, "STATInstancerTest.ttx")) + + for location in [instance.coordinates for instance in varfont["fvar"].instances]: + instance = instancer.instantiateVariableFont( + varfont, location, updateFontNames=True + ) + name_id_2 = instance["name"].getDebugName(2) + mac_style = instance["head"].macStyle + fs_selection = instance["OS/2"].fsSelection & 0b1100001 # Just bits 0, 5, 6 + + if location["ital"] == 0: + if location["wght"] == 700: + assert name_id_2 == "Bold", location + assert mac_style == 0b01, location + assert fs_selection == 0b0100000, location + else: + assert name_id_2 == "Regular", location + assert mac_style == 0b00, location + assert fs_selection == 0b1000000, location + else: + if location["wght"] == 700: + assert name_id_2 == "Bold Italic", location + assert mac_style == 0b11, location + assert fs_selection == 0b0100001, location + else: + assert name_id_2 == "Italic", location + assert mac_style == 0b10, location + assert fs_selection == 0b0000001, location From 2c773441cf25caefe6fb04390818c482a015d512 Mon Sep 17 00:00:00 2001 From: Nikolaus Waxweiler Date: Tue, 5 Jul 2022 16:09:37 +0100 Subject: [PATCH 3/6] Remove logging --- Lib/fontTools/varLib/instancer/__init__.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/Lib/fontTools/varLib/instancer/__init__.py b/Lib/fontTools/varLib/instancer/__init__.py index bc64874cc..53f08b97a 100644 --- a/Lib/fontTools/varLib/instancer/__init__.py +++ b/Lib/fontTools/varLib/instancer/__init__.py @@ -1284,17 +1284,10 @@ def setRibbiBits(font): english_ribbi_style = font["name"].getName(2, 3, 1, 0x409) if english_ribbi_style is None: - log.warning( - "Cannot set RIBBI bits because there is no Windows Unicode BMP name ID 2." - ) return styleMapStyleName = english_ribbi_style.toStr().lower() if styleMapStyleName not in {"regular", "bold", "italic", "bold italic"}: - log.warning( - "Cannot set RIBBI bits because the Windows Unicode BMP name ID 2 is " - "something other than Regular/Italic/Bold/Bold Italic." - ) return if styleMapStyleName == "bold": From e84bee9cd965e897cf263a550bfcbf2fc1e41886 Mon Sep 17 00:00:00 2001 From: Nikolaus Waxweiler Date: Tue, 5 Jul 2022 16:10:15 +0100 Subject: [PATCH 4/6] Set bits only after updating names --- Lib/fontTools/varLib/instancer/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Lib/fontTools/varLib/instancer/__init__.py b/Lib/fontTools/varLib/instancer/__init__.py index 53f08b97a..e2b1326c9 100644 --- a/Lib/fontTools/varLib/instancer/__init__.py +++ b/Lib/fontTools/varLib/instancer/__init__.py @@ -1271,9 +1271,10 @@ def instantiateVariableFont( }, ) - # Set Regular/Italic/Bold/Bold Italic bits as appropriate, after the name - # table has been updated. - setRibbiBits(varfont) + if updateFontNames: + # Set Regular/Italic/Bold/Bold Italic bits as appropriate, after the + # name table has been updated. + setRibbiBits(varfont) return varfont From 87bf2a866deddd223a6ef223a110dd49c6712422 Mon Sep 17 00:00:00 2001 From: Nikolaus Waxweiler Date: Wed, 6 Jul 2022 10:37:22 +0100 Subject: [PATCH 5/6] Update docstring --- Lib/fontTools/varLib/instancer/__init__.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/fontTools/varLib/instancer/__init__.py b/Lib/fontTools/varLib/instancer/__init__.py index e2b1326c9..8ff56b90a 100644 --- a/Lib/fontTools/varLib/instancer/__init__.py +++ b/Lib/fontTools/varLib/instancer/__init__.py @@ -1198,10 +1198,10 @@ def instantiateVariableFont( requires the skia-pathops package (available to pip install). The overlap parameter only has effect when generating full static instances. updateFontNames (bool): if True, update the instantiated font's name table using - the Axis Value Tables from the STAT table. The name table will be updated so - it conforms to the R/I/B/BI model. If the STAT table is missing or - an Axis Value table is missing for a given axis coordinate, a ValueError will - be raised. + the Axis Value Tables from the STAT table. The name table and the style bits + in the head and OS/2 table will be updated so they conform to the R/I/B/BI + model. If the STAT table is missing or an Axis Value table is missing for + a given axis coordinate, a ValueError will be raised. """ # 'overlap' used to be bool and is now enum; for backward compat keep accepting bool overlap = OverlapMode(int(overlap)) From 2cd4f7e688a8a8752bda7bbc8f760fb71bd15b90 Mon Sep 17 00:00:00 2001 From: Nikolaus Waxweiler Date: Wed, 6 Jul 2022 10:40:27 +0100 Subject: [PATCH 6/6] Use NameID enum --- Lib/fontTools/varLib/instancer/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/fontTools/varLib/instancer/__init__.py b/Lib/fontTools/varLib/instancer/__init__.py index 8ff56b90a..73838db15 100644 --- a/Lib/fontTools/varLib/instancer/__init__.py +++ b/Lib/fontTools/varLib/instancer/__init__.py @@ -1283,7 +1283,7 @@ def setRibbiBits(font): """Set the `head.macStyle` and `OS/2.fsSelection` style bits appropriately.""" - english_ribbi_style = font["name"].getName(2, 3, 1, 0x409) + english_ribbi_style = font["name"].getName(names.NameID.SUBFAMILY_NAME, 3, 1, 0x409) if english_ribbi_style is None: return