2015-08-01 14:49:19 +02:00
|
|
|
from __future__ import print_function, division, absolute_import
|
|
|
|
from __future__ import unicode_literals
|
2015-12-12 12:54:23 +01:00
|
|
|
from fontTools.feaLib.error import FeatureLibError
|
2016-04-26 06:33:41 +01:00
|
|
|
from collections import OrderedDict
|
2015-09-07 16:10:13 +02:00
|
|
|
import itertools
|
2015-08-01 14:49:19 +02:00
|
|
|
|
|
|
|
|
2015-12-04 17:10:20 +01:00
|
|
|
def deviceToString(device):
|
|
|
|
if device is None:
|
|
|
|
return "<device NULL>"
|
|
|
|
else:
|
|
|
|
return "<device %s>" % ", ".join(["%d %d" % t for t in device])
|
|
|
|
|
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
class Statement(object):
|
|
|
|
def __init__(self, location):
|
|
|
|
self.location = location
|
2015-08-01 14:49:19 +02:00
|
|
|
|
2015-09-04 15:06:11 +02:00
|
|
|
def build(self, builder):
|
|
|
|
pass
|
|
|
|
|
2015-08-01 14:49:19 +02:00
|
|
|
|
2015-12-07 22:48:10 +01:00
|
|
|
class Expression(object):
|
|
|
|
def __init__(self, location):
|
|
|
|
self.location = location
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
pass
|
|
|
|
|
|
|
|
|
2015-12-11 15:16:22 +01:00
|
|
|
class GlyphName(Expression):
|
|
|
|
"""A single glyph name, such as cedilla."""
|
|
|
|
def __init__(self, location, glyph):
|
|
|
|
Expression.__init__(self, location)
|
|
|
|
self.glyph = glyph
|
|
|
|
|
|
|
|
def glyphSet(self):
|
2016-04-21 10:46:52 +01:00
|
|
|
return (self.glyph,)
|
2015-12-11 15:16:22 +01:00
|
|
|
|
|
|
|
|
|
|
|
class GlyphClass(Expression):
|
|
|
|
"""A glyph class, such as [acute cedilla grave]."""
|
|
|
|
def __init__(self, location, glyphs):
|
|
|
|
Expression.__init__(self, location)
|
|
|
|
self.glyphs = glyphs
|
|
|
|
|
|
|
|
def glyphSet(self):
|
2016-04-21 10:46:52 +01:00
|
|
|
return tuple(self.glyphs)
|
2015-12-11 15:16:22 +01:00
|
|
|
|
|
|
|
|
2015-12-10 13:04:16 +01:00
|
|
|
class GlyphClassName(Expression):
|
2015-12-11 15:16:22 +01:00
|
|
|
"""A glyph class name, such as @FRENCH_MARKS."""
|
2015-12-10 13:04:16 +01:00
|
|
|
def __init__(self, location, glyphclass):
|
|
|
|
Expression.__init__(self, location)
|
|
|
|
assert isinstance(glyphclass, GlyphClassDefinition)
|
|
|
|
self.glyphclass = glyphclass
|
|
|
|
|
2015-12-11 15:16:22 +01:00
|
|
|
def glyphSet(self):
|
2016-04-21 10:46:52 +01:00
|
|
|
return tuple(self.glyphclass.glyphs)
|
2015-12-11 15:16:22 +01:00
|
|
|
|
2015-12-10 13:04:16 +01:00
|
|
|
|
2015-12-11 16:28:01 +01:00
|
|
|
class MarkClassName(Expression):
|
|
|
|
"""A mark class name, such as @FRENCH_MARKS defined with markClass."""
|
2015-12-12 12:54:23 +01:00
|
|
|
def __init__(self, location, markClass):
|
2015-12-11 16:28:01 +01:00
|
|
|
Expression.__init__(self, location)
|
2015-12-12 12:54:23 +01:00
|
|
|
assert isinstance(markClass, MarkClass)
|
|
|
|
self.markClass = markClass
|
2015-12-11 16:28:01 +01:00
|
|
|
|
|
|
|
def glyphSet(self):
|
2015-12-12 12:54:23 +01:00
|
|
|
return self.markClass.glyphSet()
|
2015-12-11 16:28:01 +01:00
|
|
|
|
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
class Block(Statement):
|
|
|
|
def __init__(self, location):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.statements = []
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
for s in self.statements:
|
|
|
|
s.build(builder)
|
|
|
|
|
|
|
|
|
|
|
|
class FeatureFile(Block):
|
|
|
|
def __init__(self):
|
|
|
|
Block.__init__(self, location=None)
|
2015-12-12 12:54:23 +01:00
|
|
|
self.markClasses = {} # name --> ast.MarkClass
|
2015-09-04 16:11:53 +02:00
|
|
|
|
|
|
|
|
|
|
|
class FeatureBlock(Block):
|
2015-08-11 15:28:59 +02:00
|
|
|
def __init__(self, location, name, use_extension):
|
2015-09-04 16:11:53 +02:00
|
|
|
Block.__init__(self, location)
|
2015-08-11 15:28:59 +02:00
|
|
|
self.name, self.use_extension = name, use_extension
|
2015-08-01 19:58:54 +02:00
|
|
|
|
2015-09-04 22:29:06 +02:00
|
|
|
def build(self, builder):
|
|
|
|
# TODO(sascha): Handle use_extension.
|
|
|
|
builder.start_feature(self.location, self.name)
|
2016-08-30 18:44:33 +01:00
|
|
|
# language exclude_dflt statements modify builder.features_
|
|
|
|
# limit them to this block with temporary builder.features_
|
|
|
|
features = builder.features_
|
|
|
|
builder.features_ = {}
|
2015-09-04 22:29:06 +02:00
|
|
|
Block.build(self, builder)
|
2016-08-30 18:44:33 +01:00
|
|
|
for key, value in builder.features_.items():
|
|
|
|
features.setdefault(key, []).extend(value)
|
|
|
|
builder.features_ = features
|
2015-09-07 11:14:03 +02:00
|
|
|
builder.end_feature()
|
2015-09-04 22:29:06 +02:00
|
|
|
|
2015-08-01 19:58:54 +02:00
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
class LookupBlock(Block):
|
2015-08-11 10:59:26 +02:00
|
|
|
def __init__(self, location, name, use_extension):
|
2015-09-04 16:11:53 +02:00
|
|
|
Block.__init__(self, location)
|
2015-08-11 10:59:26 +02:00
|
|
|
self.name, self.use_extension = name, use_extension
|
|
|
|
|
2015-09-07 13:33:44 +02:00
|
|
|
def build(self, builder):
|
|
|
|
# TODO(sascha): Handle use_extension.
|
|
|
|
builder.start_lookup_block(self.location, self.name)
|
|
|
|
Block.build(self, builder)
|
|
|
|
builder.end_lookup_block()
|
|
|
|
|
2015-08-11 10:59:26 +02:00
|
|
|
|
2016-01-07 16:39:35 +01:00
|
|
|
class TableBlock(Block):
|
|
|
|
def __init__(self, location, name):
|
|
|
|
Block.__init__(self, location)
|
|
|
|
self.name = name
|
|
|
|
|
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
class GlyphClassDefinition(Statement):
|
2016-01-08 17:11:29 +01:00
|
|
|
"""Example: @UPPERCASE = [A-Z];"""
|
2015-08-01 17:34:02 +02:00
|
|
|
def __init__(self, location, name, glyphs):
|
2015-09-04 16:11:53 +02:00
|
|
|
Statement.__init__(self, location)
|
2015-08-01 17:34:02 +02:00
|
|
|
self.name = name
|
|
|
|
self.glyphs = glyphs
|
|
|
|
|
2015-12-11 16:28:01 +01:00
|
|
|
def glyphSet(self):
|
2016-04-21 10:46:52 +01:00
|
|
|
return tuple(self.glyphs)
|
2015-12-11 16:28:01 +01:00
|
|
|
|
2015-08-01 17:34:02 +02:00
|
|
|
|
2016-01-08 17:11:29 +01:00
|
|
|
class GlyphClassDefStatement(Statement):
|
|
|
|
"""Example: GlyphClassDef @UPPERCASE, [B], [C], [D];"""
|
|
|
|
def __init__(self, location, baseGlyphs, markGlyphs,
|
|
|
|
ligatureGlyphs, componentGlyphs):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.baseGlyphs, self.markGlyphs = (baseGlyphs, markGlyphs)
|
|
|
|
self.ligatureGlyphs = ligatureGlyphs
|
|
|
|
self.componentGlyphs = componentGlyphs
|
|
|
|
|
|
|
|
def build(self, builder):
|
2016-04-21 10:46:52 +01:00
|
|
|
base = self.baseGlyphs.glyphSet() if self.baseGlyphs else tuple()
|
|
|
|
liga = self.ligatureGlyphs.glyphSet() \
|
|
|
|
if self.ligatureGlyphs else tuple()
|
|
|
|
mark = self.markGlyphs.glyphSet() if self.markGlyphs else tuple()
|
2016-01-08 17:11:29 +01:00
|
|
|
comp = (self.componentGlyphs.glyphSet()
|
2016-04-21 10:46:52 +01:00
|
|
|
if self.componentGlyphs else tuple())
|
2016-01-08 19:06:52 +01:00
|
|
|
builder.add_glyphClassDef(self.location, base, liga, mark, comp)
|
2016-01-08 17:11:29 +01:00
|
|
|
|
|
|
|
|
2015-12-12 12:54:23 +01:00
|
|
|
# While glyph classes can be defined only once, the feature file format
|
|
|
|
# allows expanding mark classes with multiple definitions, each using
|
|
|
|
# different glyphs and anchors. The following are two MarkClassDefinitions
|
|
|
|
# for the same MarkClass:
|
|
|
|
# markClass [acute grave] <anchor 350 800> @FRENCH_ACCENTS;
|
|
|
|
# markClass [cedilla] <anchor 350 -200> @FRENCH_ACCENTS;
|
|
|
|
class MarkClass(object):
|
|
|
|
def __init__(self, name):
|
|
|
|
self.name = name
|
|
|
|
self.definitions = []
|
2016-04-26 06:33:41 +01:00
|
|
|
self.glyphs = OrderedDict() # glyph --> ast.MarkClassDefinitions
|
2015-12-12 12:54:23 +01:00
|
|
|
|
|
|
|
def addDefinition(self, definition):
|
|
|
|
assert isinstance(definition, MarkClassDefinition)
|
|
|
|
self.definitions.append(definition)
|
|
|
|
for glyph in definition.glyphSet():
|
|
|
|
if glyph in self.definitions:
|
|
|
|
otherLoc = self.definitions[glyph].location
|
2015-12-21 16:06:59 +01:00
|
|
|
raise FeatureLibError(
|
2015-12-12 12:54:23 +01:00
|
|
|
"Glyph %s already defined at %s:%d:%d" % (
|
|
|
|
glyph, otherLoc[0], otherLoc[1], otherLoc[2]),
|
|
|
|
definition.location)
|
|
|
|
self.glyphs[glyph] = definition
|
|
|
|
|
|
|
|
def glyphSet(self):
|
2016-04-21 10:46:52 +01:00
|
|
|
return tuple(self.glyphs.keys())
|
2015-12-12 12:54:23 +01:00
|
|
|
|
|
|
|
|
|
|
|
class MarkClassDefinition(Statement):
|
|
|
|
def __init__(self, location, markClass, anchor, glyphs):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
assert isinstance(markClass, MarkClass)
|
|
|
|
assert isinstance(anchor, Anchor) and isinstance(glyphs, Expression)
|
|
|
|
self.markClass, self.anchor, self.glyphs = markClass, anchor, glyphs
|
2015-12-08 17:04:21 +01:00
|
|
|
|
2015-12-11 16:28:01 +01:00
|
|
|
def glyphSet(self):
|
2015-12-12 12:54:23 +01:00
|
|
|
return self.glyphs.glyphSet()
|
2015-12-11 16:28:01 +01:00
|
|
|
|
2015-12-08 17:04:21 +01:00
|
|
|
|
2015-12-09 13:58:05 +01:00
|
|
|
class AlternateSubstStatement(Statement):
|
2016-01-07 11:32:54 +01:00
|
|
|
def __init__(self, location, prefix, glyph, suffix, replacement):
|
2015-09-04 16:11:53 +02:00
|
|
|
Statement.__init__(self, location)
|
2016-01-07 11:32:54 +01:00
|
|
|
self.prefix, self.glyph, self.suffix = (prefix, glyph, suffix)
|
|
|
|
self.replacement = replacement
|
2015-08-11 15:54:54 +02:00
|
|
|
|
2015-09-07 11:14:03 +02:00
|
|
|
def build(self, builder):
|
2016-01-07 11:32:54 +01:00
|
|
|
glyph = self.glyph.glyphSet()
|
|
|
|
assert len(glyph) == 1, glyph
|
|
|
|
glyph = list(glyph)[0]
|
|
|
|
prefix = [p.glyphSet() for p in self.prefix]
|
|
|
|
suffix = [s.glyphSet() for s in self.suffix]
|
|
|
|
replacement = self.replacement.glyphSet()
|
|
|
|
builder.add_alternate_subst(self.location, prefix, glyph, suffix,
|
|
|
|
replacement)
|
2015-09-07 11:14:03 +02:00
|
|
|
|
2015-08-11 15:54:54 +02:00
|
|
|
|
2015-12-07 22:48:10 +01:00
|
|
|
class Anchor(Expression):
|
|
|
|
def __init__(self, location, x, y, contourpoint,
|
|
|
|
xDeviceTable, yDeviceTable):
|
|
|
|
Expression.__init__(self, location)
|
|
|
|
self.x, self.y, self.contourpoint = x, y, contourpoint
|
|
|
|
self.xDeviceTable, self.yDeviceTable = xDeviceTable, yDeviceTable
|
|
|
|
|
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
class AnchorDefinition(Statement):
|
2015-08-11 12:53:30 +02:00
|
|
|
def __init__(self, location, name, x, y, contourpoint):
|
2015-09-04 16:11:53 +02:00
|
|
|
Statement.__init__(self, location)
|
2015-08-11 12:53:30 +02:00
|
|
|
self.name, self.x, self.y, self.contourpoint = name, x, y, contourpoint
|
|
|
|
|
|
|
|
|
2016-01-08 08:32:47 +01:00
|
|
|
class AttachStatement(Statement):
|
|
|
|
def __init__(self, location, glyphs, contourPoints):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.glyphs, self.contourPoints = (glyphs, contourPoints)
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
glyphs = self.glyphs.glyphSet()
|
|
|
|
builder.add_attach_points(self.location, glyphs, self.contourPoints)
|
|
|
|
|
|
|
|
|
2015-12-09 22:56:24 +01:00
|
|
|
class ChainContextPosStatement(Statement):
|
|
|
|
def __init__(self, location, prefix, glyphs, suffix, lookups):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.prefix, self.glyphs, self.suffix = prefix, glyphs, suffix
|
|
|
|
self.lookups = lookups
|
|
|
|
|
|
|
|
def build(self, builder):
|
2015-12-14 12:20:57 +01:00
|
|
|
prefix = [p.glyphSet() for p in self.prefix]
|
|
|
|
glyphs = [g.glyphSet() for g in self.glyphs]
|
|
|
|
suffix = [s.glyphSet() for s in self.suffix]
|
2015-12-09 22:56:24 +01:00
|
|
|
builder.add_chain_context_pos(
|
2015-12-14 12:20:57 +01:00
|
|
|
self.location, prefix, glyphs, suffix, self.lookups)
|
2015-12-09 22:56:24 +01:00
|
|
|
|
|
|
|
|
2015-12-09 13:58:05 +01:00
|
|
|
class ChainContextSubstStatement(Statement):
|
2015-12-14 12:20:57 +01:00
|
|
|
def __init__(self, location, prefix, glyphs, suffix, lookups):
|
2015-12-09 13:58:05 +01:00
|
|
|
Statement.__init__(self, location)
|
2016-01-06 16:15:26 +01:00
|
|
|
self.prefix, self.glyphs, self.suffix = prefix, glyphs, suffix
|
|
|
|
self.lookups = lookups
|
2015-12-09 13:58:05 +01:00
|
|
|
|
|
|
|
def build(self, builder):
|
2015-12-14 12:20:57 +01:00
|
|
|
prefix = [p.glyphSet() for p in self.prefix]
|
|
|
|
glyphs = [g.glyphSet() for g in self.glyphs]
|
|
|
|
suffix = [s.glyphSet() for s in self.suffix]
|
2015-12-09 13:58:05 +01:00
|
|
|
builder.add_chain_context_subst(
|
2015-12-14 12:20:57 +01:00
|
|
|
self.location, prefix, glyphs, suffix, self.lookups)
|
2015-12-09 13:58:05 +01:00
|
|
|
|
|
|
|
|
|
|
|
class CursivePosStatement(Statement):
|
2015-12-07 22:48:10 +01:00
|
|
|
def __init__(self, location, glyphclass, entryAnchor, exitAnchor):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.glyphclass = glyphclass
|
|
|
|
self.entryAnchor, self.exitAnchor = entryAnchor, exitAnchor
|
|
|
|
|
2015-12-07 23:56:08 +01:00
|
|
|
def build(self, builder):
|
2015-12-09 12:59:20 +01:00
|
|
|
builder.add_cursive_pos(
|
2015-12-07 23:56:08 +01:00
|
|
|
self.location, self.glyphclass, self.entryAnchor, self.exitAnchor)
|
|
|
|
|
2015-12-07 22:48:10 +01:00
|
|
|
|
2016-01-11 16:00:52 +01:00
|
|
|
class FeatureReferenceStatement(Statement):
|
|
|
|
"""Example: feature salt;"""
|
|
|
|
def __init__(self, location, featureName):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.location, self.featureName = (location, featureName)
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
builder.add_feature_reference(self.location, self.featureName)
|
|
|
|
|
|
|
|
|
2016-02-06 11:13:58 +01:00
|
|
|
class IgnorePosStatement(Statement):
|
|
|
|
def __init__(self, location, chainContexts):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.chainContexts = chainContexts
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
for prefix, glyphs, suffix in self.chainContexts:
|
|
|
|
prefix = [p.glyphSet() for p in prefix]
|
|
|
|
glyphs = [g.glyphSet() for g in glyphs]
|
|
|
|
suffix = [s.glyphSet() for s in suffix]
|
|
|
|
builder.add_chain_context_pos(
|
|
|
|
self.location, prefix, glyphs, suffix, [])
|
|
|
|
|
|
|
|
|
2016-02-05 11:02:29 +01:00
|
|
|
class IgnoreSubstStatement(Statement):
|
|
|
|
def __init__(self, location, chainContexts):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.chainContexts = chainContexts
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
for prefix, glyphs, suffix in self.chainContexts:
|
|
|
|
prefix = [p.glyphSet() for p in prefix]
|
|
|
|
glyphs = [g.glyphSet() for g in glyphs]
|
|
|
|
suffix = [s.glyphSet() for s in suffix]
|
|
|
|
builder.add_chain_context_subst(
|
|
|
|
self.location, prefix, glyphs, suffix, [])
|
|
|
|
|
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
class LanguageStatement(Statement):
|
2015-08-10 16:30:10 +02:00
|
|
|
def __init__(self, location, language, include_default, required):
|
2015-09-04 16:11:53 +02:00
|
|
|
Statement.__init__(self, location)
|
2015-09-07 21:34:10 +02:00
|
|
|
assert(len(language) == 4)
|
2015-08-10 16:30:10 +02:00
|
|
|
self.language = language
|
|
|
|
self.include_default = include_default
|
|
|
|
self.required = required
|
2015-08-10 11:30:47 +02:00
|
|
|
|
2015-09-04 22:29:06 +02:00
|
|
|
def build(self, builder):
|
|
|
|
builder.set_language(location=self.location, language=self.language,
|
2015-09-08 15:55:54 +02:00
|
|
|
include_default=self.include_default,
|
|
|
|
required=self.required)
|
2015-09-04 22:29:06 +02:00
|
|
|
|
2015-08-10 11:30:47 +02:00
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
class LanguageSystemStatement(Statement):
|
2015-08-01 14:49:19 +02:00
|
|
|
def __init__(self, location, script, language):
|
2015-09-04 16:11:53 +02:00
|
|
|
Statement.__init__(self, location)
|
2015-08-01 14:49:19 +02:00
|
|
|
self.script, self.language = (script, language)
|
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
def build(self, builder):
|
|
|
|
builder.add_language_system(self.location, self.script, self.language)
|
|
|
|
|
2015-08-04 11:01:04 +02:00
|
|
|
|
2016-01-11 18:01:47 +01:00
|
|
|
class FontRevisionStatement(Statement):
|
|
|
|
def __init__(self, location, revision):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.revision = revision
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
builder.set_font_revision(self.location, self.revision)
|
|
|
|
|
|
|
|
|
2016-01-07 17:22:31 +01:00
|
|
|
class LigatureCaretByIndexStatement(Statement):
|
|
|
|
def __init__(self, location, glyphs, carets):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.glyphs, self.carets = (glyphs, carets)
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
glyphs = self.glyphs.glyphSet()
|
|
|
|
builder.add_ligatureCaretByIndex_(self.location, glyphs, self.carets)
|
|
|
|
|
|
|
|
|
2016-01-07 16:39:35 +01:00
|
|
|
class LigatureCaretByPosStatement(Statement):
|
|
|
|
def __init__(self, location, glyphs, carets):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.glyphs, self.carets = (glyphs, carets)
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
glyphs = self.glyphs.glyphSet()
|
|
|
|
builder.add_ligatureCaretByPos_(self.location, glyphs, self.carets)
|
|
|
|
|
|
|
|
|
2015-12-09 13:58:05 +01:00
|
|
|
class LigatureSubstStatement(Statement):
|
2016-02-04 15:31:29 +01:00
|
|
|
def __init__(self, location, prefix, glyphs, suffix, replacement,
|
|
|
|
forceChain):
|
2015-09-07 16:10:13 +02:00
|
|
|
Statement.__init__(self, location)
|
2016-01-07 10:31:13 +01:00
|
|
|
self.prefix, self.glyphs, self.suffix = (prefix, glyphs, suffix)
|
2016-02-04 15:31:29 +01:00
|
|
|
self.replacement, self.forceChain = replacement, forceChain
|
2015-09-07 16:10:13 +02:00
|
|
|
|
|
|
|
def build(self, builder):
|
2016-01-07 10:31:13 +01:00
|
|
|
prefix = [p.glyphSet() for p in self.prefix]
|
|
|
|
glyphs = [g.glyphSet() for g in self.glyphs]
|
|
|
|
suffix = [s.glyphSet() for s in self.suffix]
|
|
|
|
builder.add_ligature_subst(
|
2016-02-04 15:31:29 +01:00
|
|
|
self.location, prefix, glyphs, suffix, self.replacement,
|
|
|
|
self.forceChain)
|
2015-09-07 16:10:13 +02:00
|
|
|
|
|
|
|
|
2015-12-10 13:04:16 +01:00
|
|
|
class LookupFlagStatement(Statement):
|
|
|
|
def __init__(self, location, value, markAttachment, markFilteringSet):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.value = value
|
|
|
|
self.markAttachment = markAttachment
|
|
|
|
self.markFilteringSet = markFilteringSet
|
|
|
|
|
|
|
|
def build(self, builder):
|
2015-12-10 19:17:11 +01:00
|
|
|
markAttach = None
|
|
|
|
if self.markAttachment is not None:
|
2015-12-11 16:28:01 +01:00
|
|
|
markAttach = self.markAttachment.glyphSet()
|
2015-12-10 19:17:11 +01:00
|
|
|
markFilter = None
|
|
|
|
if self.markFilteringSet is not None:
|
2015-12-11 16:28:01 +01:00
|
|
|
markFilter = self.markFilteringSet.glyphSet()
|
2015-12-10 19:17:11 +01:00
|
|
|
builder.set_lookup_flag(self.location, self.value,
|
|
|
|
markAttach, markFilter)
|
2015-12-10 13:04:16 +01:00
|
|
|
|
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
class LookupReferenceStatement(Statement):
|
2015-08-11 10:59:26 +02:00
|
|
|
def __init__(self, location, lookup):
|
2015-09-04 16:11:53 +02:00
|
|
|
Statement.__init__(self, location)
|
2015-08-11 10:59:26 +02:00
|
|
|
self.location, self.lookup = (location, lookup)
|
|
|
|
|
2015-09-28 16:49:17 +02:00
|
|
|
def build(self, builder):
|
2016-01-07 08:57:34 +01:00
|
|
|
builder.add_lookup_call(self.lookup.name)
|
2015-09-28 16:49:17 +02:00
|
|
|
|
2015-08-11 10:59:26 +02:00
|
|
|
|
2015-12-09 13:58:05 +01:00
|
|
|
class MarkBasePosStatement(Statement):
|
2015-12-08 19:04:42 +01:00
|
|
|
def __init__(self, location, base, marks):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.base, self.marks = base, marks
|
|
|
|
|
|
|
|
def build(self, builder):
|
2015-12-09 12:59:20 +01:00
|
|
|
builder.add_mark_base_pos(self.location, self.base, self.marks)
|
2015-12-08 19:04:42 +01:00
|
|
|
|
|
|
|
|
2015-12-09 13:58:05 +01:00
|
|
|
class MarkLigPosStatement(Statement):
|
2015-12-09 10:40:49 +01:00
|
|
|
def __init__(self, location, ligatures, marks):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.ligatures, self.marks = ligatures, marks
|
|
|
|
|
|
|
|
def build(self, builder):
|
2015-12-09 16:51:15 +01:00
|
|
|
builder.add_mark_lig_pos(self.location, self.ligatures, self.marks)
|
2015-12-09 10:40:49 +01:00
|
|
|
|
|
|
|
|
2015-12-09 17:14:13 +01:00
|
|
|
class MarkMarkPosStatement(Statement):
|
|
|
|
def __init__(self, location, baseMarks, marks):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.baseMarks, self.marks = baseMarks, marks
|
|
|
|
|
|
|
|
def build(self, builder):
|
2015-12-09 17:56:47 +01:00
|
|
|
builder.add_mark_mark_pos(self.location, self.baseMarks, self.marks)
|
2015-12-09 17:14:13 +01:00
|
|
|
|
|
|
|
|
2015-12-09 13:58:05 +01:00
|
|
|
class MultipleSubstStatement(Statement):
|
2016-01-06 17:33:34 +01:00
|
|
|
def __init__(self, location, prefix, glyph, suffix, replacement):
|
2015-09-08 12:05:44 +02:00
|
|
|
Statement.__init__(self, location)
|
2016-01-06 17:33:34 +01:00
|
|
|
self.prefix, self.glyph, self.suffix = prefix, glyph, suffix
|
|
|
|
self.replacement = replacement
|
2015-09-08 12:05:44 +02:00
|
|
|
|
|
|
|
def build(self, builder):
|
2016-01-06 17:33:34 +01:00
|
|
|
prefix = [p.glyphSet() for p in self.prefix]
|
|
|
|
suffix = [s.glyphSet() for s in self.suffix]
|
|
|
|
builder.add_multiple_subst(
|
|
|
|
self.location, prefix, self.glyph, suffix, self.replacement)
|
2015-09-08 12:05:44 +02:00
|
|
|
|
|
|
|
|
2015-12-09 13:58:05 +01:00
|
|
|
class PairPosStatement(Statement):
|
2015-12-07 17:18:18 +01:00
|
|
|
def __init__(self, location, enumerated,
|
2015-12-14 12:20:57 +01:00
|
|
|
glyphs1, valuerecord1, glyphs2, valuerecord2):
|
2015-12-07 17:18:18 +01:00
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.enumerated = enumerated
|
2015-12-14 12:20:57 +01:00
|
|
|
self.glyphs1, self.valuerecord1 = glyphs1, valuerecord1
|
|
|
|
self.glyphs2, self.valuerecord2 = glyphs2, valuerecord2
|
2015-12-07 17:18:18 +01:00
|
|
|
|
|
|
|
def build(self, builder):
|
2015-12-21 15:16:47 +01:00
|
|
|
if self.enumerated:
|
|
|
|
g = [self.glyphs1.glyphSet(), self.glyphs2.glyphSet()]
|
|
|
|
for glyph1, glyph2 in itertools.product(*g):
|
2015-12-21 16:06:59 +01:00
|
|
|
builder.add_specific_pair_pos(
|
|
|
|
self.location, glyph1, self.valuerecord1,
|
|
|
|
glyph2, self.valuerecord2)
|
|
|
|
return
|
|
|
|
|
|
|
|
is_specific = (isinstance(self.glyphs1, GlyphName) and
|
|
|
|
isinstance(self.glyphs2, GlyphName))
|
|
|
|
if is_specific:
|
|
|
|
builder.add_specific_pair_pos(
|
|
|
|
self.location, self.glyphs1.glyph, self.valuerecord1,
|
|
|
|
self.glyphs2.glyph, self.valuerecord2)
|
2015-12-21 15:16:47 +01:00
|
|
|
else:
|
2015-12-21 16:06:59 +01:00
|
|
|
builder.add_class_pair_pos(
|
|
|
|
self.location, self.glyphs1.glyphSet(), self.valuerecord1,
|
|
|
|
self.glyphs2.glyphSet(), self.valuerecord2)
|
2015-12-07 17:18:18 +01:00
|
|
|
|
|
|
|
|
2015-12-09 13:58:05 +01:00
|
|
|
class ReverseChainSingleSubstStatement(Statement):
|
2015-12-03 13:05:42 +01:00
|
|
|
def __init__(self, location, old_prefix, old_suffix, mapping):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.old_prefix, self.old_suffix = old_prefix, old_suffix
|
|
|
|
self.mapping = mapping
|
|
|
|
|
|
|
|
def build(self, builder):
|
2015-12-14 12:20:57 +01:00
|
|
|
prefix = [p.glyphSet() for p in self.old_prefix]
|
|
|
|
suffix = [s.glyphSet() for s in self.old_suffix]
|
2015-12-09 13:58:05 +01:00
|
|
|
builder.add_reverse_chain_single_subst(
|
2015-12-14 12:20:57 +01:00
|
|
|
self.location, prefix, suffix, self.mapping)
|
2015-12-03 13:05:42 +01:00
|
|
|
|
|
|
|
|
2015-12-09 13:58:05 +01:00
|
|
|
class SingleSubstStatement(Statement):
|
2016-02-04 16:45:05 +01:00
|
|
|
def __init__(self, location, mapping, prefix, suffix, forceChain):
|
2015-09-08 10:33:07 +02:00
|
|
|
Statement.__init__(self, location)
|
2016-01-06 16:15:26 +01:00
|
|
|
self.mapping, self.prefix, self.suffix = mapping, prefix, suffix
|
2016-02-04 16:45:05 +01:00
|
|
|
self.forceChain = forceChain
|
2015-09-08 10:33:07 +02:00
|
|
|
|
|
|
|
def build(self, builder):
|
2016-01-06 16:15:26 +01:00
|
|
|
prefix = [p.glyphSet() for p in self.prefix]
|
|
|
|
suffix = [s.glyphSet() for s in self.suffix]
|
2016-02-04 16:45:05 +01:00
|
|
|
builder.add_single_subst(self.location, prefix, suffix, self.mapping,
|
|
|
|
self.forceChain)
|
2015-09-08 10:33:07 +02:00
|
|
|
|
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
class ScriptStatement(Statement):
|
2015-08-10 16:30:10 +02:00
|
|
|
def __init__(self, location, script):
|
2015-09-04 16:11:53 +02:00
|
|
|
Statement.__init__(self, location)
|
2015-08-10 16:30:10 +02:00
|
|
|
self.script = script
|
|
|
|
|
2015-09-04 22:29:06 +02:00
|
|
|
def build(self, builder):
|
|
|
|
builder.set_script(self.location, self.script)
|
|
|
|
|
2015-08-10 16:30:10 +02:00
|
|
|
|
2015-12-09 13:58:05 +01:00
|
|
|
class SinglePosStatement(Statement):
|
2016-02-09 08:58:18 +01:00
|
|
|
def __init__(self, location, pos, prefix, suffix, forceChain):
|
2015-12-04 11:16:43 +01:00
|
|
|
Statement.__init__(self, location)
|
2016-01-25 12:13:40 +01:00
|
|
|
self.pos, self.prefix, self.suffix = pos, prefix, suffix
|
2016-02-09 08:58:18 +01:00
|
|
|
self.forceChain = forceChain
|
2015-12-04 11:16:43 +01:00
|
|
|
|
|
|
|
def build(self, builder):
|
2016-01-25 15:10:40 +01:00
|
|
|
prefix = [p.glyphSet() for p in self.prefix]
|
|
|
|
suffix = [s.glyphSet() for s in self.suffix]
|
2016-01-25 16:27:18 +01:00
|
|
|
pos = [(g.glyphSet(), value) for g, value in self.pos]
|
2016-02-09 08:58:18 +01:00
|
|
|
builder.add_single_pos(self.location, prefix, suffix,
|
|
|
|
pos, self.forceChain)
|
2015-12-04 11:16:43 +01:00
|
|
|
|
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
class SubtableStatement(Statement):
|
2015-08-11 15:14:47 +02:00
|
|
|
def __init__(self, location):
|
2015-09-04 16:11:53 +02:00
|
|
|
Statement.__init__(self, location)
|
2015-08-11 15:14:47 +02:00
|
|
|
|
|
|
|
|
2015-12-11 14:39:59 +01:00
|
|
|
class ValueRecord(Expression):
|
2015-12-04 15:49:04 +01:00
|
|
|
def __init__(self, location, xPlacement, yPlacement, xAdvance, yAdvance,
|
|
|
|
xPlaDevice, yPlaDevice, xAdvDevice, yAdvDevice):
|
2015-12-11 14:39:59 +01:00
|
|
|
Expression.__init__(self, location)
|
2015-08-04 11:01:04 +02:00
|
|
|
self.xPlacement, self.yPlacement = (xPlacement, yPlacement)
|
|
|
|
self.xAdvance, self.yAdvance = (xAdvance, yAdvance)
|
2015-12-04 15:49:04 +01:00
|
|
|
self.xPlaDevice, self.yPlaDevice = (xPlaDevice, yPlaDevice)
|
|
|
|
self.xAdvDevice, self.yAdvDevice = (xAdvDevice, yAdvDevice)
|
2015-12-04 11:16:43 +01:00
|
|
|
|
|
|
|
def __eq__(self, other):
|
|
|
|
return (self.xPlacement == other.xPlacement and
|
|
|
|
self.yPlacement == other.yPlacement and
|
|
|
|
self.xAdvance == other.xAdvance and
|
|
|
|
self.yAdvance == other.yAdvance and
|
|
|
|
self.xPlaDevice == other.xPlaDevice and
|
|
|
|
self.xAdvDevice == other.xAdvDevice)
|
|
|
|
|
|
|
|
def __ne__(self, other):
|
|
|
|
return not self.__eq__(other)
|
|
|
|
|
|
|
|
def __hash__(self):
|
|
|
|
return (hash(self.xPlacement) ^ hash(self.yPlacement) ^
|
|
|
|
hash(self.xAdvance) ^ hash(self.yAdvance) ^
|
|
|
|
hash(self.xPlaDevice) ^ hash(self.yPlaDevice) ^
|
|
|
|
hash(self.xAdvDevice) ^ hash(self.yAdvDevice))
|
|
|
|
|
|
|
|
def makeString(self, vertical):
|
|
|
|
x, y = self.xPlacement, self.yPlacement
|
|
|
|
xAdvance, yAdvance = self.xAdvance, self.yAdvance
|
|
|
|
xPlaDevice, yPlaDevice = self.xPlaDevice, self.yPlaDevice
|
|
|
|
xAdvDevice, yAdvDevice = self.xAdvDevice, self.yAdvDevice
|
|
|
|
|
|
|
|
# Try format A, if possible.
|
|
|
|
if x == 0 and y == 0:
|
|
|
|
if xAdvance == 0 and vertical:
|
|
|
|
return str(yAdvance)
|
|
|
|
elif yAdvance == 0 and not vertical:
|
|
|
|
return str(xAdvance)
|
|
|
|
|
|
|
|
# Try format B, if possible.
|
2015-12-04 17:10:20 +01:00
|
|
|
if (xPlaDevice is None and yPlaDevice is None and
|
|
|
|
xAdvDevice is None and yAdvDevice is None):
|
2015-12-04 11:16:43 +01:00
|
|
|
return "<%s %s %s %s>" % (x, y, xAdvance, yAdvance)
|
|
|
|
|
|
|
|
# Last resort is format C.
|
2016-04-10 23:06:35 +01:00
|
|
|
return "<%s %s %s %s %s %s %s %s>" % (
|
2015-12-04 11:16:43 +01:00
|
|
|
x, y, xAdvance, yAdvance,
|
2015-12-04 17:10:20 +01:00
|
|
|
deviceToString(xPlaDevice), deviceToString(yPlaDevice),
|
|
|
|
deviceToString(xAdvDevice), deviceToString(yAdvDevice))
|
2015-08-04 11:01:04 +02:00
|
|
|
|
|
|
|
|
2015-09-04 16:11:53 +02:00
|
|
|
class ValueRecordDefinition(Statement):
|
2015-08-04 11:01:04 +02:00
|
|
|
def __init__(self, location, name, value):
|
2015-09-04 16:11:53 +02:00
|
|
|
Statement.__init__(self, location)
|
2015-08-04 11:01:04 +02:00
|
|
|
self.name = name
|
|
|
|
self.value = value
|
2016-03-14 23:44:25 +04:00
|
|
|
|
|
|
|
|
|
|
|
class NameRecord(Statement):
|
|
|
|
def __init__(self, location, nameID, platformID,
|
|
|
|
platEncID, langID, string):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.nameID = nameID
|
|
|
|
self.platformID = platformID
|
|
|
|
self.platEncID = platEncID
|
|
|
|
self.langID = langID
|
|
|
|
self.string = string
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
builder.add_name_record(
|
|
|
|
self.location, self.nameID, self.platformID,
|
|
|
|
self.platEncID, self.langID, self.string)
|
2016-03-18 09:55:51 +04:00
|
|
|
|
|
|
|
class FeatureNameStatement(NameRecord):
|
|
|
|
def build(self, builder):
|
|
|
|
NameRecord.build(self, builder)
|
|
|
|
builder.add_featureName(self.location, self.nameID)
|
2016-03-18 13:18:31 +04:00
|
|
|
|
|
|
|
|
|
|
|
class SizeParameters(Statement):
|
|
|
|
def __init__(self, location, DesignSize, SubfamilyID, RangeStart,
|
|
|
|
RangeEnd):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.DesignSize = DesignSize
|
|
|
|
self.SubfamilyID = SubfamilyID
|
|
|
|
self.RangeStart = RangeStart
|
|
|
|
self.RangeEnd = RangeEnd
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
builder.set_size_parameters(self.location, self.DesignSize,
|
|
|
|
self.SubfamilyID, self.RangeStart, self.RangeEnd)
|
2016-03-19 02:47:04 +04:00
|
|
|
|
|
|
|
|
|
|
|
class BaseAxis(Statement):
|
|
|
|
def __init__(self, location, bases, scripts, vertical):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.bases = bases
|
|
|
|
self.scripts = scripts
|
|
|
|
self.vertical = vertical
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
builder.set_base_axis(self.bases, self.scripts, self.vertical)
|
2016-03-19 22:05:38 +04:00
|
|
|
|
|
|
|
|
|
|
|
class OS2Field(Statement):
|
|
|
|
def __init__(self, location, key, value):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.key = key
|
|
|
|
self.value = value
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
builder.add_os2_field(self.key, self.value)
|
2016-04-09 17:42:38 +02:00
|
|
|
|
|
|
|
|
|
|
|
class HheaField(Statement):
|
|
|
|
def __init__(self, location, key, value):
|
|
|
|
Statement.__init__(self, location)
|
|
|
|
self.key = key
|
|
|
|
self.value = value
|
|
|
|
|
|
|
|
def build(self, builder):
|
|
|
|
builder.add_hhea_field(self.key, self.value)
|