Пример #1
0
def addLookupReferences(
    feature, lookups, script=None, languages=None, exclude_dflt=False
):
    """Add references to named lookups to the feature's statements.
    If `script` (str) and `languages` (sequence of str) are provided,
    only register the lookup for the given script and languages,
    optionally with `exclude_dflt` directive.
    Otherwise add a global reference which will be registered for all
    the scripts and languages in the feature file's `languagesystems`
    statements.
    """
    assert lookups
    if not script:
        for lookup in lookups:
            feature.statements.append(ast.LookupReferenceStatement(lookup))
        return

    feature.statements.append(ast.ScriptStatement(script))
    if exclude_dflt:
        for language in languages or ("dflt",):
            feature.statements.append(
                ast.LanguageStatement(language, include_default=False)
            )
            for lookup in lookups:
                feature.statements.append(ast.LookupReferenceStatement(lookup))
    else:
        feature.statements.append(ast.LanguageStatement("dflt", include_default=True))
        for lookup in lookups:
            feature.statements.append(ast.LookupReferenceStatement(lookup))
        for language in languages or ():
            if language == "dflt":
                continue
            feature.statements.append(
                ast.LanguageStatement(language, include_default=True)
            )
Пример #2
0
def asFeaAST(self, allLanguages=[("DFLT", "dflt")]):
    if set(allLanguages) == set(self.routine.languages):
        if self.routine.usecount == 1:
            return self.routine.asFeaAST(inFeature=True)
        return feaast.LookupReferenceStatement(self.routine.asFeaAST())
    f = feaast.Block()
    lastLang = 'dflt'
    for s,l in self.routine.languages:
        f.statements.append(feaast.ScriptStatement(s))
        if l != lastLang:
            f.statements.append(feaast.LanguageStatement("%4s" % l))
            lastLang = l
        f.statements.append(feaast.LookupReferenceStatement(self.routine.asFeaAST()))
    return f
def asFeaAST(self, expand=False):
    if expand or not self.routine.languages:
        if self.routine.usecount == 1:
            return self.routine.asFeaAST(inFeature=True)
        return feaast.LookupReferenceStatement(self.routine.asFeaAST())
    f = feaast.Block()
    lastLang = 'dflt'
    for s, l in self.routine.languages:
        f.statements.append(feaast.ScriptStatement(s))
        if l != lastLang:
            f.statements.append(feaast.LanguageStatement("%4s" % l))
            lastLang = l
        f.statements.append(
            feaast.LookupReferenceStatement(self.routine.asFeaAST()))
    return f
Пример #4
0
 def parse_script_(self):
     assert self.is_cur_keyword_("script")
     location, script = self.cur_token_location_, self.expect_script_tag_()
     self.expect_symbol_(";")
     return ast.ScriptStatement(location, script)
Пример #5
0
    def _buildFeatureFile(self, tables):
        doc = ast.FeatureFile()
        statements = doc.statements

        if self._glyphclasses:
            statements.append(ast.Comment("# Glyph classes"))
            statements.extend(self._glyphclasses.values())

        if self._markclasses:
            statements.append(ast.Comment("\n# Mark classes"))
            statements.extend(c[1] for c in sorted(self._markclasses.items()))

        if self._lookups:
            statements.append(ast.Comment("\n# Lookups"))
            for lookup in self._lookups.values():
                statements.extend(getattr(lookup, "targets", []))
                statements.append(lookup)

        # Prune features
        features = self._features.copy()
        for ftag in features:
            scripts = features[ftag]
            for stag in scripts:
                langs = scripts[stag]
                for ltag in langs:
                    langs[ltag] = [
                        l for l in langs[ltag] if l.lower() in self._lookups
                    ]
                scripts[stag] = {t: l for t, l in langs.items() if l}
            features[ftag] = {t: s for t, s in scripts.items() if s}
        features = {t: f for t, f in features.items() if f}

        if features:
            statements.append(ast.Comment("# Features"))
            for ftag, scripts in features.items():
                feature = ast.FeatureBlock(ftag)
                stags = sorted(scripts, key=lambda k: 0 if k == "DFLT" else 1)
                for stag in stags:
                    feature.statements.append(ast.ScriptStatement(stag))
                    ltags = sorted(scripts[stag],
                                   key=lambda k: 0 if k == "dflt" else 1)
                    for ltag in ltags:
                        include_default = True if ltag == "dflt" else False
                        feature.statements.append(
                            ast.LanguageStatement(
                                ltag, include_default=include_default))
                        for name in scripts[stag][ltag]:
                            lookup = self._lookups[name.lower()]
                            lookupref = ast.LookupReferenceStatement(lookup)
                            feature.statements.append(lookupref)
                statements.append(feature)

        if self._gdef and "GDEF" in tables:
            classes = []
            for name in ("BASE", "MARK", "LIGATURE", "COMPONENT"):
                if name in self._gdef:
                    classname = "GDEF_" + name.lower()
                    glyphclass = ast.GlyphClassDefinition(
                        classname, self._gdef[name])
                    statements.append(glyphclass)
                    classes.append(ast.GlyphClassName(glyphclass))
                else:
                    classes.append(None)

            gdef = ast.TableBlock("GDEF")
            gdef.statements.append(ast.GlyphClassDefStatement(*classes))
            statements.append(gdef)

        return doc
