Exemplo n.º 1
0
    def __init__(self,
                 featurefile,
                 font=None,
                 glyphNames=None,
                 includeDir=None):

        self.ff = fontFeatures.FontFeatures()
        self.markclasses = {}
        self.currentFeature = None
        self.currentRoutine = None
        self.gensym = 1
        self.glyphmap = ()
        self.currentLanguage = None
        if font and not glyphNames:
            glyphNames = font.getGlyphOrder()
        if isinstance(featurefile, str):
            featurefile = io.StringIO(featurefile)
        self.featurefile = featurefile
        if glyphNames:
            self.parser = Parser(self.featurefile,
                                 glyphNames=glyphNames,
                                 includeDir=includeDir)
        else:
            self.parser = Parser(self.featurefile, includeDir=includeDir)
        self.parser.ast.ValueRecord = fontFeatures.ValueRecord
Exemplo n.º 2
0
def parseLayoutFeatures(font):
    """Parse OpenType layout features in the UFO and return a
    feaLib.ast.FeatureFile instance.
    """
    featxt = font.features.text or ""
    if not featxt:
        return ast.FeatureFile()
    buf = StringIO(featxt)
    ufoPath = font.path
    includeDir = None
    if ufoPath is not None:
        # The UFO v3 specification says "Any include() statements must be relative to
        # the UFO path, not to the features.fea file itself". We set the `name`
        # attribute on the buffer to the actual feature file path, which feaLib will
        # pick up and use to attribute errors to the correct file, and explicitly set
        # the include directory to the parent of the UFO.
        ufoPath = os.path.normpath(ufoPath)
        buf.name = os.path.join(ufoPath, "features.fea")
        includeDir = os.path.dirname(ufoPath)
    glyphNames = set(font.keys())
    try:
        parser = Parser(buf, glyphNames, includeDir=includeDir)
        doc = parser.parse()
    except IncludedFeaNotFound as e:
        if ufoPath and os.path.exists(os.path.join(ufoPath, e.args[0])):
            logger.warning("Please change the file name in the include(...); "
                           "statement to be relative to the UFO itself, "
                           "instead of relative to the 'features.fea' file "
                           "contained in it.")
        raise
    return doc
Exemplo n.º 3
0
def parseLayoutFeatures(font):
    """ Parse OpenType layout features in the UFO and return a
    feaLib.ast.FeatureFile instance.
    """
    featxt = tounicode(font.features.text or "", "utf-8")
    if not featxt:
        return ast.FeatureFile()
    buf = UnicodeIO(featxt)
    # the path is used by the lexer to resolve 'include' statements
    # and print filename in error messages. For the UFO spec, this
    # should be the path of the UFO, not the inner features.fea:
    # https://github.com/unified-font-object/ufo-spec/issues/55
    ufoPath = font.path
    if ufoPath is not None:
        buf.name = ufoPath
    glyphNames = set(font.keys())
    try:
        parser = Parser(buf, glyphNames)
        doc = parser.parse()
    except IncludedFeaNotFound as e:
        if ufoPath and os.path.exists(os.path.join(ufoPath, e.args[0])):
            logger.warning("Please change the file name in the include(...); "
                           "statement to be relative to the UFO itself, "
                           "instead of relative to the 'features.fea' file "
                           "contained in it.")
        raise
    return doc
Exemplo n.º 4
0
 def parse(self, text):
     if not self.tempdir:
         self.tempdir = tempfile.mkdtemp()
     self.num_tempfiles += 1
     path = os.path.join(self.tempdir, "tmp%d.fea" % self.num_tempfiles)
     with codecs.open(path, "wb", "utf-8") as outfile:
         outfile.write(text)
     return Parser(path).parse()
Exemplo n.º 5
0
def parseFea(text):
    from fontTools.feaLib.parser import Parser

    if isinstance(text, ast.FeatureFile):
        return text
    f = StringIO(text)
    fea = Parser(f).parse()
    return fea
Exemplo n.º 6
0
 def check_fea2fea_file(self, name):
     f = self.getpath("{}.fea".format(name))
     p = Parser(f)
     doc = p.parse()
     tlines = self.normal_fea(doc.asFea().split("\n"))
     with open(f, "r", encoding="utf-8") as ofile:
         olines = self.normal_fea(ofile.readlines())
     if olines != tlines:
         for line in difflib.unified_diff(olines, tlines):
             sys.stdout.write(line)
         self.fail("Fea2Fea output is different from expected")
