diff options
Diffstat (limited to 'Lib/fontTools/otlLib/builder.py')
-rw-r--r-- | Lib/fontTools/otlLib/builder.py | 57 |
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() |