[cffLib.specializer] Implement width extraction in programToCommands()

Test:

./fonttools cffLib.specializer 7 0 8 rmoveto 1 2 3 4 5 0 rrcurvet
This commit is contained in:
Behdad Esfahbod 2017-05-06 13:12:14 -06:00
parent bef46993f6
commit 0bf5044d12

View File

@ -8,10 +8,11 @@ from fontTools.misc.py23 import *
def programToCommands(program): def programToCommands(program):
"""Takes a T2CharString program list and returns list of commands. """Takes a T2CharString program list and returns list of commands.
Each command is a two-tuple of commandname,arg-list. The commandname might Each command is a two-tuple of commandname,arg-list. The commandname might
be None if no commandname shall be emitted (used for glyph width (TODO), be empty string if no commandname shall be emitted (used for glyph width,
hintmask/cntrmask argument, as well as stray arguments at the end of the hintmask/cntrmask argument, as well as stray arguments at the end of the
program (¯\_()_/¯).""" program (¯\_()_/¯)."""
width = None
commands = [] commands = []
stack = [] stack = []
it = iter(program) it = iter(program)
@ -19,16 +20,26 @@ def programToCommands(program):
if not isinstance(token, basestring): if not isinstance(token, basestring):
stack.append(token) stack.append(token)
continue continue
if width is None and token in {'hstem', 'hstemhm', 'vstem', 'vstemhm',
'cntrmask', 'hintmask',
'hmoveto', 'vmoveto', 'rmoveto',
'endchar'}:
parity = token in {'hmoveto', 'vmoveto'}
if (len(stack) % 2) ^ parity:
width = stack.pop(0)
commands.append(('', [width]))
if token in {'hintmask', 'cntrmask'}: if token in {'hintmask', 'cntrmask'}:
if stack: if stack:
commands.append((None, stack)) commands.append(('', stack))
commands.append((token, [])) commands.append((token, []))
commands.append((None, [next(it)])) commands.append(('', [next(it)]))
else: else:
commands.append((token,stack)) commands.append((token,stack))
stack = [] stack = []
if stack: if stack:
commands.append((None, stack)) commands.append(('', stack))
return commands return commands
def commandsToProgram(commands): def commandsToProgram(commands):
@ -167,7 +178,7 @@ def generalizeCommands(commands, ignoreErrors=True):
result = [] result = []
mapping = _GeneralizerDecombinerCommandsMap mapping = _GeneralizerDecombinerCommandsMap
for op,args in commands: for op,args in commands:
func = getattr(mapping, op if op else '', None) func = getattr(mapping, op, None)
if not func: if not func:
result.append((op,args)) result.append((op,args))
continue continue
@ -178,8 +189,8 @@ def generalizeCommands(commands, ignoreErrors=True):
if ignoreErrors: if ignoreErrors:
# Store op as data, such that consumers of commands do not have to # Store op as data, such that consumers of commands do not have to
# deal with incorrect number of arguments. # deal with incorrect number of arguments.
result.append((None,args)) result.append(('', args))
result.append((None, [op])) result.append(('', [op]))
else: else:
raise raise
return result return result