[feaLib] Add helper for creating glyph class definition tables

The helper will be used for building class-based kerning tables.
This commit is contained in:
Sascha Brawer 2015-12-22 14:42:13 +01:00
parent dd23788a53
commit 26c02e4d95
2 changed files with 73 additions and 3 deletions

View File

@ -1121,3 +1121,43 @@ class SinglePosBuilder(LookupBuilder):
st.Value, st.ValueFormat = value, valueFormat
return self.buildLookup_(subtables)
class ClassDefBuilder(object):
"""Helper for building ClassDef tables."""
def __init__(self, otClass):
self.classes = set()
self.glyphs = {}
self.otClass = otClass
def canAdd(self, glyphs):
glyphs = frozenset(glyphs)
if glyphs in self.classes:
return True
for glyph in glyphs:
if glyph in self.glyphs:
return False
return True
def add(self, glyphs):
glyphs = frozenset(glyphs)
if glyphs in self.classes:
return
self.classes.add(glyphs)
for glyph in glyphs:
assert glyph not in self.glyphs
self.glyphs[glyph] = glyphs
def build(self):
glyphClasses = {}
# Class id #0 does not need to be encoded because zero is the default
# when no class is specified. Therefore, we use id #0 for the glyph
# class that has the largest number of members.
classes = sorted(self.classes, key=len, reverse=True)
for classID, glyphs in enumerate(classes):
if classID != 0:
for glyph in glyphs:
glyphClasses[glyph] = classID
classDef = self.otClass()
classDef.classDefs = glyphClasses
return classDef

View File

@ -1,9 +1,10 @@
from __future__ import print_function, division, absolute_import
from __future__ import unicode_literals
from fontTools.feaLib.builder import Builder, addOpenTypeFeatures
from fontTools.feaLib.builder import LigatureSubstBuilder
from fontTools.feaLib.builder import ClassDefBuilder, LigatureSubstBuilder
from fontTools.feaLib.error import FeatureLibError
from fontTools.ttLib import TTFont
from fontTools.ttLib.tables import otTables
import codecs
import difflib
import os
@ -311,10 +312,39 @@ class BuilderTest(unittest.TestCase):
"} foo;")
class ClassDefBuilderTest(unittest.TestCase):
def test_build(self):
builder = ClassDefBuilder(otTables.ClassDef2)
builder.add({"a", "b"})
builder.add({"c"})
builder.add({"e", "f", "g", "h"})
cdef = builder.build()
self.assertIsInstance(cdef, otTables.ClassDef2)
# The largest class {"e", "f", "g", "h"} should become class ID #0.
# Zero is the default class ID, so it does not get encoded at all.
self.assertEqual(cdef.classDefs, {
"a": 1,
"b": 1,
"c": 2
})
def test_canAdd(self):
b = ClassDefBuilder(otTables.ClassDef1)
b.add({"a", "b", "c", "d"})
b.add({"e", "f"})
self.assertTrue(b.canAdd({"a", "b", "c", "d"}))
self.assertTrue(b.canAdd({"e", "f"}))
self.assertTrue(b.canAdd({"g", "h", "i"}))
self.assertFalse(b.canAdd({"b", "c", "d"}))
self.assertFalse(b.canAdd({"a", "b", "c", "d", "e", "f"}))
self.assertFalse(b.canAdd({"d", "e", "f"}))
self.assertFalse(b.canAdd({"f"}))
class LigatureSubstBuilderTest(unittest.TestCase):
def test_make_key(self):
self.assertEqual(LigatureSubstBuilder.make_key(('f', 'f', 'i')),
(-3, ('f', 'f', 'i')))
self.assertEqual(LigatureSubstBuilder.make_key(("f", "f", "i")),
(-3, ("f", "f", "i")))
if __name__ == "__main__":