Coverage for /usr/lib/python3/dist-packages/fontTools/otlLib/maxContextCalc.py: 9%

57 statements  

« prev     ^ index     » next       coverage.py v7.9.1, created at 2025-06-14 15:55 +0200

1__all__ = ["maxCtxFont"] 

2 

3 

4def maxCtxFont(font): 

5 """Calculate the usMaxContext value for an entire font.""" 

6 

7 maxCtx = 0 

8 for tag in ("GSUB", "GPOS"): 

9 if tag not in font: 

10 continue 

11 table = font[tag].table 

12 if not table.LookupList: 

13 continue 

14 for lookup in table.LookupList.Lookup: 

15 for st in lookup.SubTable: 

16 maxCtx = maxCtxSubtable(maxCtx, tag, lookup.LookupType, st) 

17 return maxCtx 

18 

19 

20def maxCtxSubtable(maxCtx, tag, lookupType, st): 

21 """Calculate usMaxContext based on a single lookup table (and an existing 

22 max value). 

23 """ 

24 

25 # single positioning, single / multiple substitution 

26 if (tag == "GPOS" and lookupType == 1) or ( 

27 tag == "GSUB" and lookupType in (1, 2, 3) 

28 ): 

29 maxCtx = max(maxCtx, 1) 

30 

31 # pair positioning 

32 elif tag == "GPOS" and lookupType == 2: 

33 maxCtx = max(maxCtx, 2) 

34 

35 # ligatures 

36 elif tag == "GSUB" and lookupType == 4: 

37 for ligatures in st.ligatures.values(): 

38 for ligature in ligatures: 

39 maxCtx = max(maxCtx, ligature.CompCount) 

40 

41 # context 

42 elif (tag == "GPOS" and lookupType == 7) or (tag == "GSUB" and lookupType == 5): 

43 maxCtx = maxCtxContextualSubtable(maxCtx, st, "Pos" if tag == "GPOS" else "Sub") 

44 

45 # chained context 

46 elif (tag == "GPOS" and lookupType == 8) or (tag == "GSUB" and lookupType == 6): 

47 maxCtx = maxCtxContextualSubtable( 

48 maxCtx, st, "Pos" if tag == "GPOS" else "Sub", "Chain" 

49 ) 

50 

51 # extensions 

52 elif (tag == "GPOS" and lookupType == 9) or (tag == "GSUB" and lookupType == 7): 

53 maxCtx = maxCtxSubtable(maxCtx, tag, st.ExtensionLookupType, st.ExtSubTable) 

54 

55 # reverse-chained context 

56 elif tag == "GSUB" and lookupType == 8: 

57 maxCtx = maxCtxContextualRule(maxCtx, st, "Reverse") 

58 

59 return maxCtx 

60 

61 

62def maxCtxContextualSubtable(maxCtx, st, ruleType, chain=""): 

63 """Calculate usMaxContext based on a contextual feature subtable.""" 

64 

65 if st.Format == 1: 

66 for ruleset in getattr(st, "%s%sRuleSet" % (chain, ruleType)): 

67 if ruleset is None: 

68 continue 

69 for rule in getattr(ruleset, "%s%sRule" % (chain, ruleType)): 

70 if rule is None: 

71 continue 

72 maxCtx = maxCtxContextualRule(maxCtx, rule, chain) 

73 

74 elif st.Format == 2: 

75 for ruleset in getattr(st, "%s%sClassSet" % (chain, ruleType)): 

76 if ruleset is None: 

77 continue 

78 for rule in getattr(ruleset, "%s%sClassRule" % (chain, ruleType)): 

79 if rule is None: 

80 continue 

81 maxCtx = maxCtxContextualRule(maxCtx, rule, chain) 

82 

83 elif st.Format == 3: 

84 maxCtx = maxCtxContextualRule(maxCtx, st, chain) 

85 

86 return maxCtx 

87 

88 

89def maxCtxContextualRule(maxCtx, st, chain): 

90 """Calculate usMaxContext based on a contextual feature rule.""" 

91 

92 if not chain: 

93 return max(maxCtx, st.GlyphCount) 

94 elif chain == "Reverse": 

95 return max(maxCtx, st.GlyphCount + st.LookAheadGlyphCount) 

96 return max(maxCtx, st.InputGlyphCount + st.LookAheadGlyphCount)