Skip to content

Commit

Permalink
Merge pull request #3042 from fonttools/conditionset-consult-avar
Browse files Browse the repository at this point in the history
Conditionset: consult avar to normalize values
  • Loading branch information
madig committed Mar 15, 2023
2 parents 032616b + c3a5e9e commit a55a545
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 10 deletions.
2 changes: 1 addition & 1 deletion Lib/fontTools/feaLib/ast.py
Expand Up @@ -2065,7 +2065,7 @@ def __init__(self, name, conditions, location=None):
self.conditions = conditions

def build(self, builder):
builder.add_conditionset(self.name, self.conditions)
builder.add_conditionset(self.location, self.name, self.conditions)

def asFea(self, res="", indent=""):
res += indent + f"conditionset {self.name} " + "{\n"
Expand Down
27 changes: 18 additions & 9 deletions Lib/fontTools/feaLib/builder.py
Expand Up @@ -34,7 +34,7 @@
from fontTools.varLib.varStore import OnlineVarStoreBuilder
from fontTools.varLib.builder import buildVarDevTable
from fontTools.varLib.featureVars import addFeatureVariationsRaw
from fontTools.varLib.models import normalizeValue
from fontTools.varLib.models import normalizeValue, piecewiseLinearMap
from collections import defaultdict
import itertools
from io import StringIO
Expand Down Expand Up @@ -947,11 +947,7 @@ def makeFeatureVariations(self, table, table_tag):
feature_vars = {}
has_any_variations = False
# Sort out which lookups to build, gather their indices
for (
script_,
language,
feature_tag,
), variations in self.feature_variations_.items():
for (_, _, feature_tag), variations in self.feature_variations_.items():
feature_vars[feature_tag] = []
for conditionset, builders in variations.items():
raw_conditionset = self.conditionsets_[conditionset]
Expand Down Expand Up @@ -1572,10 +1568,11 @@ def add_hhea_field(self, key, value):
def add_vhea_field(self, key, value):
self.vhea_[key] = value

def add_conditionset(self, key, value):
if not "fvar" in self.font:
def add_conditionset(self, location, key, value):
if "fvar" not in self.font:
raise FeatureLibError(
"Cannot add feature variations to a font without an 'fvar' table"
"Cannot add feature variations to a font without an 'fvar' table",
location,
)

# Normalize
Expand All @@ -1592,6 +1589,18 @@ def add_conditionset(self, key, value):
for tag, (bottom, top) in value.items()
}

# NOTE: This might result in rounding errors (off-by-ones) compared to
# rules in Designspace files, since we're working with what's in the
# `avar` table rather than the original values.
if "avar" in self.font:
mapping = self.font["avar"].segments
value = {
axis: tuple(
piecewiseLinearMap(v, mapping[axis]) for v in condition_range
)
for axis, condition_range in value.items()
}

self.conditionsets_[key] = value

def makeOpenTypeAnchor(self, location, anchor):
Expand Down
51 changes: 51 additions & 0 deletions Tests/feaLib/builder_test.py
Expand Up @@ -975,6 +975,57 @@ def test_unmarked_ignore_statement(self):
f'{name}.fea:{line}:12: Ambiguous "ignore {sub}", there should be least one marked glyph'
)

def test_condition_set_avar(self):
"""Test that the `avar` table is consulted when normalizing user-space
values."""

features = """
languagesystem DFLT dflt;
lookup conditional_sub {
sub e by a;
} conditional_sub;
conditionset test {
wght 600 1000;
} test;
variation rlig test {
lookup conditional_sub;
} rlig;
"""

def make_mock_vf():
font = makeTTFont()
font["name"] = newTable("name")
addFvar(font, [("wght", 0, 0, 1000, "Weight")], [])
del font["name"]
return font

# Without `avar`:
font = make_mock_vf()
addOpenTypeFeaturesFromString(font, features)
assert (
font.tables["GSUB"]
.table.FeatureVariations.FeatureVariationRecord[0]
.ConditionSet.ConditionTable[0]
.FilterRangeMinValue
== 0.6 # user-space 600
)

# With `avar`, shifting the positive midpoint 0.5 a bit to the right:
font = make_mock_vf()
font["avar"] = newTable("avar")
font["avar"].segments = {"wght": {-1.0: -1.0, 0.0: 0.0, 0.5: 0.625, 1.0: 1.0}}
addOpenTypeFeaturesFromString(font, features)
assert (
font.tables["GSUB"]
.table.FeatureVariations.FeatureVariationRecord[0]
.ConditionSet.ConditionTable[0]
.FilterRangeMinValue
== 0.7 # user-space 600 shifted to the right,
)


def generate_feature_file_test(name):
return lambda self: self.check_feature_file(name)
Expand Down

0 comments on commit a55a545

Please sign in to comment.