1*e1fe3e4aSElliott Hughes__all__ = ["maxCtxFont"] 2*e1fe3e4aSElliott Hughes 3*e1fe3e4aSElliott Hughes 4*e1fe3e4aSElliott Hughesdef maxCtxFont(font): 5*e1fe3e4aSElliott Hughes """Calculate the usMaxContext value for an entire font.""" 6*e1fe3e4aSElliott Hughes 7*e1fe3e4aSElliott Hughes maxCtx = 0 8*e1fe3e4aSElliott Hughes for tag in ("GSUB", "GPOS"): 9*e1fe3e4aSElliott Hughes if tag not in font: 10*e1fe3e4aSElliott Hughes continue 11*e1fe3e4aSElliott Hughes table = font[tag].table 12*e1fe3e4aSElliott Hughes if not table.LookupList: 13*e1fe3e4aSElliott Hughes continue 14*e1fe3e4aSElliott Hughes for lookup in table.LookupList.Lookup: 15*e1fe3e4aSElliott Hughes for st in lookup.SubTable: 16*e1fe3e4aSElliott Hughes maxCtx = maxCtxSubtable(maxCtx, tag, lookup.LookupType, st) 17*e1fe3e4aSElliott Hughes return maxCtx 18*e1fe3e4aSElliott Hughes 19*e1fe3e4aSElliott Hughes 20*e1fe3e4aSElliott Hughesdef maxCtxSubtable(maxCtx, tag, lookupType, st): 21*e1fe3e4aSElliott Hughes """Calculate usMaxContext based on a single lookup table (and an existing 22*e1fe3e4aSElliott Hughes max value). 23*e1fe3e4aSElliott Hughes """ 24*e1fe3e4aSElliott Hughes 25*e1fe3e4aSElliott Hughes # single positioning, single / multiple substitution 26*e1fe3e4aSElliott Hughes if (tag == "GPOS" and lookupType == 1) or ( 27*e1fe3e4aSElliott Hughes tag == "GSUB" and lookupType in (1, 2, 3) 28*e1fe3e4aSElliott Hughes ): 29*e1fe3e4aSElliott Hughes maxCtx = max(maxCtx, 1) 30*e1fe3e4aSElliott Hughes 31*e1fe3e4aSElliott Hughes # pair positioning 32*e1fe3e4aSElliott Hughes elif tag == "GPOS" and lookupType == 2: 33*e1fe3e4aSElliott Hughes maxCtx = max(maxCtx, 2) 34*e1fe3e4aSElliott Hughes 35*e1fe3e4aSElliott Hughes # ligatures 36*e1fe3e4aSElliott Hughes elif tag == "GSUB" and lookupType == 4: 37*e1fe3e4aSElliott Hughes for ligatures in st.ligatures.values(): 38*e1fe3e4aSElliott Hughes for ligature in ligatures: 39*e1fe3e4aSElliott Hughes maxCtx = max(maxCtx, ligature.CompCount) 40*e1fe3e4aSElliott Hughes 41*e1fe3e4aSElliott Hughes # context 42*e1fe3e4aSElliott Hughes elif (tag == "GPOS" and lookupType == 7) or (tag == "GSUB" and lookupType == 5): 43*e1fe3e4aSElliott Hughes maxCtx = maxCtxContextualSubtable(maxCtx, st, "Pos" if tag == "GPOS" else "Sub") 44*e1fe3e4aSElliott Hughes 45*e1fe3e4aSElliott Hughes # chained context 46*e1fe3e4aSElliott Hughes elif (tag == "GPOS" and lookupType == 8) or (tag == "GSUB" and lookupType == 6): 47*e1fe3e4aSElliott Hughes maxCtx = maxCtxContextualSubtable( 48*e1fe3e4aSElliott Hughes maxCtx, st, "Pos" if tag == "GPOS" else "Sub", "Chain" 49*e1fe3e4aSElliott Hughes ) 50*e1fe3e4aSElliott Hughes 51*e1fe3e4aSElliott Hughes # extensions 52*e1fe3e4aSElliott Hughes elif (tag == "GPOS" and lookupType == 9) or (tag == "GSUB" and lookupType == 7): 53*e1fe3e4aSElliott Hughes maxCtx = maxCtxSubtable(maxCtx, tag, st.ExtensionLookupType, st.ExtSubTable) 54*e1fe3e4aSElliott Hughes 55*e1fe3e4aSElliott Hughes # reverse-chained context 56*e1fe3e4aSElliott Hughes elif tag == "GSUB" and lookupType == 8: 57*e1fe3e4aSElliott Hughes maxCtx = maxCtxContextualRule(maxCtx, st, "Reverse") 58*e1fe3e4aSElliott Hughes 59*e1fe3e4aSElliott Hughes return maxCtx 60*e1fe3e4aSElliott Hughes 61*e1fe3e4aSElliott Hughes 62*e1fe3e4aSElliott Hughesdef maxCtxContextualSubtable(maxCtx, st, ruleType, chain=""): 63*e1fe3e4aSElliott Hughes """Calculate usMaxContext based on a contextual feature subtable.""" 64*e1fe3e4aSElliott Hughes 65*e1fe3e4aSElliott Hughes if st.Format == 1: 66*e1fe3e4aSElliott Hughes for ruleset in getattr(st, "%s%sRuleSet" % (chain, ruleType)): 67*e1fe3e4aSElliott Hughes if ruleset is None: 68*e1fe3e4aSElliott Hughes continue 69*e1fe3e4aSElliott Hughes for rule in getattr(ruleset, "%s%sRule" % (chain, ruleType)): 70*e1fe3e4aSElliott Hughes if rule is None: 71*e1fe3e4aSElliott Hughes continue 72*e1fe3e4aSElliott Hughes maxCtx = maxCtxContextualRule(maxCtx, rule, chain) 73*e1fe3e4aSElliott Hughes 74*e1fe3e4aSElliott Hughes elif st.Format == 2: 75*e1fe3e4aSElliott Hughes for ruleset in getattr(st, "%s%sClassSet" % (chain, ruleType)): 76*e1fe3e4aSElliott Hughes if ruleset is None: 77*e1fe3e4aSElliott Hughes continue 78*e1fe3e4aSElliott Hughes for rule in getattr(ruleset, "%s%sClassRule" % (chain, ruleType)): 79*e1fe3e4aSElliott Hughes if rule is None: 80*e1fe3e4aSElliott Hughes continue 81*e1fe3e4aSElliott Hughes maxCtx = maxCtxContextualRule(maxCtx, rule, chain) 82*e1fe3e4aSElliott Hughes 83*e1fe3e4aSElliott Hughes elif st.Format == 3: 84*e1fe3e4aSElliott Hughes maxCtx = maxCtxContextualRule(maxCtx, st, chain) 85*e1fe3e4aSElliott Hughes 86*e1fe3e4aSElliott Hughes return maxCtx 87*e1fe3e4aSElliott Hughes 88*e1fe3e4aSElliott Hughes 89*e1fe3e4aSElliott Hughesdef maxCtxContextualRule(maxCtx, st, chain): 90*e1fe3e4aSElliott Hughes """Calculate usMaxContext based on a contextual feature rule.""" 91*e1fe3e4aSElliott Hughes 92*e1fe3e4aSElliott Hughes if not chain: 93*e1fe3e4aSElliott Hughes return max(maxCtx, st.GlyphCount) 94*e1fe3e4aSElliott Hughes elif chain == "Reverse": 95*e1fe3e4aSElliott Hughes return max(maxCtx, st.GlyphCount + st.LookAheadGlyphCount) 96*e1fe3e4aSElliott Hughes return max(maxCtx, st.InputGlyphCount + st.LookAheadGlyphCount) 97