xref: /aosp_15_r20/external/fonttools/Lib/fontTools/varLib/interpolatableTestContourOrder.py (revision e1fe3e4ad2793916b15cccdc4a7da52a7e1dd0e9)
1from .interpolatableHelpers import *
2import logging
3
4log = logging.getLogger("fontTools.varLib.interpolatable")
5
6
7def test_contour_order(glyph0, glyph1):
8    # We try matching both the StatisticsControlPen vector
9    # and the StatisticsPen vector.
10    #
11    # If either method found a identity matching, accept it.
12    # This is crucial for fonts like Kablammo[MORF].ttf and
13    # Nabla[EDPT,EHLT].ttf, since they really confuse the
14    # StatisticsPen vector because of their area=0 contours.
15
16    n = len(glyph0.controlVectors)
17    matching = None
18    matching_cost = 0
19    identity_cost = 0
20    done = n <= 1
21    if not done:
22        m0Control = glyph0.controlVectors
23        m1Control = glyph1.controlVectors
24        (
25            matching_control,
26            matching_cost_control,
27            identity_cost_control,
28        ) = matching_for_vectors(m0Control, m1Control)
29        done = matching_cost_control == identity_cost_control
30    if not done:
31        m0Green = glyph0.greenVectors
32        m1Green = glyph1.greenVectors
33        (
34            matching_green,
35            matching_cost_green,
36            identity_cost_green,
37        ) = matching_for_vectors(m0Green, m1Green)
38        done = matching_cost_green == identity_cost_green
39
40    if not done:
41        # See if reversing contours in one master helps.
42        # That's a common problem.  Then the wrong_start_point
43        # test will fix them.
44        #
45        # Reverse the sign of the area (0); the rest stay the same.
46        if not done:
47            m1ControlReversed = [(-m[0],) + m[1:] for m in m1Control]
48            (
49                matching_control_reversed,
50                matching_cost_control_reversed,
51                identity_cost_control_reversed,
52            ) = matching_for_vectors(m0Control, m1ControlReversed)
53            done = matching_cost_control_reversed == identity_cost_control_reversed
54        if not done:
55            m1GreenReversed = [(-m[0],) + m[1:] for m in m1Green]
56            (
57                matching_control_reversed,
58                matching_cost_control_reversed,
59                identity_cost_control_reversed,
60            ) = matching_for_vectors(m0Control, m1ControlReversed)
61            done = matching_cost_control_reversed == identity_cost_control_reversed
62
63        if not done:
64            # Otherwise, use the worst of the two matchings.
65            if (
66                matching_cost_control / identity_cost_control
67                < matching_cost_green / identity_cost_green
68            ):
69                matching = matching_control
70                matching_cost = matching_cost_control
71                identity_cost = identity_cost_control
72            else:
73                matching = matching_green
74                matching_cost = matching_cost_green
75                identity_cost = identity_cost_green
76
77    this_tolerance = matching_cost / identity_cost if identity_cost else 1
78    log.debug(
79        "test-contour-order: tolerance %g",
80        this_tolerance,
81    )
82    return this_tolerance, matching
83