diff --git a/Lib/fontTools/feaLib/ast.py b/Lib/fontTools/feaLib/ast.py index 3b1b89321..a60ac3ec3 100644 --- a/Lib/fontTools/feaLib/ast.py +++ b/Lib/fontTools/feaLib/ast.py @@ -30,6 +30,11 @@ class FeatureBlock(Block): Block.__init__(self, location) self.name, self.use_extension = name, use_extension + def build(self, builder): + # TODO(sascha): Handle use_extension. + builder.start_feature(self.location, self.name) + Block.build(self, builder) + class LookupBlock(Block): def __init__(self, location, name, use_extension): @@ -63,6 +68,11 @@ class LanguageStatement(Statement): self.include_default = include_default self.required = required + def build(self, builder): + # TODO(sascha): Handle required. + builder.set_language(location=self.location, language=self.language, + include_default=self.include_default) + class LanguageSystemStatement(Statement): def __init__(self, location, script, language): @@ -90,6 +100,9 @@ class ScriptStatement(Statement): Statement.__init__(self, location) self.script = script + def build(self, builder): + builder.set_script(self.location, self.script) + class SubtableStatement(Statement): def __init__(self, location): diff --git a/Lib/fontTools/feaLib/builder.py b/Lib/fontTools/feaLib/builder.py index 1f85450e9..e3664133e 100644 --- a/Lib/fontTools/feaLib/builder.py +++ b/Lib/fontTools/feaLib/builder.py @@ -14,7 +14,10 @@ class Builder(object): def __init__(self, featurefile_path, font): self.featurefile_path = featurefile_path self.font = font - self.language_systems_ = [] + self.default_language_systems_ = set() + self.script_ = None + self.lookupflag_ = 0 + self.language_systems = set() def build(self): self.gpos = self.font['GPOS'] = self.makeTable('GPOS') @@ -37,9 +40,37 @@ class Builder(object): return table def add_language_system(self, location, script, language): - if script == "DFLT" and language == "dflt" and self.language_systems_: - # OpenType Feature File Specification, section 4.b.i + # OpenType Feature File Specification, section 4.b.i + if (script == "DFLT" and language == "dflt" and + self.default_language_systems_): raise FeatureLibError( 'If "languagesystem DFLT dflt" is present, it must be ' 'the first of the languagesystem statements', location) - self.language_systems_.append((script, language)) + self.default_language_systems_.add((script, language)) + + def get_default_language_systems_(self): + # OpenType Feature File specification, 4.b.i. languagesystem: + # If no "languagesystem" statement is present, then the + # implementation must behave exactly as though the following + # statement were present at the beginning of the feature file: + # languagesystem DFLT dflt; + if self.default_language_systems_: + return frozenset(self.default_language_systems_) + else: + return frozenset({('DFLT', 'dflt')}) + + def start_feature(self, location, name): + self.language_systems = self.get_default_language_systems_() + + def set_language(self, location, language, include_default): + if include_default: + langsys = set(self.get_default_language_systems_()) + else: + langsys = set() + langsys.add((self.script_, language)) + self.language_systems = frozenset(langsys) + + def set_script(self, location, script): + self.script_ = script + self.lookupflag_ = 0 + self.set_language(location, 'dflt', include_default=True) diff --git a/Lib/fontTools/feaLib/builder_test.py b/Lib/fontTools/feaLib/builder_test.py index 7eee08bb6..dfd1b0250 100644 --- a/Lib/fontTools/feaLib/builder_test.py +++ b/Lib/fontTools/feaLib/builder_test.py @@ -1,6 +1,6 @@ from __future__ import print_function, division, absolute_import from __future__ import unicode_literals -from fontTools.feaLib.builder import addOpenTypeFeatures +from fontTools.feaLib.builder import Builder, addOpenTypeFeatures from fontTools.feaLib.error import FeatureLibError from fontTools.ttLib import TTFont import codecs @@ -77,6 +77,19 @@ class BuilderTest(unittest.TestCase): addOpenTypeFeatures(self.getpath("spec4h1.fea"), font) self.expect_ttx(font, self.getpath("spec4h1_expected.ttx")) + def test_languagesystem(self): + builder = Builder(None, TTFont()) + builder.add_language_system(None, 'latn', 'FRA') + builder.add_language_system(None, 'cyrl', 'RUS') + builder.start_feature(location=None, name='test') + self.assertEqual(builder.language_systems, + {('latn', 'FRA'), ('cyrl', 'RUS')}) + + def test_languagesystem_none_specified(self): + builder = Builder(None, TTFont()) + builder.start_feature(location=None, name='test') + self.assertEqual(builder.language_systems, {('DFLT', 'dflt')}) + def test_languagesystem_DFLT_dflt_not_first(self): self.assertRaisesRegex( FeatureLibError, @@ -84,6 +97,26 @@ class BuilderTest(unittest.TestCase): "it must be the first of the languagesystem statements", self.build, "languagesystem latn TRK; languagesystem DFLT dflt;") + def test_script(self): + builder = Builder(None, TTFont()) + builder.start_feature(location=None, name='test') + builder.set_script(location=None, script='cyrl') + self.assertEqual(builder.language_systems, + {('DFLT', 'dflt'), ('cyrl', 'dflt')}) + + def test_language(self): + builder = Builder(None, TTFont()) + builder.add_language_system(None, 'latn', 'FRA') + builder.start_feature(location=None, name='test') + builder.set_script(location=None, script='cyrl') + builder.set_language(location=None, language='RUS', + include_default=False) + self.assertEqual(builder.language_systems, {('cyrl', 'RUS')}) + builder.set_language(location=None, language='BGR', + include_default=True) + self.assertEqual(builder.language_systems, + {('latn', 'FRA'), ('cyrl', 'BGR')}) + if __name__ == "__main__": unittest.main()