Exemplo n.º 7
0
def parse(features):
    names = set()
    featurefile = UnicodeIO(tounicode(features))
    fea = Parser(featurefile, []).parse()
    for statement in fea.statements:
        if getattr(statement, "name", None) in ("isol", "ccmp"):
            for substatement in statement.statements:
                if hasattr(substatement, "glyphs"):
                    # Single
                    names.update(substatement.glyphs[0].glyphSet())
                elif hasattr(substatement, "glyph"):
                    # Multiple
                    names.add(substatement.glyph)

    return names
Exemplo n.º 8
0
    def __init__(self, featurefile, font=None):

        self.ff = fontFeatures.FontFeatures()
        self.markclasses = {}
        self.currentFeature = None
        self.currentRoutine = None
        self.gensym = 1
        self.glyphmap = ()
        self.currentLanguage = None
        if font:
            self.glyphmap = font.getReverseGlyphMap()
        if isinstance(featurefile, str):
            featurefile = io.StringIO(featurefile)
        self.featurefile = featurefile
        self.parser = Parser(self.featurefile, self.glyphmap)
        self.parser.ast.ValueRecord = fontFeatures.ValueRecord
Exemplo n.º 9
0
 def build(self):
     self.parseTree = Parser(self.featurefile_path).parse()
     self.parseTree.build(self)
     for tag in ('GPOS', 'GSUB'):
         table = self.makeTable(tag)
         if (table.ScriptList.ScriptCount > 0
                 or table.FeatureList.FeatureCount > 0
                 or table.LookupList.LookupCount > 0):
             fontTable = self.font[tag] = getTableClass(tag)()
             fontTable.table = table
         elif tag in self.font:
             del self.font[tag]
     gdef = self.makeGDEF()
     if gdef:
         self.font["GDEF"] = gdef
     elif "GDEF" in self.font:
         del self.font["GDEF"]
Exemplo n.º 10
0
    def __init__(self, featurefile, font=None):
        from fontTools.feaLib.parser import Parser

        self.ff = fontFeatures.FontFeatures()
        self.markclasses = {}
        self.currentFeature = None
        self.currentRoutine = None
        self.gensym = 1
        self.language_systems = []
        glyphmap = ()
        if font:
            glyphmap = font.getReverseGlyphMap()
        if isinstance(featurefile, str):
            featurefile = io.StringIO(featurefile)
        parsetree = Parser(featurefile, glyphmap).parse()
        self.features_ = {}
        parsetree.build(self)
Exemplo n.º 11
0
 def test_build_pre_parsed_ast_featurefile(self):
     f = StringIO("feature liga {sub f i by f_i;} liga;")
     tree = Parser(f).parse()
     font = makeTTFont()
     addOpenTypeFeatures(font, tree)
     assert "GSUB" in font
Exemplo n.º 12
0
 def test_substitute_lookups(self):
     doc = Parser(self.getpath("spec5fi1.fea")).parse()
     [langsys, ligs, sub, feature] = doc.statements
     self.assertEqual(feature.statements[0].lookups, [ligs, None, sub])
     self.assertEqual(feature.statements[1].lookups, [ligs, None, sub])
Exemplo n.º 13
0
reMarkClass = re.compile(r"markClass.*;")
markClassDefinitions = reMarkClass.findall(
    markFeatures)  # Save all the markClass definitions

# Read the input feature file
with open(in_path, "r") as input_fea:
    # Replace $markClasses with the generated markClassDefinitions
    if markClassDefinitions != []:
        features = input_fea.read().replace(
            "$markClasses", "\n".join(markClassDefinitions))
    else:
        features = input_fea.read().replace("$markClasses", "")

    if stylename:
        # Replace the matra I style-based include path for each style
        print("Replacing $stylename with '%s' if found in feature file" %
              stylename)
        features = features.replace("$stylename", stylename)

    # Write to a temporary file, which we can parse and expand all includes
    with open("production/features/tmp.fea", "w") as tmp:
        tmp.write(features)

parser = Parser("production/features/tmp.fea")
parsed = parser.parse()
os.remove("production/features/tmp.fea")

# Write the parsed and substituted features to the UFO features
with open(out_path + "/features.fea", "w") as fea:
    fea.write(str(parsed))
Exemplo n.º 14
0
 def build(self):
     parsetree = Parser(self.featurefile_path).parse()
     parsetree.build(self)
     for tag in ('GPOS', 'GSUB'):
         fontTable = self.font[tag] = getTableClass(tag)()
         fontTable.table = self.makeTable(tag)