aboutsummaryrefslogtreecommitdiff
path: root/Lib/fontTools/feaLib/ast.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/fontTools/feaLib/ast.py')
-rw-r--r--Lib/fontTools/feaLib/ast.py172
1 files changed, 161 insertions, 11 deletions
diff --git a/Lib/fontTools/feaLib/ast.py b/Lib/fontTools/feaLib/ast.py
index 6c2bfce8..763d0d2c 100644
--- a/Lib/fontTools/feaLib/ast.py
+++ b/Lib/fontTools/feaLib/ast.py
@@ -1,4 +1,4 @@
-from fontTools.misc.py23 import *
+from fontTools.misc.py23 import byteord, tobytes
from fontTools.feaLib.error import FeatureLibError
from fontTools.feaLib.location import FeatureLibLocation
from fontTools.misc.encodingTools import getEncoding
@@ -28,12 +28,15 @@ __all__ = [
"Anchor",
"AnchorDefinition",
"AttachStatement",
+ "AxisValueLocationStatement",
"BaseAxis",
"CVParametersNameStatement",
"ChainContextPosStatement",
"ChainContextSubstStatement",
"CharacterStatement",
"CursivePosStatement",
+ "ElidedFallbackName",
+ "ElidedFallbackNameID",
"Expression",
"FeatureNameStatement",
"FeatureReferenceStatement",
@@ -62,6 +65,9 @@ __all__ = [
"SingleSubstStatement",
"SizeParameters",
"Statement",
+ "STATAxisValueStatement",
+ "STATDesignAxisStatement",
+ "STATNameStatement",
"SubtableStatement",
"TableBlock",
"ValueRecord",
@@ -252,7 +258,7 @@ class GlyphClass(Expression):
def add_range(self, start, end, glyphs):
"""Add a range (e.g. ``A-Z``) to the class. ``start`` and ``end``
- are either :class:`GlyphName` objects or strings representing the
+ are either :class:`GlyphName` objects or strings representing the
start and end glyphs in the class, and ``glyphs`` is the full list of
:class:`GlyphName` objects in the range."""
if self.curr < len(self.glyphs):
@@ -547,7 +553,7 @@ class MarkClass(object):
class MarkClassDefinition(Statement):
- """A single ``markClass`` statement. The ``markClass`` should be a
+ """A single ``markClass`` statement. The ``markClass`` should be a
:class:`MarkClass` object, the ``anchor`` an :class:`Anchor` object,
and the ``glyphs`` parameter should be a `glyph-containing object`_ .
@@ -849,7 +855,7 @@ class IgnorePosStatement(Statement):
"""An ``ignore pos`` statement, containing `one or more` contexts to ignore.
``chainContexts`` should be a list of ``(prefix, glyphs, suffix)`` tuples,
- with each of ``prefix``, ``glyphs`` and ``suffix`` being
+ with each of ``prefix``, ``glyphs`` and ``suffix`` being
`glyph-containing objects`_ ."""
def __init__(self, chainContexts, location=None):
@@ -1146,7 +1152,7 @@ class MarkBasePosStatement(Statement):
def asFea(self, indent=""):
res = "pos base {}".format(self.base.asFea())
for a, m in self.marks:
- res += " {} mark @{}".format(a.asFea(), m.name)
+ res += "\n" + indent + SHIFT + "{} mark @{}".format(a.asFea(), m.name)
res += ";"
return res
@@ -1165,7 +1171,7 @@ class MarkLigPosStatement(Statement):
# ... add definitions to mark classes...
glyph = GlyphName("lam_meem_jeem")
- marks = [
+ marks = [
[ (Anchor(625,1800), m1) ], # Attachments on 1st component (lam)
[ (Anchor(376,-378), m2) ], # Attachments on 2nd component (meem)
[ ] # No attachments on the jeem
@@ -1192,10 +1198,15 @@ class MarkLigPosStatement(Statement):
for l in self.marks:
temp = ""
if l is None or not len(l):
- temp = " <anchor NULL>"
+ temp = "\n" + indent + SHIFT * 2 + "<anchor NULL>"
else:
for a, m in l:
- temp += " {} mark @{}".format(a.asFea(), m.name)
+ temp += (
+ "\n"
+ + indent
+ + SHIFT * 2
+ + "{} mark @{}".format(a.asFea(), m.name)
+ )
ligs.append(temp)
res += ("\n" + indent + SHIFT + "ligComponent").join(ligs)
res += ";"
@@ -1218,7 +1229,7 @@ class MarkMarkPosStatement(Statement):
def asFea(self, indent=""):
res = "pos mark {}".format(self.baseMarks.asFea())
for a, m in self.marks:
- res += " {} mark @{}".format(a.asFea(), m.name)
+ res += "\n" + indent + SHIFT + "{} mark @{}".format(a.asFea(), m.name)
res += ";"
return res
@@ -1261,7 +1272,7 @@ class MultipleSubstStatement(Statement):
res += " " + " ".join(map(asFea, self.suffix))
else:
res += asFea(self.glyph)
- replacement = self.replacement or [ NullGlyph() ]
+ replacement = self.replacement or [NullGlyph()]
res += " by "
res += " ".join(map(asFea, replacement))
res += ";"
@@ -1657,7 +1668,7 @@ class NameRecord(Statement):
def escape(c, escape_pattern):
# Also escape U+0022 QUOTATION MARK and U+005C REVERSE SOLIDUS
if c >= 0x20 and c <= 0x7E and c not in (0x22, 0x5C):
- return unichr(c)
+ return chr(c)
else:
return escape_pattern % c
@@ -1699,6 +1710,16 @@ class FeatureNameStatement(NameRecord):
return '{} {}"{}";'.format(tag, plat, self.string)
+class STATNameStatement(NameRecord):
+ """Represents a STAT table ``name`` statement."""
+
+ def asFea(self, indent=""):
+ plat = simplify_name_attributes(self.platformID, self.platEncID, self.langID)
+ if plat != "":
+ plat += " "
+ return 'name {}"{}";'.format(plat, self.string)
+
+
class SizeParameters(Statement):
"""A ``parameters`` statement."""
@@ -1877,3 +1898,132 @@ class VheaField(Statement):
fields = ("VertTypoAscender", "VertTypoDescender", "VertTypoLineGap")
keywords = dict([(x.lower(), x) for x in fields])
return "{} {};".format(keywords[self.key], self.value)
+
+
+class STATDesignAxisStatement(Statement):
+ """A STAT table Design Axis
+
+ Args:
+ tag (str): a 4 letter axis tag
+ axisOrder (int): an int
+ names (list): a list of :class:`STATNameStatement` objects
+ """
+
+ def __init__(self, tag, axisOrder, names, location=None):
+ Statement.__init__(self, location)
+ self.tag = tag
+ self.axisOrder = axisOrder
+ self.names = names
+ self.location = location
+
+ def build(self, builder):
+ builder.addDesignAxis(self, self.location)
+
+ def asFea(self, indent=""):
+ indent += SHIFT
+ res = f"DesignAxis {self.tag} {self.axisOrder} {{ \n"
+ res += ("\n" + indent).join([s.asFea(indent=indent) for s in self.names]) + "\n"
+ res += "};"
+ return res
+
+
+class ElidedFallbackName(Statement):
+ """STAT table ElidedFallbackName
+
+ Args:
+ names: a list of :class:`STATNameStatement` objects
+ """
+
+ def __init__(self, names, location=None):
+ Statement.__init__(self, location)
+ self.names = names
+ self.location = location
+
+ def build(self, builder):
+ builder.setElidedFallbackName(self.names, self.location)
+
+ def asFea(self, indent=""):
+ indent += SHIFT
+ res = "ElidedFallbackName { \n"
+ res += ("\n" + indent).join([s.asFea(indent=indent) for s in self.names]) + "\n"
+ res += "};"
+ return res
+
+
+class ElidedFallbackNameID(Statement):
+ """STAT table ElidedFallbackNameID
+
+ Args:
+ value: an int pointing to an existing name table name ID
+ """
+
+ def __init__(self, value, location=None):
+ Statement.__init__(self, location)
+ self.value = value
+ self.location = location
+
+ def build(self, builder):
+ builder.setElidedFallbackName(self.value, self.location)
+
+ def asFea(self, indent=""):
+ return f"ElidedFallbackNameID {self.value};"
+
+
+class STATAxisValueStatement(Statement):
+ """A STAT table Axis Value Record
+
+ Args:
+ names (list): a list of :class:`STATNameStatement` objects
+ locations (list): a list of :class:`AxisValueLocationStatement` objects
+ flags (int): an int
+ """
+
+ def __init__(self, names, locations, flags, location=None):
+ Statement.__init__(self, location)
+ self.names = names
+ self.locations = locations
+ self.flags = flags
+
+ def build(self, builder):
+ builder.addAxisValueRecord(self, self.location)
+
+ def asFea(self, indent=""):
+ res = "AxisValue {\n"
+ for location in self.locations:
+ res += location.asFea()
+
+ for nameRecord in self.names:
+ res += nameRecord.asFea()
+ res += "\n"
+
+ if self.flags:
+ flags = ["OlderSiblingFontAttribute", "ElidableAxisValueName"]
+ flagStrings = []
+ curr = 1
+ for i in range(len(flags)):
+ if self.flags & curr != 0:
+ flagStrings.append(flags[i])
+ curr = curr << 1
+ res += f"flag {' '.join(flagStrings)};\n"
+ res += "};"
+ return res
+
+
+class AxisValueLocationStatement(Statement):
+ """
+ A STAT table Axis Value Location
+
+ Args:
+ tag (str): a 4 letter axis tag
+ values (list): a list of ints and/or floats
+ """
+
+ def __init__(self, tag, values, location=None):
+ Statement.__init__(self, location)
+ self.tag = tag
+ self.values = values
+
+ def asFea(self, res=""):
+ res += f"location {self.tag} "
+ res += f"{' '.join(str(i) for i in self.values)};\n"
+ return res