diff --git a/CHANGELOG.md b/CHANGELOG.md index 793a8f982c..fe6e81f723 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ A more detailed list of changes is available in the corresponding milestones for #### On the Universal Profile - **[kerning_for_non_ligated_sequences]**: "Is there kerning info for non-ligated sequences?" (issue #2954 / https://github.com/simoncozens/fontspector/commit/eaa52447ddc4a42e26b6430841a43026870d8a48) +#### On the OpenType Profile + - **[opentype/STAT_has_axis_value_tables]**: Because **inconsistencies_between_fvar_STAT** (now on `Universal`) potentially has a wider scope in the future, checking back from the fvar table to the STAT table. (https://github.com/fonttools/fontbakery/issues/4916#issuecomment-2507999113) + ### Changes to existing checks ### On the Universal profile - **[smallcaps_before_ligatures]:** This check works just fine on OTFs, no need for `conditions=["is_ttf"]` (issue #4920) diff --git a/Lib/fontbakery/checks/opentype/STAT_has_axis_value_tables.py b/Lib/fontbakery/checks/opentype/STAT_has_axis_value_tables.py deleted file mode 100644 index 22620e00eb..0000000000 --- a/Lib/fontbakery/checks/opentype/STAT_has_axis_value_tables.py +++ /dev/null @@ -1,95 +0,0 @@ -from fontbakery.prelude import check, Message, FAIL, PASS - - -@check( - id="opentype/STAT_has_axis_value_tables", - rationale=""" - According to the OpenType spec, in a variable font, it is strongly recommended - that axis value tables be included for every element of typographic subfamily - names for all of the named instances defined in the 'fvar' table. - - Axis value tables are particularly important for variable fonts, but can also - be used in non-variable fonts. When used in non-variable fonts, axis value - tables for particular values should be implemented consistently across fonts - in the family. - - If present, Format 4 Axis Value tables are checked to ensure they have more than - one AxisValueRecord (a strong recommendation from the OpenType spec). - - https://docs.microsoft.com/en-us/typography/opentype/spec/stat#axis-value-tables - """, - conditions=["has_STAT_table"], - proposal="https://github.com/fonttools/fontbakery/issues/3090", -) -def check_STAT_has_axis_value_tables(ttFont, is_variable_font): - """STAT table has Axis Value tables?""" - passed = True - STAT_table = ttFont["STAT"].table - - if ttFont["STAT"].table.AxisValueCount == 0: - yield FAIL, Message( - "no-axis-value-tables", - "STAT table has no Axis Value tables.", - ) - return - - if is_variable_font: - # Collect all the values defined for each design axis in the STAT table. - STAT_axes_values = {} - for axis_index, axis in enumerate(STAT_table.DesignAxisRecord.Axis): - axis_tag = axis.AxisTag - axis_values = set() - - # Iterate over Axis Value tables. - for axis_value in STAT_table.AxisValueArray.AxisValue: - axis_value_format = axis_value.Format - - if axis_value_format in (1, 2, 3): - if axis_value.AxisIndex != axis_index: - # Not the axis we're collecting for, skip. - continue - - if axis_value_format == 2: - axis_values.add(axis_value.NominalValue) - else: - axis_values.add(axis_value.Value) - - elif axis_value_format == 4: - # check that axisCount > 1. Also, format 4 records DO NOT - # contribute to the "STAT_axes_values" list used to check - # against fvar instances. - # see https://github.com/fonttools/fontbakery/issues/3957 - if axis_value.AxisCount <= 1: - yield FAIL, Message( - "format-4-axis-count", - "STAT Format 4 Axis Value table has axis count <= 1.", - ) - - else: - # FAIL on unknown axis_value_format - yield FAIL, Message( - "unknown-axis-value-format", - f"AxisValue format {axis_value_format} is unknown.", - ) - - STAT_axes_values[axis_tag] = axis_values - - # Iterate over the 'fvar' named instances, and confirm that every coordinate - # can be represented by the STAT table Axis Value tables. - for inst in ttFont["fvar"].instances: - for coord_axis_tag, coord_axis_value in inst.coordinates.items(): - if ( - coord_axis_tag in STAT_axes_values - and coord_axis_value in STAT_axes_values[coord_axis_tag] - ): - continue - - yield FAIL, Message( - "missing-axis-value-table", - f"STAT table is missing Axis Value for" - f" {coord_axis_tag!r} value '{coord_axis_value}'", - ) - passed = False - - if passed: - yield PASS, "STAT table has Axis Value tables." diff --git a/Lib/fontbakery/profiles/adobefonts.py b/Lib/fontbakery/profiles/adobefonts.py index a519813d6d..dfde2cd681 100644 --- a/Lib/fontbakery/profiles/adobefonts.py +++ b/Lib/fontbakery/profiles/adobefonts.py @@ -196,20 +196,6 @@ "Fonts that do not meet these guidelines might behave inconsistently so please carefully consider trying to meet them.", }, ], - "opentype/STAT_has_axis_value_tables": [ - { - "code": "missing-axis-value-table", - "status": "WARN", - "reason": "Adobe and the OpenType spec strongly recommend following these guidelines, but they are not hard requirements so we are relaxing this to WARN rather than FAIL.\n" - "Fonts that do not meet these guidelines might behave inconsistently so please carefully consider trying to meet them.", - }, - { - "code": "format-4-axis-count", - "status": "WARN", - "reason": "Adobe and the OpenType spec strongly recommend following these guidelines, but they are not hard requirements so we are relaxing this to WARN rather than FAIL.\n" - "Fonts that do not meet these guidelines might behave inconsistently so please carefully consider trying to meet them.", - }, - ], "inconsistencies_between_fvar_STAT": [ { "code": "missing-fvar-instance-axis-value", diff --git a/Lib/fontbakery/profiles/opentype.py b/Lib/fontbakery/profiles/opentype.py index 31dda76702..9710a3f350 100644 --- a/Lib/fontbakery/profiles/opentype.py +++ b/Lib/fontbakery/profiles/opentype.py @@ -45,7 +45,6 @@ "opentype/postscript_name", "opentype/post_table_version", "opentype/slant_direction", - "opentype/STAT_has_axis_value_tables", "opentype/unitsperem", "opentype/varfont/distinct_instance_records", "opentype/varfont/family_axis_ranges", diff --git a/tests/test_checks_adobefonts_overrides.py b/tests/test_checks_adobefonts_overrides.py index 089549a706..f7a5e35d50 100644 --- a/tests/test_checks_adobefonts_overrides.py +++ b/tests/test_checks_adobefonts_overrides.py @@ -1,7 +1,6 @@ from unittest.mock import patch from fontTools.ttLib import TTFont -from fontTools.ttLib.tables.otTables import AxisValueRecord import requests from conftest import check_id @@ -189,37 +188,6 @@ def test_check_override_varfont_valid_default_instance_nameids(check): assert "Overridden" in msg -@check_id("opentype/STAT_has_axis_value_tables", profile=adobefonts_profile) -def test_check_override_STAT_has_axis_value_tables(check): - """Check that overridden tests yield the right result.""" - - # Our reference Cabin[wdth,wght].ttf variable font has Axis Value tables. - ttFont = TTFont(TEST_FILE("cabinvf/Cabin[wdth,wght].ttf")) - # Remove the 4th Axis Value table (index 3), belonging to 'Medium' weight. - # The overridden check should WARN. - ttFont["STAT"].table.AxisValueArray.AxisValue.pop(3) - msg = assert_results_contain(check(ttFont), WARN, "missing-axis-value-table") - assert "STAT table is missing Axis Value for 'wght' value '500.0'" in msg - assert "Overridden" in msg - - # Add a format 4 AxisValue table with a single AxisValueRecord. This overriden check - # should WARN. - ttFont = TTFont(TEST_FILE("cabinvf/Cabin[wdth,wght].ttf")) - f4avt = type(ttFont["STAT"].table.AxisValueArray.AxisValue[0])() - f4avt.Format = 4 - f4avt.Flags = 0 - f4avt.ValueNameID = 2 - avr0 = AxisValueRecord() - avr0.AxisIndex = 0 - avr0.Value = 100 - f4avt.AxisValueRecord = [avr0] - f4avt.AxisCount = len(f4avt.AxisValueRecord) - ttFont["STAT"].table.AxisValueArray.AxisValue.append(f4avt) - msg = assert_results_contain(check(ttFont), WARN, "format-4-axis-count") - assert "STAT Format 4 Axis Value table has axis count <= 1." in msg - assert "Overridden" in msg - - @check_id("inconsistencies_between_fvar_STAT", profile=adobefonts_profile) def test_check_override_inconsistencies_between_fvar_STAT(check): """Check that the overridden test yields WARN rather than FAIL""" diff --git a/tests/test_checks_opentype_stat.py b/tests/test_checks_opentype_stat.py index 9c340f6251..d63e706345 100644 --- a/tests/test_checks_opentype_stat.py +++ b/tests/test_checks_opentype_stat.py @@ -1,5 +1,4 @@ from fontTools.ttLib import TTFont -from fontTools.ttLib.tables.otTables import AxisValueRecord from conftest import check_id from fontbakery.status import FAIL, SKIP, WARN @@ -37,76 +36,6 @@ def test_check_varfont_STAT_axis_record_for_each_axis(check): assert "Unfulfilled Conditions: is_variable_font" in msg -@check_id("opentype/STAT_has_axis_value_tables") -def test_check_STAT_has_axis_value_tables(check): - """Check the STAT table has at least one Axis Value table.""" - - # Our reference Cabin[wdth,wght].ttf variable font has Axis Value tables. - # So the check must PASS. - ttFont = TTFont(TEST_FILE("cabinvf/Cabin[wdth,wght].ttf")) - assert_PASS(check(ttFont)) - - # Remove the 4th Axis Value table (index 3), belonging to 'Medium' weight. - # The check should FAIL. - ttFont["STAT"].table.AxisValueArray.AxisValue.pop(3) - msg = assert_results_contain(check(ttFont), FAIL, "missing-axis-value-table") - assert msg == "STAT table is missing Axis Value for 'wght' value '500.0'" - - # Now remove all Axis Value tables by emptying the AxisValueArray. - # The check should FAIL. - ttFont["STAT"].table.AxisValueArray = None - ttFont["STAT"].table.AxisValueCount = 0 - msg = assert_results_contain(check(ttFont), FAIL, "no-axis-value-tables") - assert msg == "STAT table has no Axis Value tables." - - # Most of the Axis Value tables in Cabin[wdth,wght].ttf are format 1. - # Now test with SourceSansVariable-Italic.ttf whose tables are mostly format 2. - ttFont = TTFont(TEST_FILE("source-sans-pro/VAR/SourceSansVariable-Italic.ttf")) - assert_PASS(check(ttFont)) - - # Remove the 2nd Axis Value table (index 1), belonging to 'Light' weight. - # The check should FAIL. - ttFont["STAT"].table.AxisValueArray.AxisValue.pop(1) - msg = assert_results_contain(check(ttFont), FAIL, "missing-axis-value-table") - assert msg == "STAT table is missing Axis Value for 'wght' value '300.0'" - - # Now use a font that has no STAT table. - # The check should be skipped due to an unfulfilled condition. - ttFont = TTFont(TEST_FILE("source-sans-pro/TTF/SourceSansPro-Black.ttf")) - msg = assert_results_contain(check(ttFont), SKIP, "unfulfilled-conditions") - assert "Unfulfilled Conditions: has_STAT_table" in msg - - # Add a format 4 AxisValue table with 2 AxisValueRecords. This should PASS. - ttFont = TTFont(TEST_FILE("cabinvf/Cabin[wdth,wght].ttf")) - f4avt = type(ttFont["STAT"].table.AxisValueArray.AxisValue[0])() - f4avt.Format = 4 - f4avt.Flags = 0 - f4avt.ValueNameID = 2 - avr0 = AxisValueRecord() - avr0.AxisIndex = 0 - avr0.Value = 100 - avr1 = AxisValueRecord() - avr1.AxisIndex = 1 - avr1.Value = 400 - f4avt.AxisValueRecord = [avr0, avr1] - f4avt.AxisCount = len(f4avt.AxisValueRecord) - ttFont["STAT"].table.AxisValueArray.AxisValue.append(f4avt) - assert_PASS(check(ttFont)) - - # Now delete one of the AxisValueRecords of the just-added format 4 AxisValue table. - # This should now FAIL since format 4 should contain at least 2 AxisValueRecords. - del ttFont["STAT"].table.AxisValueArray.AxisValue[7].AxisValueRecord[1] - ttFont["STAT"].table.AxisValueArray.AxisValue[7].AxisCount = 1 - msg = assert_results_contain(check(ttFont), FAIL, "format-4-axis-count") - assert msg == "STAT Format 4 Axis Value table has axis count <= 1." - - # An unknown AxisValue table Format should FAIL. - ttFont = TTFont(TEST_FILE("cabinvf/Cabin[wdth,wght].ttf")) - ttFont["STAT"].table.AxisValueArray.AxisValue[0].Format = 5 - msg = assert_results_contain(check(ttFont), FAIL, "unknown-axis-value-format") - assert msg == "AxisValue format 5 is unknown." - - @check_id("opentype/italic_axis_in_STAT") def test_check_italic_axis_in_STAT(check): """Ensure VFs have 'ital' STAT axis."""