191 lines
4.5 KiB
Python
191 lines
4.5 KiB
Python
|
"""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()
|