xref: /aosp_15_r20/external/fonttools/Lib/fontTools/otlLib/maxContextCalc.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
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