xref: /aosp_15_r20/external/fonttools/Lib/fontTools/ufoLib/kerning.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1def lookupKerningValue(
2    pair, kerning, groups, fallback=0, glyphToFirstGroup=None, glyphToSecondGroup=None
3):
4    """
5    Note: This expects kerning to be a flat dictionary
6    of kerning pairs, not the nested structure used
7    in kerning.plist.
8
9    >>> groups = {
10    ...     "public.kern1.O" : ["O", "D", "Q"],
11    ...     "public.kern2.E" : ["E", "F"]
12    ... }
13    >>> kerning = {
14    ...     ("public.kern1.O", "public.kern2.E") : -100,
15    ...     ("public.kern1.O", "F") : -200,
16    ...     ("D", "F") : -300
17    ... }
18    >>> lookupKerningValue(("D", "F"), kerning, groups)
19    -300
20    >>> lookupKerningValue(("O", "F"), kerning, groups)
21    -200
22    >>> lookupKerningValue(("O", "E"), kerning, groups)
23    -100
24    >>> lookupKerningValue(("O", "O"), kerning, groups)
25    0
26    >>> lookupKerningValue(("E", "E"), kerning, groups)
27    0
28    >>> lookupKerningValue(("E", "O"), kerning, groups)
29    0
30    >>> lookupKerningValue(("X", "X"), kerning, groups)
31    0
32    >>> lookupKerningValue(("public.kern1.O", "public.kern2.E"),
33    ...     kerning, groups)
34    -100
35    >>> lookupKerningValue(("public.kern1.O", "F"), kerning, groups)
36    -200
37    >>> lookupKerningValue(("O", "public.kern2.E"), kerning, groups)
38    -100
39    >>> lookupKerningValue(("public.kern1.X", "public.kern2.X"), kerning, groups)
40    0
41    """
42    # quickly check to see if the pair is in the kerning dictionary
43    if pair in kerning:
44        return kerning[pair]
45    # create glyph to group mapping
46    if glyphToFirstGroup is not None:
47        assert glyphToSecondGroup is not None
48    if glyphToSecondGroup is not None:
49        assert glyphToFirstGroup is not None
50    if glyphToFirstGroup is None:
51        glyphToFirstGroup = {}
52        glyphToSecondGroup = {}
53        for group, groupMembers in groups.items():
54            if group.startswith("public.kern1."):
55                for glyph in groupMembers:
56                    glyphToFirstGroup[glyph] = group
57            elif group.startswith("public.kern2."):
58                for glyph in groupMembers:
59                    glyphToSecondGroup[glyph] = group
60    # get group names and make sure first and second are glyph names
61    first, second = pair
62    firstGroup = secondGroup = None
63    if first.startswith("public.kern1."):
64        firstGroup = first
65        first = None
66    else:
67        firstGroup = glyphToFirstGroup.get(first)
68    if second.startswith("public.kern2."):
69        secondGroup = second
70        second = None
71    else:
72        secondGroup = glyphToSecondGroup.get(second)
73    # make an ordered list of pairs to look up
74    pairs = [
75        (first, second),
76        (first, secondGroup),
77        (firstGroup, second),
78        (firstGroup, secondGroup),
79    ]
80    # look up the pairs and return any matches
81    for pair in pairs:
82        if pair in kerning:
83            return kerning[pair]
84    # use the fallback value
85    return fallback
86
87
88if __name__ == "__main__":
89    import doctest
90
91    doctest.testmod()
92