psb1558 / Elstob-font

A variable font for medievalists
SIL Open Font License 1.1
386 stars 9 forks source link

Trouble with script for merging TT instructions #12

Closed psb1558 closed 4 years ago

psb1558 commented 4 years ago

I've posted about this on the fontTools list but will also put it here, in case some good soul wandering in these parts should happen to have an answer. I've been trying to write a script that will merge TT instructions into a variable font, but while the resulting font looks correct when examined via ttx, OTMaster or elsewhere, the instructions don't get executed, and in OTMaster the glyph doesn't display, but instead a red frowny face:

image

which expresses my mood just now. I've tried paring down the script to do nothing but push and pop values, but the effect is the same. But here's the thing: the very same script, run on a static instance of Elstob, works fine. If there are real instructions in it, they get executed without difficulty.

So what I am doing wrong, or how do instructions for a variable font have to be handled differently from a static font?

Here's the minimal code (which does nothing):

from fontTools import ttLib
from fontTools.ttLib import ttFont, tables
import array

currentFont = ttLib.TTFont("Elstob[GRAD,opsz,wght].ttf")
for g_name in currentFont['glyf'].glyphs:
    glyph = currentFont['glyf'][g_name]
    if hasattr(glyph, 'program'):
        glyph.program.fromAssembly("")

def install_glyph_program(nm, fo, asm):
    g = fo['glyf'][nm]
    g.program = tables.ttProgram.Program()
    g.program.fromAssembly(asm)

currentFont['cvt '] = ttFont.newTable('cvt ')
setattr(currentFont['cvt '],'values',array.array('h', [891, 914, 74, 1487, 85, 39, 0, -23]))

currentFont['fpgm'] = ttFont.newTable('fpgm')
currentFont['fpgm'].program = tables.ttProgram.Program()
currentFont['fpgm'].program.fromAssembly('PUSHB[ ]\n\
0\n\
FDEF[ ]\n\
PUSHB[ ]\n\
0\n\
POP[ ]\n\
ENDF[ ]')

currentFont['prep'] = ttFont.newTable('prep')
currentFont['prep'].program = tables.ttProgram.Program()
currentFont['prep'].program.fromAssembly('PUSHB[ ]\n\
1\n\
POP[ ]')

install_glyph_program("a", currentFont, "SVTCA[0]\n\
PUSHB[ ]\n\
34\n\
1\n\
MIAP[1]")

currentFont['maxp'].maxTwilightPoints = 25
currentFont['maxp'].maxStorage = 70
currentFont['maxp'].maxStackElements = 256
currentFont['maxp'].maxFunctionDefs = 4

currentFont.save("Elstob[GRAD,opsz,wght]-hinted.ttf", 1)
psb1558 commented 4 years ago

I'll answer my own query, since I figured it out this morning after some two days of struggle. Got the answer by trying the font out in Axis-Praxis with the console open, so saw the report from OTSanitiser that maxSizeOfInstructions in maxp was too small. In fact, I wasn't setting MaxSizeOfInstructions at all, so whatever value was already stored in the font was being retained. The difference between a variable font and a static one was simply that fontmake was running ttfautohint on the static font but not on the variable one, so MaxSizeOfInstructions in the static font was quite large, while in the variable font it was zero.

One can track the size of the instructions with len(glyph.program.getBytecode()).

And now I'll close this to spare myself embarrassment for missing something so obvious.