This repository has been archived on 2025-10-02. You can view files and clone it, but you cannot make any changes to it's state, such as pushing and creating new issues, pull requests or comments.
inter-font/misc/pylib/robofab/tools/otFeatures.py
Rasmus Andersson 8234b62ab7 Speeds up font compilation by around 200%
Cython is used to compile some hot paths into native Python extensions.
These hot paths were identified through running ufocompile with the hotshot
profiler and then converting file by file to Cython, starting with the "hottest"
paths and continuing until returns were deminishing. This means that only a few
Python files were converted to Cython.

Closes #23
Closes #20 (really this time)
2017-09-04 11:12:34 -04:00

190 lines
4.5 KiB
Python
Executable file

"""Simple module to write features to font"""
import string
from types import StringType, ListType, TupleType
from robofab.world import world
if world.inFontLab:
from FL import *
from fl_cmd import *
from robofab.tools.toolsFL import FontIndex
#feat = []
#feat.append('feature smcp {')
#feat.append('\tlookup SMALLCAPS {')
#feat.append('\t\tsub @LETTERS_LC by @LETTERS_LC;')
#feat.append('\t} SMALLCAPS;')
#feat.append('} smcp;')
class FeatureWriter:
"""Make properly formatted feature code"""
def __init__(self, type):
self.type = type
self.data = []
def add(self, src, dst):
"""Add a substitution: change src to dst."""
self.data.append((src, dst))
def write(self, group=0):
"""Write the whole thing to string"""
t = []
if len(self.data) == 0:
return None
t.append('feature %s {' % self.type)
for src, dst in self.data:
if isinstance(src, (list, tuple)):
if group:
src = "[%s]" % string.join(src, ' ')
else:
src = string.join(src, ' ')
if isinstance(dst, (list, tuple)):
if group:
dst = "[%s]" % string.join(dst, ' ')
else:
dst = string.join(dst, ' ')
src = string.strip(src)
dst = string.strip(dst)
t.append("\tsub %s by %s;" % (src, dst))
t.append('}%s;' % self.type)
return string.join(t, '\n')
class GlyphName:
"""Simple class that splits a glyphname in handy parts,
access the parts as attributes of the name."""
def __init__(self, name):
self.suffix = []
self.ligs = []
self.name = self.base = name
if '.' in name:
self.bits = name.split('.')
self.base = self.bits[0]
self.suffix = self.bits[1:]
if '_' in name:
self.ligs = self.base.split('_')
def GetAlternates(font, flavor="alt", match=0):
"""Sort the glyphs of this font by the parts of the name.
flavor is the bit to look for, i.e. 'alt' in a.alt
match = 1 if you want a exact match: alt1 != alt
match = 0 if the flavor is a partial match: alt == alt1
"""
names = {}
for c in font.glyphs:
name = GlyphName(c.name)
if not names.has_key(name.base):
names[name.base] = []
if match:
# only include if there is an exact match
if flavor in name.suffix:
names[name.base].append(c.name)
else:
# include if there is a partial match
for a in name.suffix:
if a.find(flavor) != -1:
names[name.base].append(c.name)
return names
# XXX there should be a more generic glyph finder.
def MakeCapsFeature(font):
"""Build a feature for smallcaps based on .sc glyphnames"""
names = GetAlternates(font, 'sc', match=1)
fw = FeatureWriter('smcp')
k = names.keys()
k.sort()
for p in k:
if names[p]:
fw.add(p, names[p])
feat = fw.write()
if feat:
font.features.append(Feature('smcp', feat))
return feat
def MakeAlternatesFeature(font):
"""Build a aalt feature based on glyphnames"""
names = GetAlternates(font, 'alt', match=0)
fw = FeatureWriter('aalt')
k = names.keys()
k.sort()
for p in k:
if names[p]:
fw.add(p, names[p])
feat = fw.write(group=1)
if feat:
font.features.append(Feature('aalt', feat))
return feat
def MakeSwashFeature(font):
"""Build a swash feature based on glyphnames"""
names = GetAlternates(font, 'swash', match=0)
fw = FeatureWriter('swsh')
k=names.keys()
k.sort()
for p in k:
if names[p]:
l=names[p]
l.sort()
fw.add(p, l[0])
feat=fw.write()
if feat:
font.features.append(Feature('swsh', feat))
return feat
def MakeLigaturesFeature(font):
"""Build a liga feature based on glyphnames"""
from robofab.gString import ligatures
ligCountDict = {}
for glyph in font.glyphs:
if glyph.name in ligatures:
if len(glyph.name) not in ligCountDict.keys():
ligCountDict[len(glyph.name)] = [glyph.name]
else:
ligCountDict[len(glyph.name)].append(glyph.name)
elif glyph.name.find('_') != -1:
usCounter=1
for i in glyph.name:
if i =='_':
usCounter=usCounter+1
if usCounter not in ligCountDict.keys():
ligCountDict[usCounter] = [glyph.name]
else:
ligCountDict[usCounter].append(glyph.name)
ligCount=ligCountDict.keys()
ligCount.sort()
foundLigs=[]
for i in ligCount:
l = ligCountDict[i]
l.sort()
foundLigs=foundLigs+l
fw=FeatureWriter('liga')
for i in foundLigs:
if i.find('_') != -1:
sub=i.split('_')
else:
sub=[]
for c in i:
sub.append(c)
fw.add(sub, i)
feat=fw.write()
if feat:
font.features.append(Feature('liga', feat))
return feat
if __name__ == "__main__":
fw = FeatureWriter('liga')
fw.add(['f', 'f', 'i'], ['f_f_i'])
fw.add('f f ', 'f_f')
fw.add(['f', 'i'], 'f_i')
print fw.write()