[instancer/CFF2] Fixups with used-vsindex handing
vsindex 0 is implied. Also, add Unimplemented code for private-dict variable values. I couldn't find any fonts using them, so for now they remain unimplemented.
This commit is contained in:
parent
68f87dd850
commit
bdd42f14fc
@ -97,6 +97,7 @@ from fontTools import varLib
|
|||||||
# we import the `subset` module because we use the `prune_lookups` method on the GSUB
|
# we import the `subset` module because we use the `prune_lookups` method on the GSUB
|
||||||
# table class, and that method is only defined dynamically upon importing `subset`
|
# table class, and that method is only defined dynamically upon importing `subset`
|
||||||
from fontTools import subset # noqa: F401
|
from fontTools import subset # noqa: F401
|
||||||
|
from fontTools.cffLib import privateDictOperators2
|
||||||
from fontTools.cffLib.specializer import (
|
from fontTools.cffLib.specializer import (
|
||||||
programToCommands,
|
programToCommands,
|
||||||
commandsToProgram,
|
commandsToProgram,
|
||||||
@ -588,7 +589,6 @@ def instantiateCFF2(
|
|||||||
cff.desubroutinize()
|
cff.desubroutinize()
|
||||||
|
|
||||||
varStore2 = topDict.CharStrings.varStore.otVarStore
|
varStore2 = topDict.CharStrings.varStore.otVarStore
|
||||||
|
|
||||||
assert varStore is varStore2 # Who knows why it's in two places?!
|
assert varStore is varStore2 # Who knows why it's in two places?!
|
||||||
|
|
||||||
def getNumRegions(vsindex):
|
def getNumRegions(vsindex):
|
||||||
@ -597,6 +597,18 @@ def instantiateCFF2(
|
|||||||
)
|
)
|
||||||
|
|
||||||
charStrings = topDict.CharStrings.values()
|
charStrings = topDict.CharStrings.values()
|
||||||
|
|
||||||
|
# Gather all unique private dicts
|
||||||
|
uniquePrivateDicts = set()
|
||||||
|
privateDicts = []
|
||||||
|
if hasattr(topDict, "Private"):
|
||||||
|
uniquePrivateDicts.add(topDict.Private)
|
||||||
|
privateDicts.append(topDict.Private)
|
||||||
|
for cs in charStrings:
|
||||||
|
if cs.private not in uniquePrivateDicts:
|
||||||
|
uniquePrivateDicts.add(cs.private)
|
||||||
|
privateDicts.append(cs.private)
|
||||||
|
|
||||||
allCommands = []
|
allCommands = []
|
||||||
for cs in charStrings:
|
for cs in charStrings:
|
||||||
assert cs.private.vstore.otVarStore is varStore # Or in many places!!
|
assert cs.private.vstore.otVarStore is varStore # Or in many places!!
|
||||||
@ -697,18 +709,19 @@ def instantiateCFF2(
|
|||||||
varData.Item = []
|
varData.Item = []
|
||||||
varData.ItemCount = 0
|
varData.ItemCount = 0
|
||||||
|
|
||||||
# Remove vsindex commands that are no longer needed
|
# Remove vsindex commands that are no longer needed, collect those that are.
|
||||||
for commands in allCommands:
|
|
||||||
if any(isinstance(arg, list) for command in commands for arg in command[1]):
|
|
||||||
continue
|
|
||||||
commands[:] = [command for command in commands if command[0] != "vsindex"]
|
|
||||||
|
|
||||||
# Collect used vsindex values
|
|
||||||
usedVsindex = set()
|
usedVsindex = set()
|
||||||
for commands in allCommands:
|
for commands in allCommands:
|
||||||
for command in commands:
|
if any(isinstance(arg, list) for command in commands for arg in command[1]):
|
||||||
if command[0] == "vsindex":
|
vsindex = 0
|
||||||
usedVsindex.add(command[1][0])
|
for command in commands:
|
||||||
|
if command[0] == "vsindex":
|
||||||
|
vsindex = command[1][0]
|
||||||
|
continue
|
||||||
|
if any(isinstance(arg, list) for arg in command[1]):
|
||||||
|
usedVsindex.add(vsindex)
|
||||||
|
else:
|
||||||
|
commands[:] = [command for command in commands if command[0] != "vsindex"]
|
||||||
|
|
||||||
# Remove unused VarData and update vsindex values
|
# Remove unused VarData and update vsindex values
|
||||||
vsindexMapping = {v: i for i, v in enumerate(sorted(usedVsindex))}
|
vsindexMapping = {v: i for i, v in enumerate(sorted(usedVsindex))}
|
||||||
@ -720,16 +733,49 @@ def instantiateCFF2(
|
|||||||
if command[0] == "vsindex":
|
if command[0] == "vsindex":
|
||||||
command[1][0] = vsindexMapping[command[1][0]]
|
command[1][0] = vsindexMapping[command[1][0]]
|
||||||
|
|
||||||
|
# Ship the charstrings!
|
||||||
|
for cs, commands in zip(charStrings, allCommands):
|
||||||
|
cs.program = commandsToProgram(commands)
|
||||||
|
|
||||||
|
# TODO We don't currently instantiate the private-dict
|
||||||
|
# variable values, as I couldn't find any fonts using those.
|
||||||
|
# File a bug if you need this.
|
||||||
|
|
||||||
|
# Now to instantiate private values
|
||||||
|
for opcode, name, arg_type, default, converter in privateDictOperators2:
|
||||||
|
if arg_type not in ("number", "delta", "array"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for private in privateDicts:
|
||||||
|
if not hasattr(private, name):
|
||||||
|
continue
|
||||||
|
values = getattr(private, name)
|
||||||
|
if arg_type == "number":
|
||||||
|
values = [values]
|
||||||
|
|
||||||
|
newValues = []
|
||||||
|
for value in values:
|
||||||
|
if not isinstance(value, list):
|
||||||
|
newValues.append(value)
|
||||||
|
continue
|
||||||
|
|
||||||
|
raise NotImplementedError(
|
||||||
|
"File an issue to instantiate private-dict values."
|
||||||
|
)
|
||||||
|
|
||||||
|
newValues.extend(fetchBlendsFromVarStore(value))
|
||||||
|
|
||||||
|
if arg_type == "number":
|
||||||
|
newValues = newValues[0]
|
||||||
|
|
||||||
|
setattr(private, name, newValues)
|
||||||
|
|
||||||
# Remove empty VarStore
|
# Remove empty VarStore
|
||||||
if not varStore.VarData:
|
if not varStore.VarData:
|
||||||
topDict.VarStore = None
|
topDict.VarStore = None
|
||||||
topDict.CharStrings.varStore = None
|
topDict.CharStrings.varStore = None
|
||||||
for cs in charStrings:
|
for private in privateDicts:
|
||||||
cs.private.vstore = None
|
private.vstore = None
|
||||||
|
|
||||||
# Ship it!
|
|
||||||
for cs, commands in zip(charStrings, allCommands):
|
|
||||||
cs.program = commandsToProgram(commands)
|
|
||||||
|
|
||||||
|
|
||||||
def _instantiateGvarGlyph(
|
def _instantiateGvarGlyph(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user