summaryrefslogtreecommitdiffstats
path: root/src/silfont/scripts/psfbuildfea.py
blob: f65931581f0b4ed995b0392fb2ea20f086a8eade (plain)
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
#!/usr/bin/env python3
__doc__ = 'Build features.fea file into a ttf font'
# TODO: add conditional compilation, compare to fea, compile to ttf
__url__ = 'https://github.com/silnrsi/pysilfont'
__copyright__ = 'Copyright (c) 2017 SIL International  (https://www.sil.org)'
__license__ = 'Released under the MIT License (https://opensource.org/licenses/MIT)'
__author__ = 'Martin Hosken'

from fontTools.feaLib.builder import Builder
from fontTools import configLogger
from fontTools.ttLib import TTFont
from fontTools.ttLib.tables.otTables import lookupTypes
from fontTools.feaLib.lookupDebugInfo import LookupDebugInfo

from silfont.core import execute

class MyBuilder(Builder):

    def __init__(self, font, featurefile, lateSortLookups=False, fronts=None):
        super(MyBuilder, self).__init__(font, featurefile)
        self.lateSortLookups = lateSortLookups
        self.fronts = fronts if fronts is not None else []

    def buildLookups_(self, tag):
        assert tag in ('GPOS', 'GSUB'), tag
        countFeatureLookups = 0
        fronts = set([l for k, l in self.named_lookups_.items() if k in self.fronts])
        for bldr in self.lookups_:
            bldr.lookup_index = None
            if bldr.table == tag and getattr(bldr, '_feature', "") != "":
                countFeatureLookups += 1
        lookups = []
        latelookups = []
        for bldr in self.lookups_:
            if bldr.table != tag:
                continue
            if self.lateSortLookups and getattr(bldr, '_feature', "") == "":
                if bldr in fronts:
                    latelookups.insert(0, bldr)
                else:
                    latelookups.append(bldr)
            else:
                bldr.lookup_index = len(lookups)
                lookups.append(bldr)
                bldr.map_index = bldr.lookup_index
        numl = len(lookups)
        for i, l in enumerate(latelookups):
            l.lookup_index = numl + i
            l.map_index = l.lookup_index
        for l in lookups + latelookups:
            self.lookup_locations[tag][str(l.lookup_index)] = LookupDebugInfo(
                    location=str(l.location),
                    name=self.get_lookup_name_(l),
                    feature=None)
        return [b.build() for b in lookups + latelookups]

    def add_lookup_to_feature_(self, lookup, feature_name):
        super(MyBuilder, self).add_lookup_to_feature_(lookup, feature_name)
        lookup._feature = feature_name


#TODO: provide more argument info
argspec = [
    ('input_fea', {'help': 'Input fea file'}, {}),
    ('input_font', {'help': 'Input font file'}, {}),
    ('-o', '--output', {'help': 'Output font file'}, {}),
    ('-v', '--verbose', {'help': 'Repeat to increase verbosity', 'action': 'count', 'default': 0}, {}),
    ('-m', '--lookupmap', {'help': 'File into which place lookup map'}, {}),
    ('-l','--log',{'help': 'Optional log file'}, {'type': 'outfile', 'def': '_buildfea.log', 'optlog': True}),
    ('-e','--end',{'help': 'Push lookups not in features to the end', 'action': 'store_true'}, {}),
    ('-F','--front',{'help': 'Pull named lookups to the front of unnamed list', 'action': 'append'}, {}),
]

def doit(args) :
    levels = ["WARNING", "INFO", "DEBUG"]
    configLogger(level=levels[min(len(levels) - 1, args.verbose)])

    font = TTFont(args.input_font)
    builder = MyBuilder(font, args.input_fea, lateSortLookups=args.end, fronts=args.front)
    builder.build()
    if args.lookupmap:
        with open(args.lookupmap, "w") as outf:
            for n, l in sorted(builder.named_lookups_.items()):
                if l is not None:
                    outf.write("{},{},{}\n".format(n, l.table, l.map_index))
    font.save(args.output)

def cmd(): execute(None, doit, argspec)
if __name__ == '__main__': cmd()