[feaLib] Handle languagesystem, script and languaguage statements

Currently, the compiler uses them to figure out which set of
languagesystems would apply for the current scope. However, this
information is not yet used for anything.
This commit is contained in:
Sascha Brawer 2015-09-04 22:29:06 +02:00
parent 701c72116d
commit 102c0e0e56
3 changed files with 82 additions and 5 deletions

View File

@ -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):

View File

@ -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)

View File

@ -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()