File: Chaining.py

package info (click to toggle)
python-fontfeatures 1.9.0%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 2,096 kB
  • sloc: python: 9,112; makefile: 22
file content (91 lines) | stat: -rw-r--r-- 2,730 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# Code for converting a Chaining object into feaLib statements
import fontTools.feaLib.ast as feaast


# Can we chain multiple lookups?


def glyphref(g):
    if len(g) == 1:
        return feaast.GlyphName(g[0])
    return feaast.GlyphClass([feaast.GlyphName(x) for x in g])


def gensym(ff):
    if "index" not in ff.scratch:
        ff.scratch["index"] = 0
    ff.scratch["index"] = ff.scratch["index"] + 1
    return str(ff.scratch["index"])


def replaceLongWithClasses(i, ff):
    for ix, gc in enumerate(i):
        if len(gc) > 5:
            classname = ff.getNamedClassFor(sorted(gc), "class" + gensym(ff))
            i[ix] = ["@" + classname]


def feaPreamble(self, ff):
    if "glyphclasses" not in ff.scratch:
        ff.scratch["glyphclasses"] = {
            tuple(sorted(ff.namedClasses[g])): g for g in ff.namedClasses.keys()
        }
    replaceLongWithClasses(self.input, ff)
    replaceLongWithClasses(self.precontext, ff)
    replaceLongWithClasses(self.postcontext, ff)
    from fontFeatures import RoutineReference

    # Ensure all linked routines have names
    for lul in self.lookups:
        for r in lul or []:
            assert isinstance(r, RoutineReference)
            assert r.routine
            if not r.routine.name:
                r.routine.name = "ChainedRoutine" + gensym(ff)
            if not r.name:
                r.name = r.routine.name

    return []


def _complex(self):
    if self.stage == "sub":
        routine = feaast.ChainContextSubstStatement
    else:
        routine = feaast.ChainContextPosStatement

    return routine(
        [glyphref(x) for x in self.precontext],
        [glyphref(x) for x in self.input],
        [glyphref(x) for x in self.postcontext],
        self.lookups,
    )


def asFeaAST(self):
    if len(self.lookups) > 0 and any([x is not None for x in self.lookups]):
        # Fill in the blanks
        if self.stage == "sub":
            routine = feaast.ChainContextSubstStatement
        else:
            routine = feaast.ChainContextPosStatement
        # Check for >1 lookups per position
        if any([x and len(x) > 1 for x in self.lookups]):
            return _complex(self)
        lookups = self.lookups
        return routine(
            [glyphref(x) for x in self.precontext],
            [glyphref(x) for x in self.input],
            [glyphref(x) for x in self.postcontext],
            lookups,
        )
    else:
        return feaast.IgnoreSubstStatement(
            chainContexts=[
                [
                    [glyphref(x) for x in self.precontext],
                    [glyphref(x) for x in self.input],
                    [glyphref(x) for x in self.postcontext],
                ]
            ]
        )