diff --git a/Lib/fontTools/cffLib/specializer.py b/Lib/fontTools/cffLib/specializer.py index 3db5b3882..e61ad26f8 100644 --- a/Lib/fontTools/cffLib/specializer.py +++ b/Lib/fontTools/cffLib/specializer.py @@ -509,6 +509,19 @@ def _addArgs(a, b): return a + b +def _argsStackUse(args): + stackLen = 0 + maxLen = 0 + for arg in args: + if type(arg) is list: + # Blended arg + maxLen = max(maxLen, stackLen + _argsStackUse(arg)) + stackLen += arg[-1] + else: + stackLen += 1 + return max(stackLen, maxLen) + + def specializeCommands( commands, ignoreErrors=False, @@ -751,7 +764,7 @@ def specializeCommands( # Make sure the stack depth does not exceed (maxstack - 1), so # that subroutinizer can insert subroutine calls at any point. - if new_op and len(args1) + len(args2) < maxstack: + if new_op and _argsStackUse(args1) + _argsStackUse(args2) < maxstack: commands[i - 1] = (new_op, args1 + args2) del commands[i] diff --git a/Tests/cffLib/specializer_test.py b/Tests/cffLib/specializer_test.py index bcbd3d718..08c137ada 100644 --- a/Tests/cffLib/specializer_test.py +++ b/Tests/cffLib/specializer_test.py @@ -585,17 +585,19 @@ class CFFSpecializeProgramTest: # maxstack CFF2=513, specializer uses up to 512 def test_maxstack_blends(self): - getNumRegions = lambda iv: 15 - blend_one = "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 1 blend" + numRegions = 15 + numOps = 2000 + getNumRegions = lambda iv: numRegions + blend_one = " ".join([str(i) for i in range(1 + numRegions)] + ["1", "blend"]) operands = " ".join([blend_one] * 6) operator = "rrcurveto" - charstr = " ".join([operands, operator] * 10) + charstr = " ".join([operands, operator] * numOps) expected = charstr specialized = charstr_specialize( charstr, getNumRegions=getNumRegions, maxstack=maxStack ) stack_use = charstr_stack_use(specialized, getNumRegions=getNumRegions) - assert stack_use < maxStack + assert maxStack - numRegions < stack_use < maxStack class CFF2VFTestSpecialize(DataFilesHandler):