aboutsummaryrefslogtreecommitdiff
path: root/Lib/fontTools/otlLib/builder.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/fontTools/otlLib/builder.py')
-rw-r--r--Lib/fontTools/otlLib/builder.py57
1 files changed, 34 insertions, 23 deletions
diff --git a/Lib/fontTools/otlLib/builder.py b/Lib/fontTools/otlLib/builder.py
index 233edec2..3508a7e2 100644
--- a/Lib/fontTools/otlLib/builder.py
+++ b/Lib/fontTools/otlLib/builder.py
@@ -55,7 +55,11 @@ def buildCoverage(glyphs, glyphMap):
if not glyphs:
return None
self = ot.Coverage()
- self.glyphs = sorted(set(glyphs), key=glyphMap.__getitem__)
+ try:
+ self.glyphs = sorted(set(glyphs), key=glyphMap.__getitem__)
+ except KeyError as e:
+ raise ValueError(f"Could not find glyph {e} in font") from e
+
return self
@@ -369,10 +373,19 @@ class ChainContextualBuilder(LookupBuilder):
rulesets = self.rulesets()
chaining = any(ruleset.hasPrefixOrSuffix for ruleset in rulesets)
+
+ # https://github.com/fonttools/fonttools/issues/2539
+ #
# Unfortunately, as of 2022-03-07, Apple's CoreText renderer does not
# correctly process GPOS7 lookups, so for now we force contextual
# positioning lookups to be chaining (GPOS8).
- if self.subtable_type == "Pos": # horrible separation of concerns breach
+ #
+ # This seems to be fixed as of macOS 13.2, but we keep disabling this
+ # for now until we are no longer concerned about old macOS versions.
+ # But we allow people to opt-out of this with the config key below.
+ write_gpos7 = self.font.cfg.get("fontTools.otlLib.builder:WRITE_GPOS7")
+ # horrible separation of concerns breach
+ if not write_gpos7 and self.subtable_type == "Pos":
chaining = True
for ruleset in rulesets:
@@ -764,7 +777,7 @@ class ChainContextSubstBuilder(ChainContextualBuilder):
result.setdefault(glyph, set()).update(replacements)
return result
- def find_chainable_single_subst(self, glyphs):
+ def find_chainable_single_subst(self, mapping):
"""Helper for add_single_subst_chained_()"""
res = None
for rule in self.rules[::-1]:
@@ -772,7 +785,7 @@ class ChainContextSubstBuilder(ChainContextualBuilder):
return res
for sub in rule.lookups:
if isinstance(sub, SingleSubstBuilder) and not any(
- g in glyphs for g in sub.mapping.keys()
+ g in mapping and mapping[g] != sub.mapping[g] for g in sub.mapping
):
res = sub
return res
@@ -981,7 +994,7 @@ class MarkBasePosBuilder(LookupBuilder):
for mc, anchor in anchors.items():
if mc not in markClasses:
raise ValueError(
- "Mark class %s not found for base glyph %s" % (mc, mark)
+ "Mark class %s not found for base glyph %s" % (mc, glyph)
)
bases[glyph][markClasses[mc]] = anchor
subtables = buildMarkBasePos(marks, bases, self.glyphMap)
@@ -1387,27 +1400,16 @@ class PairPosBuilder(LookupBuilder):
lookup.
"""
builders = {}
- builder = None
+ builder = ClassPairPosSubtableBuilder(self)
for glyphclass1, value1, glyphclass2, value2 in self.pairs:
if glyphclass1 is self.SUBTABLE_BREAK_:
- if builder is not None:
- builder.addSubtableBreak()
+ builder.addSubtableBreak()
continue
- valFormat1, valFormat2 = 0, 0
- if value1:
- valFormat1 = value1.getFormat()
- if value2:
- valFormat2 = value2.getFormat()
- builder = builders.get((valFormat1, valFormat2))
- if builder is None:
- builder = ClassPairPosSubtableBuilder(self)
- builders[(valFormat1, valFormat2)] = builder
builder.addPair(glyphclass1, value1, glyphclass2, value2)
subtables = []
if self.glyphPairs:
subtables.extend(buildPairPosGlyphs(self.glyphPairs, self.glyphMap))
- for key in sorted(builders.keys()):
- subtables.extend(builders[key].subtables())
+ subtables.extend(builder.subtables())
lookup = self.buildLookup_(subtables)
# Compact the lookup
@@ -2511,9 +2513,14 @@ def buildAttachPoint(points):
def buildCaretValueForCoord(coord):
# 500 --> otTables.CaretValue, format 1
+ # (500, DeviceTable) --> otTables.CaretValue, format 3
self = ot.CaretValue()
- self.Format = 1
- self.Coordinate = coord
+ if isinstance(coord, tuple):
+ self.Format = 3
+ self.Coordinate, self.DeviceTable = coord
+ else:
+ self.Format = 1
+ self.Coordinate = coord
return self
@@ -2575,7 +2582,8 @@ def buildLigGlyph(coords, points):
# ([500], [4]) --> otTables.LigGlyph; None for empty coords/points
carets = []
if coords:
- carets.extend([buildCaretValueForCoord(c) for c in sorted(coords)])
+ coords = sorted(coords, key=lambda c: c[0] if isinstance(c, tuple) else c)
+ carets.extend([buildCaretValueForCoord(c) for c in coords])
if points:
carets.extend([buildCaretValueForPoint(p) for p in sorted(points)])
if not carets:
@@ -2666,7 +2674,7 @@ class ClassDefBuilder(object):
# class form a contiguous range, the encoding is actually quite
# compact, whereas a non-contiguous set might need a lot of bytes
# in the output file. We don't get this right with the key below.
- result = sorted(self.classes_, key=lambda s: (len(s), s), reverse=True)
+ result = sorted(self.classes_, key=lambda s: (-len(s), s))
if not self.useClass0_:
result.insert(0, frozenset())
return result
@@ -2792,6 +2800,7 @@ def buildStatTable(
locations, axes, nameTable, windowsNames=windowsNames, macNames=macNames
)
axisValues = multiAxisValues + axisValues
+ nameTable.names.sort()
# Store AxisRecords
axisRecordArray = ot.AxisRecordArray()
@@ -2801,6 +2810,8 @@ def buildStatTable(
statTable.DesignAxisRecord = axisRecordArray
statTable.DesignAxisCount = len(axisRecords)
+ statTable.AxisValueCount = 0
+ statTable.AxisValueArray = None
if axisValues:
# Store AxisValueRecords
axisValueArray = ot.AxisValueArray()