diff --git a/Lib/fontTools/cffLib/specializer.py b/Lib/fontTools/cffLib/specializer.py index 11e9e578e..ce7bbcebc 100644 --- a/Lib/fontTools/cffLib/specializer.py +++ b/Lib/fontTools/cffLib/specializer.py @@ -715,6 +715,7 @@ def specializeCommands( continue # 5. Combine adjacent operators when possible, minding not to go over max stack size. + stackUse = _argsStackUse(commands[-1][1]) if commands else 0 for i in range(len(commands) - 1, 0, -1): op1, args1 = commands[i - 1] op2, args2 = commands[i] @@ -764,19 +765,14 @@ def specializeCommands( # Make sure the stack depth does not exceed (maxstack - 1), so # that subroutinizer can insert subroutine calls at any point. - # - # The assumption is that args1, and args2, each individually - # can be successfully processed without a stack overflow. - # When combined, the stack depth to consider would be the - # number of items in args1 plus what it takes to build args2 - # on top of args1, which will be already on the stack as - # len(args1) items. - # - # It's unfortunate that _argsStackUse() is O(n) in the number - # of args, but it's not a big deal hopefully. - if new_op and len(args1) + _argsStackUse(args2) < maxstack: + args1StackUse = _argsStackUse(args1) + combinedStackUse = max(args1StackUse, len(args1) + stackUse) + if new_op and combinedStackUse < maxstack: commands[i - 1] = (new_op, args1 + args2) del commands[i] + stackUse = combinedStackUse + else: + stackUse = args1StackUse # 6. Resolve any remaining made-up operators into real operators. for i in range(len(commands)): diff --git a/Tests/cffLib/specializer_test.py b/Tests/cffLib/specializer_test.py index aad3bfdfb..ffc85b51c 100644 --- a/Tests/cffLib/specializer_test.py +++ b/Tests/cffLib/specializer_test.py @@ -599,8 +599,8 @@ class CFFSpecializeProgramTest: stack_use = charstr_stack_use(specialized, getNumRegions=getNumRegions) assert maxStack - numRegions < stack_use < maxStack - def test_maxstack_blends2(self): - # See if two long blend sequences are merged into one + def test_maxstack_commands(self): + # See if two commands with deep blends are merged into one numRegions = 400 numOps = 2 getNumRegions = lambda iv: numRegions