From 2e96d81b050564c9e87a895d79ec31882b2aea4a Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 6 Nov 2024 18:03:38 -0500 Subject: [PATCH] [specializer_test] Add a test for blend stack-use after specialize() --- Tests/cffLib/specializer_test.py | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/Tests/cffLib/specializer_test.py b/Tests/cffLib/specializer_test.py index d7ab17d2f..bcbd3d718 100644 --- a/Tests/cffLib/specializer_test.py +++ b/Tests/cffLib/specializer_test.py @@ -1,3 +1,4 @@ +from fontTools.cffLib import maxStackLimit as maxStack from fontTools.cffLib.specializer import ( programToString, stringToProgram, @@ -22,6 +23,30 @@ def charstr_specialize(charstr, **kwargs): return programToString(specializeProgram(stringToProgram(charstr), **kwargs)) +def charstr_stack_use(charstr, getNumRegions=None): + program = stringToProgram(charstr) + + vsindex = None + maxStack = 0 + stack = [] + for token in program: + if token == vsindex: + vsindex = stack[-1] + stack = [] + elif token == "blend": + numBlends = stack[-1] + numRegions = getNumRegions(vsindex) + numOperandsToPop = 1 + numBlends * numRegions + stack[-numOperandsToPop:] = [] + elif type(token) is str: + stack = [] + else: + stack.append(token) + maxStack = max(maxStack, len(stack)) + + return maxStack + + class CFFGeneralizeProgramTest: @pytest.mark.parametrize( "charstr", @@ -558,6 +583,20 @@ class CFFSpecializeProgramTest: specialized = charstr_specialize(charstr) assert specialized == expected, (specialized, expected) + # 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" + operands = " ".join([blend_one] * 6) + operator = "rrcurveto" + charstr = " ".join([operands, operator] * 10) + expected = charstr + specialized = charstr_specialize( + charstr, getNumRegions=getNumRegions, maxstack=maxStack + ) + stack_use = charstr_stack_use(specialized, getNumRegions=getNumRegions) + assert stack_use < maxStack + class CFF2VFTestSpecialize(DataFilesHandler): def test_blend_round_trip(self):