Пример #6
0
def asFeaAST(self, do_gdef=True):
    """Returns this font's features as a feaLib AST object, for later
    translation to AFDKO code."""
    from fontFeatures import Routine, Chaining
    ff = feaast.FeatureFile()

    add_language_system_statements(self, ff)

    if do_gdef:
        add_gdef(self, ff)

    # In OpenType, we need to rearrange the routines such that all rules for
    # a given languagesystem, lookup type, and lookup flags, appear in the
    # same lookup. Also, lookups with the same languagesystem need to appear next
    # to one another, because FEA syntax is stupid.

    # Now arrange them by type/etc.
    for k, v in self.features.items():
        for reference in v:
            routine = reference.routine
            # If a rule has >1 language it must first be split
            newrules = []
            for r in routine.rules:
                if len(r.languages or []) > 1:
                    for language in r.languages:
                        newrule = copy.copy(r)
                        newrule.languages = [language]
                        newrules.append(newrule)
                else:
                    newrules.append(r)
            routine.rules = newrules
            partitioned = self.partitionRoutine(
                routine, lambda rule: tuple([
                    tuple(rule.languages or []),
                    type(rule),
                    lookup_type(rule)
                ]))
            if routine.name and partitioned and len(partitioned) > 1:
                for p in partitioned:
                    rule = p.rules[0]
                    language = (rule.languages or [("DFLT", "dflt")])[0]
                    p.name = p.name + "%s_%s_%s_%i" % (
                        language[0].strip(), language[1].strip(),
                        type(rule).__name__, lookup_type(rule))

    for r in self.routines:
        r.usecount = 0
        # Bubble up flags and languages
        if r.rules and not r.flags:
            r.flags = r.rules[0].flags
        if r.rules and not r.languages:
            r.languages = r.rules[0].languages

    for k, v in self.features.items():
        # Similarly split routines with multiple languages
        references = []
        for reference in v:
            routine = reference.routine
            if len(routine.languages or []) > 1:
                splitroutines = []
                for language in routine.languages:
                    # This is wrong. It should really be a new reference to the
                    # same routine. But this will do for now.
                    newreference = copy.copy(reference)
                    newreference.languages = [language]
                    references.append(newreference)
            else:
                references.append(reference)
                reference.languages = routine.languages
        self.features[k] = references
        # Order the arranged routines by language
        # new_references = list(sorted(v, key=lambda x: tuple(x.routine.languages or [])))

    # Next, we'll ensure that all chaining lookups are resolved and in the right order
    newRoutines = [self.routines[i] for i in reorderAndResolve(self)]

    # Preamble
    for k in newRoutines:
        assert isinstance(k, Routine)
        if not k.name and k.usecount != 1:
            k.name = self.gensym("Routine_")
        pre = k.feaPreamble(self)
        if k.rules:
            ff.statements.extend(pre)

    for k, v in self.namedClasses.items():
        asclass = _to_inline_class(v)
        ff.statements.append(feaast.GlyphClassDefinition(k, asclass))

    ff.statements.append(feaast.Comment(""))

    for k in newRoutines:
        if k.rules:
            ff.statements.append(k.asFeaAST())

    for k, v in self.features.items():
        for routine in v:
            # Putting each routine in its own feature saves problems...
            lang = routine.languages
            f = feaast.FeatureBlock(k)
            if lang:
                f.statements.append(feaast.ScriptStatement(lang[0][0]))
                f.statements.append(
                    feaast.LanguageStatement("%4s" % lang[0][1]))
            f.statements.append(routine.asFeaAST(expand=k == "aalt"))
            ff.statements.append(f)
    return ff