From faeba0c0c0bfb2b3a12f0859dd7c86e8cb341037 Mon Sep 17 00:00:00 2001 From: Sascha Brawer Date: Tue, 2 Feb 2016 18:23:37 +0100 Subject: [PATCH] [feaLib] Support lookups with mixed glyph/class-based kerning Resolves https://github.com/behdad/fonttools/issues/456 --- Lib/fontTools/feaLib/builder.py | 69 +++++++++++------------- Lib/fontTools/feaLib/testdata/GPOS_2.fea | 16 ++++-- Lib/fontTools/feaLib/testdata/GPOS_2.ttx | 56 +++++++++++++++++-- 3 files changed, 94 insertions(+), 47 deletions(-) diff --git a/Lib/fontTools/feaLib/builder.py b/Lib/fontTools/feaLib/builder.py index df2e35e96..072844bd9 100644 --- a/Lib/fontTools/feaLib/builder.py +++ b/Lib/fontTools/feaLib/builder.py @@ -617,12 +617,12 @@ class Builder(object): def add_class_pair_pos(self, location, glyphclass1, value1, glyphclass2, value2): - lookup = self.get_lookup_(location, ClassPairPosBuilder) - lookup.add_pair(location, glyphclass1, value1, glyphclass2, value2) + lookup = self.get_lookup_(location, PairPosBuilder) + lookup.addClassPair(location, glyphclass1, value1, glyphclass2, value2) def add_specific_pair_pos(self, location, glyph1, value1, glyph2, value2): - lookup = self.get_lookup_(location, SpecificPairPosBuilder) - lookup.add_pair(location, glyph1, value1, glyph2, value2) + lookup = self.get_lookup_(location, PairPosBuilder) + lookup.addGlyphPair(location, glyph1, value1, glyph2, value2) def add_single_pos(self, location, prefix, suffix, pos): if prefix or suffix: @@ -885,34 +885,6 @@ class MultipleSubstBuilder(LookupBuilder): return self.buildLookup_([subtable]) -class SpecificPairPosBuilder(LookupBuilder): - def __init__(self, font, location): - LookupBuilder.__init__(self, font, location, 'GPOS', 2) - self.pairs = {} # (glyph1, glyph2) -> (value1, value2) - self.locations = {} # (glyph1, glyph2) -> (filepath, line, column) - - def add_pair(self, location, glyph1, value1, glyph2, value2): - key = (glyph1, glyph2) - oldValue = self.pairs.get(key, None) - if oldValue is not None: - otherLoc = self.locations[key] - raise FeatureLibError( - 'Already defined position for pair %s %s at %s:%d:%d' - % (glyph1, glyph2, otherLoc[0], otherLoc[1], otherLoc[2]), - location) - val1, _ = makeOpenTypeValueRecord(value1) - val2, _ = makeOpenTypeValueRecord(value2) - self.pairs[key] = (val1, val2) - self.locations[key] = location - - def equals(self, other): - return (LookupBuilder.equals(self, other) and self.pairs == other.pairs) - - def build(self): - subtables = otl.buildPairPosGlyphs(self.pairs, self.glyphMap) - return self.buildLookup_(subtables) - - class CursivePosBuilder(LookupBuilder): def __init__(self, font, location): LookupBuilder.__init__(self, font, location, 'GPOS', 3) @@ -1107,29 +1079,45 @@ class ClassPairPosSubtableBuilder(object): self.subtables_.append(st) -class ClassPairPosBuilder(LookupBuilder): +class PairPosBuilder(LookupBuilder): SUBTABLE_BREAK_ = "SUBTABLE_BREAK" def __init__(self, font, location): LookupBuilder.__init__(self, font, location, 'GPOS', 2) - self.pairs = [] # [(location, gc1, value1, gc2, value2)*] + self.pairs = [] # [(gc1, value1, gc2, value2)*] + self.glyphPairs = {} # (glyph1, glyph2) --> (value1, value2) + self.locations = {} # (gc1, gc2) --> (filepath, line, column) - def add_pair(self, location, glyphclass1, value1, glyphclass2, value2): - self.pairs.append((location, glyphclass1, value1, glyphclass2, value2)) + def addClassPair(self, location, glyphclass1, value1, glyphclass2, value2): + self.pairs.append((glyphclass1, value1, glyphclass2, value2)) + + def addGlyphPair(self, location, glyph1, value1, glyph2, value2): + key = (glyph1, glyph2) + oldValue = self.glyphPairs.get(key, None) + if oldValue is not None: + otherLoc = self.locations[key] + raise FeatureLibError( + 'Already defined position for pair %s %s at %s:%d:%d' + % (glyph1, glyph2, otherLoc[0], otherLoc[1], otherLoc[2]), + location) + val1, _ = makeOpenTypeValueRecord(value1) + val2, _ = makeOpenTypeValueRecord(value2) + self.glyphPairs[key] = (val1, val2) + self.locations[key] = location def add_subtable_break(self, location): - self.pairs.append((location, - self.SUBTABLE_BREAK_, self.SUBTABLE_BREAK_, + self.pairs.append((self.SUBTABLE_BREAK_, self.SUBTABLE_BREAK_, self.SUBTABLE_BREAK_, self.SUBTABLE_BREAK_)) def equals(self, other): return (LookupBuilder.equals(self, other) and + self.glyphPairs == other.glyphPairs and self.pairs == other.pairs) def build(self): builders = {} builder = None - for location, glyphclass1, value1, glyphclass2, value2 in self.pairs: + for glyphclass1, value1, glyphclass2, value2 in self.pairs: if glyphclass1 is self.SUBTABLE_BREAK_: if builder is not None: builder.addSubtableBreak() @@ -1143,6 +1131,9 @@ class ClassPairPosBuilder(LookupBuilder): builders[(valFormat1, valFormat2)] = builder builder.addPair(glyphclass1, val1, glyphclass2, val2) subtables = [] + if self.glyphPairs: + subtables.extend( + otl.buildPairPosGlyphs(self.glyphPairs, self.glyphMap)) for key in sorted(builders.keys()): subtables.extend(builders[key].subtables()) return self.buildLookup_(subtables) diff --git a/Lib/fontTools/feaLib/testdata/GPOS_2.fea b/Lib/fontTools/feaLib/testdata/GPOS_2.fea index e30209e65..b1f26d154 100644 --- a/Lib/fontTools/feaLib/testdata/GPOS_2.fea +++ b/Lib/fontTools/feaLib/testdata/GPOS_2.fea @@ -1,18 +1,28 @@ languagesystem DFLT dflt; -feature kern { +# Mixes kerning between single glyphs, and class-based kerning. +# https://github.com/behdad/fonttools/issues/456 +lookup MixedKerning { + pos v v 14; + pos [D O Q] [T V W] -26; +} MixedKerning; + +lookup GlyphKerning { pos T one 100; pos T two 200; pos T two.oldstyle 200; pos T three 300; pos T four 400; - pos X a 100; pos X b 200; - pos Y a 100; pos Y b 200; pos Y c <3 3 3 3>; +} GlyphKerning; + +feature kern { + lookup GlyphKerning; + lookup MixedKerning; } kern; feature vkrn { diff --git a/Lib/fontTools/feaLib/testdata/GPOS_2.ttx b/Lib/fontTools/feaLib/testdata/GPOS_2.ttx index 97e0249b8..219353540 100644 --- a/Lib/fontTools/feaLib/testdata/GPOS_2.ttx +++ b/Lib/fontTools/feaLib/testdata/GPOS_2.ttx @@ -23,21 +23,67 @@ - - + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -112,7 +158,7 @@ - +