[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) Block.__init__(self, location)
self.name, self.use_extension = name, use_extension 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): class LookupBlock(Block):
def __init__(self, location, name, use_extension): def __init__(self, location, name, use_extension):
@ -63,6 +68,11 @@ class LanguageStatement(Statement):
self.include_default = include_default self.include_default = include_default
self.required = required 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): class LanguageSystemStatement(Statement):
def __init__(self, location, script, language): def __init__(self, location, script, language):
@ -90,6 +100,9 @@ class ScriptStatement(Statement):
Statement.__init__(self, location) Statement.__init__(self, location)
self.script = script self.script = script
def build(self, builder):
builder.set_script(self.location, self.script)
class SubtableStatement(Statement): class SubtableStatement(Statement):
def __init__(self, location): def __init__(self, location):

View File

@ -14,7 +14,10 @@ class Builder(object):
def __init__(self, featurefile_path, font): def __init__(self, featurefile_path, font):
self.featurefile_path = featurefile_path self.featurefile_path = featurefile_path
self.font = font self.font = font
self.language_systems_ = [] self.default_language_systems_ = set()
self.script_ = None
self.lookupflag_ = 0
self.language_systems = set()
def build(self): def build(self):
self.gpos = self.font['GPOS'] = self.makeTable('GPOS') self.gpos = self.font['GPOS'] = self.makeTable('GPOS')
@ -37,9 +40,37 @@ class Builder(object):
return table return table
def add_language_system(self, location, script, language): 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( raise FeatureLibError(
'If "languagesystem DFLT dflt" is present, it must be ' 'If "languagesystem DFLT dflt" is present, it must be '
'the first of the languagesystem statements', location) '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 print_function, division, absolute_import
from __future__ import unicode_literals 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.feaLib.error import FeatureLibError
from fontTools.ttLib import TTFont from fontTools.ttLib import TTFont
import codecs import codecs
@ -77,6 +77,19 @@ class BuilderTest(unittest.TestCase):
addOpenTypeFeatures(self.getpath("spec4h1.fea"), font) addOpenTypeFeatures(self.getpath("spec4h1.fea"), font)
self.expect_ttx(font, self.getpath("spec4h1_expected.ttx")) 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): def test_languagesystem_DFLT_dflt_not_first(self):
self.assertRaisesRegex( self.assertRaisesRegex(
FeatureLibError, FeatureLibError,
@ -84,6 +97,26 @@ class BuilderTest(unittest.TestCase):
"it must be the first of the languagesystem statements", "it must be the first of the languagesystem statements",
self.build, "languagesystem latn TRK; languagesystem DFLT dflt;") 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__": if __name__ == "__main__":
unittest.main() unittest.main()