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