fonttools 4.60.2__cp311-cp311-win32.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fontTools/__init__.py +8 -0
- fontTools/__main__.py +35 -0
- fontTools/afmLib.py +439 -0
- fontTools/agl.py +5233 -0
- fontTools/annotations.py +30 -0
- fontTools/cffLib/CFF2ToCFF.py +258 -0
- fontTools/cffLib/CFFToCFF2.py +305 -0
- fontTools/cffLib/__init__.py +3694 -0
- fontTools/cffLib/specializer.py +927 -0
- fontTools/cffLib/transforms.py +495 -0
- fontTools/cffLib/width.py +210 -0
- fontTools/colorLib/__init__.py +0 -0
- fontTools/colorLib/builder.py +664 -0
- fontTools/colorLib/errors.py +2 -0
- fontTools/colorLib/geometry.py +143 -0
- fontTools/colorLib/table_builder.py +223 -0
- fontTools/colorLib/unbuilder.py +81 -0
- fontTools/config/__init__.py +90 -0
- fontTools/cu2qu/__init__.py +15 -0
- fontTools/cu2qu/__main__.py +6 -0
- fontTools/cu2qu/benchmark.py +54 -0
- fontTools/cu2qu/cli.py +198 -0
- fontTools/cu2qu/cu2qu.c +15817 -0
- fontTools/cu2qu/cu2qu.cp311-win32.pyd +0 -0
- fontTools/cu2qu/cu2qu.py +563 -0
- fontTools/cu2qu/errors.py +77 -0
- fontTools/cu2qu/ufo.py +363 -0
- fontTools/designspaceLib/__init__.py +3343 -0
- fontTools/designspaceLib/__main__.py +6 -0
- fontTools/designspaceLib/split.py +475 -0
- fontTools/designspaceLib/statNames.py +260 -0
- fontTools/designspaceLib/types.py +147 -0
- fontTools/encodings/MacRoman.py +258 -0
- fontTools/encodings/StandardEncoding.py +258 -0
- fontTools/encodings/__init__.py +1 -0
- fontTools/encodings/codecs.py +135 -0
- fontTools/feaLib/__init__.py +4 -0
- fontTools/feaLib/__main__.py +78 -0
- fontTools/feaLib/ast.py +2143 -0
- fontTools/feaLib/builder.py +1814 -0
- fontTools/feaLib/error.py +22 -0
- fontTools/feaLib/lexer.c +17029 -0
- fontTools/feaLib/lexer.cp311-win32.pyd +0 -0
- fontTools/feaLib/lexer.py +287 -0
- fontTools/feaLib/location.py +12 -0
- fontTools/feaLib/lookupDebugInfo.py +12 -0
- fontTools/feaLib/parser.py +2394 -0
- fontTools/feaLib/variableScalar.py +118 -0
- fontTools/fontBuilder.py +1014 -0
- fontTools/help.py +36 -0
- fontTools/merge/__init__.py +248 -0
- fontTools/merge/__main__.py +6 -0
- fontTools/merge/base.py +81 -0
- fontTools/merge/cmap.py +173 -0
- fontTools/merge/layout.py +526 -0
- fontTools/merge/options.py +85 -0
- fontTools/merge/tables.py +352 -0
- fontTools/merge/unicode.py +78 -0
- fontTools/merge/util.py +143 -0
- fontTools/misc/__init__.py +1 -0
- fontTools/misc/arrayTools.py +424 -0
- fontTools/misc/bezierTools.c +39731 -0
- fontTools/misc/bezierTools.cp311-win32.pyd +0 -0
- fontTools/misc/bezierTools.py +1500 -0
- fontTools/misc/classifyTools.py +170 -0
- fontTools/misc/cliTools.py +53 -0
- fontTools/misc/configTools.py +349 -0
- fontTools/misc/cython.py +27 -0
- fontTools/misc/dictTools.py +83 -0
- fontTools/misc/eexec.py +119 -0
- fontTools/misc/encodingTools.py +72 -0
- fontTools/misc/enumTools.py +23 -0
- fontTools/misc/etree.py +456 -0
- fontTools/misc/filenames.py +245 -0
- fontTools/misc/filesystem/__init__.py +68 -0
- fontTools/misc/filesystem/_base.py +134 -0
- fontTools/misc/filesystem/_copy.py +45 -0
- fontTools/misc/filesystem/_errors.py +54 -0
- fontTools/misc/filesystem/_info.py +75 -0
- fontTools/misc/filesystem/_osfs.py +164 -0
- fontTools/misc/filesystem/_path.py +67 -0
- fontTools/misc/filesystem/_subfs.py +92 -0
- fontTools/misc/filesystem/_tempfs.py +34 -0
- fontTools/misc/filesystem/_tools.py +34 -0
- fontTools/misc/filesystem/_walk.py +55 -0
- fontTools/misc/filesystem/_zipfs.py +204 -0
- fontTools/misc/fixedTools.py +253 -0
- fontTools/misc/intTools.py +25 -0
- fontTools/misc/iterTools.py +12 -0
- fontTools/misc/lazyTools.py +42 -0
- fontTools/misc/loggingTools.py +543 -0
- fontTools/misc/macCreatorType.py +56 -0
- fontTools/misc/macRes.py +261 -0
- fontTools/misc/plistlib/__init__.py +681 -0
- fontTools/misc/plistlib/py.typed +0 -0
- fontTools/misc/psCharStrings.py +1511 -0
- fontTools/misc/psLib.py +398 -0
- fontTools/misc/psOperators.py +572 -0
- fontTools/misc/py23.py +96 -0
- fontTools/misc/roundTools.py +110 -0
- fontTools/misc/sstruct.py +227 -0
- fontTools/misc/symfont.py +242 -0
- fontTools/misc/testTools.py +233 -0
- fontTools/misc/textTools.py +156 -0
- fontTools/misc/timeTools.py +88 -0
- fontTools/misc/transform.py +516 -0
- fontTools/misc/treeTools.py +45 -0
- fontTools/misc/vector.py +147 -0
- fontTools/misc/visitor.py +158 -0
- fontTools/misc/xmlReader.py +188 -0
- fontTools/misc/xmlWriter.py +231 -0
- fontTools/mtiLib/__init__.py +1400 -0
- fontTools/mtiLib/__main__.py +5 -0
- fontTools/otlLib/__init__.py +1 -0
- fontTools/otlLib/builder.py +3465 -0
- fontTools/otlLib/error.py +11 -0
- fontTools/otlLib/maxContextCalc.py +96 -0
- fontTools/otlLib/optimize/__init__.py +53 -0
- fontTools/otlLib/optimize/__main__.py +6 -0
- fontTools/otlLib/optimize/gpos.py +439 -0
- fontTools/pens/__init__.py +1 -0
- fontTools/pens/areaPen.py +52 -0
- fontTools/pens/basePen.py +475 -0
- fontTools/pens/boundsPen.py +98 -0
- fontTools/pens/cairoPen.py +26 -0
- fontTools/pens/cocoaPen.py +26 -0
- fontTools/pens/cu2quPen.py +325 -0
- fontTools/pens/explicitClosingLinePen.py +101 -0
- fontTools/pens/filterPen.py +433 -0
- fontTools/pens/freetypePen.py +462 -0
- fontTools/pens/hashPointPen.py +89 -0
- fontTools/pens/momentsPen.c +13378 -0
- fontTools/pens/momentsPen.cp311-win32.pyd +0 -0
- fontTools/pens/momentsPen.py +879 -0
- fontTools/pens/perimeterPen.py +69 -0
- fontTools/pens/pointInsidePen.py +192 -0
- fontTools/pens/pointPen.py +643 -0
- fontTools/pens/qtPen.py +29 -0
- fontTools/pens/qu2cuPen.py +105 -0
- fontTools/pens/quartzPen.py +43 -0
- fontTools/pens/recordingPen.py +335 -0
- fontTools/pens/reportLabPen.py +79 -0
- fontTools/pens/reverseContourPen.py +96 -0
- fontTools/pens/roundingPen.py +130 -0
- fontTools/pens/statisticsPen.py +312 -0
- fontTools/pens/svgPathPen.py +310 -0
- fontTools/pens/t2CharStringPen.py +88 -0
- fontTools/pens/teePen.py +55 -0
- fontTools/pens/transformPen.py +115 -0
- fontTools/pens/ttGlyphPen.py +335 -0
- fontTools/pens/wxPen.py +29 -0
- fontTools/qu2cu/__init__.py +15 -0
- fontTools/qu2cu/__main__.py +7 -0
- fontTools/qu2cu/benchmark.py +56 -0
- fontTools/qu2cu/cli.py +125 -0
- fontTools/qu2cu/qu2cu.c +16682 -0
- fontTools/qu2cu/qu2cu.cp311-win32.pyd +0 -0
- fontTools/qu2cu/qu2cu.py +405 -0
- fontTools/subset/__init__.py +4096 -0
- fontTools/subset/__main__.py +6 -0
- fontTools/subset/cff.py +184 -0
- fontTools/subset/svg.py +253 -0
- fontTools/subset/util.py +25 -0
- fontTools/svgLib/__init__.py +3 -0
- fontTools/svgLib/path/__init__.py +65 -0
- fontTools/svgLib/path/arc.py +154 -0
- fontTools/svgLib/path/parser.py +322 -0
- fontTools/svgLib/path/shapes.py +183 -0
- fontTools/t1Lib/__init__.py +648 -0
- fontTools/tfmLib.py +460 -0
- fontTools/ttLib/__init__.py +30 -0
- fontTools/ttLib/__main__.py +148 -0
- fontTools/ttLib/macUtils.py +54 -0
- fontTools/ttLib/removeOverlaps.py +395 -0
- fontTools/ttLib/reorderGlyphs.py +285 -0
- fontTools/ttLib/scaleUpem.py +436 -0
- fontTools/ttLib/sfnt.py +661 -0
- fontTools/ttLib/standardGlyphOrder.py +271 -0
- fontTools/ttLib/tables/B_A_S_E_.py +14 -0
- fontTools/ttLib/tables/BitmapGlyphMetrics.py +64 -0
- fontTools/ttLib/tables/C_B_D_T_.py +113 -0
- fontTools/ttLib/tables/C_B_L_C_.py +19 -0
- fontTools/ttLib/tables/C_F_F_.py +61 -0
- fontTools/ttLib/tables/C_F_F__2.py +26 -0
- fontTools/ttLib/tables/C_O_L_R_.py +165 -0
- fontTools/ttLib/tables/C_P_A_L_.py +305 -0
- fontTools/ttLib/tables/D_S_I_G_.py +158 -0
- fontTools/ttLib/tables/D__e_b_g.py +35 -0
- fontTools/ttLib/tables/DefaultTable.py +49 -0
- fontTools/ttLib/tables/E_B_D_T_.py +835 -0
- fontTools/ttLib/tables/E_B_L_C_.py +718 -0
- fontTools/ttLib/tables/F_F_T_M_.py +52 -0
- fontTools/ttLib/tables/F__e_a_t.py +149 -0
- fontTools/ttLib/tables/G_D_E_F_.py +13 -0
- fontTools/ttLib/tables/G_M_A_P_.py +148 -0
- fontTools/ttLib/tables/G_P_K_G_.py +133 -0
- fontTools/ttLib/tables/G_P_O_S_.py +14 -0
- fontTools/ttLib/tables/G_S_U_B_.py +13 -0
- fontTools/ttLib/tables/G_V_A_R_.py +5 -0
- fontTools/ttLib/tables/G__l_a_t.py +235 -0
- fontTools/ttLib/tables/G__l_o_c.py +85 -0
- fontTools/ttLib/tables/H_V_A_R_.py +13 -0
- fontTools/ttLib/tables/J_S_T_F_.py +13 -0
- fontTools/ttLib/tables/L_T_S_H_.py +58 -0
- fontTools/ttLib/tables/M_A_T_H_.py +13 -0
- fontTools/ttLib/tables/M_E_T_A_.py +352 -0
- fontTools/ttLib/tables/M_V_A_R_.py +13 -0
- fontTools/ttLib/tables/O_S_2f_2.py +752 -0
- fontTools/ttLib/tables/S_I_N_G_.py +99 -0
- fontTools/ttLib/tables/S_T_A_T_.py +15 -0
- fontTools/ttLib/tables/S_V_G_.py +223 -0
- fontTools/ttLib/tables/S__i_l_f.py +1040 -0
- fontTools/ttLib/tables/S__i_l_l.py +92 -0
- fontTools/ttLib/tables/T_S_I_B_.py +13 -0
- fontTools/ttLib/tables/T_S_I_C_.py +14 -0
- fontTools/ttLib/tables/T_S_I_D_.py +13 -0
- fontTools/ttLib/tables/T_S_I_J_.py +13 -0
- fontTools/ttLib/tables/T_S_I_P_.py +13 -0
- fontTools/ttLib/tables/T_S_I_S_.py +13 -0
- fontTools/ttLib/tables/T_S_I_V_.py +26 -0
- fontTools/ttLib/tables/T_S_I__0.py +70 -0
- fontTools/ttLib/tables/T_S_I__1.py +163 -0
- fontTools/ttLib/tables/T_S_I__2.py +17 -0
- fontTools/ttLib/tables/T_S_I__3.py +22 -0
- fontTools/ttLib/tables/T_S_I__5.py +60 -0
- fontTools/ttLib/tables/T_T_F_A_.py +14 -0
- fontTools/ttLib/tables/TupleVariation.py +884 -0
- fontTools/ttLib/tables/V_A_R_C_.py +12 -0
- fontTools/ttLib/tables/V_D_M_X_.py +249 -0
- fontTools/ttLib/tables/V_O_R_G_.py +165 -0
- fontTools/ttLib/tables/V_V_A_R_.py +13 -0
- fontTools/ttLib/tables/__init__.py +98 -0
- fontTools/ttLib/tables/_a_n_k_r.py +15 -0
- fontTools/ttLib/tables/_a_v_a_r.py +193 -0
- fontTools/ttLib/tables/_b_s_l_n.py +15 -0
- fontTools/ttLib/tables/_c_i_d_g.py +24 -0
- fontTools/ttLib/tables/_c_m_a_p.py +1591 -0
- fontTools/ttLib/tables/_c_v_a_r.py +94 -0
- fontTools/ttLib/tables/_c_v_t.py +56 -0
- fontTools/ttLib/tables/_f_e_a_t.py +15 -0
- fontTools/ttLib/tables/_f_p_g_m.py +62 -0
- fontTools/ttLib/tables/_f_v_a_r.py +261 -0
- fontTools/ttLib/tables/_g_a_s_p.py +63 -0
- fontTools/ttLib/tables/_g_c_i_d.py +13 -0
- fontTools/ttLib/tables/_g_l_y_f.py +2311 -0
- fontTools/ttLib/tables/_g_v_a_r.py +340 -0
- fontTools/ttLib/tables/_h_d_m_x.py +127 -0
- fontTools/ttLib/tables/_h_e_a_d.py +130 -0
- fontTools/ttLib/tables/_h_h_e_a.py +147 -0
- fontTools/ttLib/tables/_h_m_t_x.py +164 -0
- fontTools/ttLib/tables/_k_e_r_n.py +289 -0
- fontTools/ttLib/tables/_l_c_a_r.py +13 -0
- fontTools/ttLib/tables/_l_o_c_a.py +70 -0
- fontTools/ttLib/tables/_l_t_a_g.py +72 -0
- fontTools/ttLib/tables/_m_a_x_p.py +147 -0
- fontTools/ttLib/tables/_m_e_t_a.py +112 -0
- fontTools/ttLib/tables/_m_o_r_t.py +14 -0
- fontTools/ttLib/tables/_m_o_r_x.py +15 -0
- fontTools/ttLib/tables/_n_a_m_e.py +1242 -0
- fontTools/ttLib/tables/_o_p_b_d.py +14 -0
- fontTools/ttLib/tables/_p_o_s_t.py +319 -0
- fontTools/ttLib/tables/_p_r_e_p.py +16 -0
- fontTools/ttLib/tables/_p_r_o_p.py +12 -0
- fontTools/ttLib/tables/_s_b_i_x.py +129 -0
- fontTools/ttLib/tables/_t_r_a_k.py +332 -0
- fontTools/ttLib/tables/_v_h_e_a.py +139 -0
- fontTools/ttLib/tables/_v_m_t_x.py +19 -0
- fontTools/ttLib/tables/asciiTable.py +20 -0
- fontTools/ttLib/tables/grUtils.py +92 -0
- fontTools/ttLib/tables/otBase.py +1458 -0
- fontTools/ttLib/tables/otConverters.py +2068 -0
- fontTools/ttLib/tables/otData.py +6400 -0
- fontTools/ttLib/tables/otTables.py +2703 -0
- fontTools/ttLib/tables/otTraverse.py +163 -0
- fontTools/ttLib/tables/sbixGlyph.py +149 -0
- fontTools/ttLib/tables/sbixStrike.py +177 -0
- fontTools/ttLib/tables/table_API_readme.txt +91 -0
- fontTools/ttLib/tables/ttProgram.py +594 -0
- fontTools/ttLib/ttCollection.py +125 -0
- fontTools/ttLib/ttFont.py +1148 -0
- fontTools/ttLib/ttGlyphSet.py +490 -0
- fontTools/ttLib/ttVisitor.py +32 -0
- fontTools/ttLib/woff2.py +1680 -0
- fontTools/ttx.py +479 -0
- fontTools/ufoLib/__init__.py +2575 -0
- fontTools/ufoLib/converters.py +407 -0
- fontTools/ufoLib/errors.py +30 -0
- fontTools/ufoLib/etree.py +6 -0
- fontTools/ufoLib/filenames.py +356 -0
- fontTools/ufoLib/glifLib.py +2120 -0
- fontTools/ufoLib/kerning.py +141 -0
- fontTools/ufoLib/plistlib.py +47 -0
- fontTools/ufoLib/pointPen.py +6 -0
- fontTools/ufoLib/utils.py +107 -0
- fontTools/ufoLib/validators.py +1208 -0
- fontTools/unicode.py +50 -0
- fontTools/unicodedata/Blocks.py +817 -0
- fontTools/unicodedata/Mirrored.py +446 -0
- fontTools/unicodedata/OTTags.py +50 -0
- fontTools/unicodedata/ScriptExtensions.py +832 -0
- fontTools/unicodedata/Scripts.py +3639 -0
- fontTools/unicodedata/__init__.py +306 -0
- fontTools/varLib/__init__.py +1600 -0
- fontTools/varLib/__main__.py +6 -0
- fontTools/varLib/avar/__init__.py +0 -0
- fontTools/varLib/avar/__main__.py +72 -0
- fontTools/varLib/avar/build.py +79 -0
- fontTools/varLib/avar/map.py +108 -0
- fontTools/varLib/avar/plan.py +1004 -0
- fontTools/varLib/avar/unbuild.py +271 -0
- fontTools/varLib/avarPlanner.py +8 -0
- fontTools/varLib/builder.py +215 -0
- fontTools/varLib/cff.py +631 -0
- fontTools/varLib/errors.py +219 -0
- fontTools/varLib/featureVars.py +703 -0
- fontTools/varLib/hvar.py +113 -0
- fontTools/varLib/instancer/__init__.py +2052 -0
- fontTools/varLib/instancer/__main__.py +5 -0
- fontTools/varLib/instancer/featureVars.py +190 -0
- fontTools/varLib/instancer/names.py +388 -0
- fontTools/varLib/instancer/solver.py +309 -0
- fontTools/varLib/interpolatable.py +1209 -0
- fontTools/varLib/interpolatableHelpers.py +399 -0
- fontTools/varLib/interpolatablePlot.py +1269 -0
- fontTools/varLib/interpolatableTestContourOrder.py +82 -0
- fontTools/varLib/interpolatableTestStartingPoint.py +107 -0
- fontTools/varLib/interpolate_layout.py +124 -0
- fontTools/varLib/iup.c +19815 -0
- fontTools/varLib/iup.cp311-win32.pyd +0 -0
- fontTools/varLib/iup.py +490 -0
- fontTools/varLib/merger.py +1717 -0
- fontTools/varLib/models.py +642 -0
- fontTools/varLib/multiVarStore.py +253 -0
- fontTools/varLib/mutator.py +529 -0
- fontTools/varLib/mvar.py +40 -0
- fontTools/varLib/plot.py +238 -0
- fontTools/varLib/stat.py +149 -0
- fontTools/varLib/varStore.py +739 -0
- fontTools/voltLib/__init__.py +5 -0
- fontTools/voltLib/__main__.py +206 -0
- fontTools/voltLib/ast.py +452 -0
- fontTools/voltLib/error.py +12 -0
- fontTools/voltLib/lexer.py +99 -0
- fontTools/voltLib/parser.py +664 -0
- fontTools/voltLib/voltToFea.py +911 -0
- fonttools-4.60.2.data/data/share/man/man1/ttx.1 +225 -0
- fonttools-4.60.2.dist-info/METADATA +2250 -0
- fonttools-4.60.2.dist-info/RECORD +353 -0
- fonttools-4.60.2.dist-info/WHEEL +5 -0
- fonttools-4.60.2.dist-info/entry_points.txt +5 -0
- fonttools-4.60.2.dist-info/licenses/LICENSE +21 -0
- fonttools-4.60.2.dist-info/licenses/LICENSE.external +388 -0
- fonttools-4.60.2.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
from .interpolatableHelpers import *
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
log = logging.getLogger("fontTools.varLib.interpolatable")
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def 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_green_reversed,
|
|
59
|
+
identity_cost_green_reversed,
|
|
60
|
+
) = matching_for_vectors(m0Green, m1GreenReversed)
|
|
61
|
+
done = matching_cost_green_reversed == identity_cost_green_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
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
from .interpolatableHelpers import *
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def test_starting_point(glyph0, glyph1, ix, tolerance, matching):
|
|
5
|
+
if matching is None:
|
|
6
|
+
matching = list(range(len(glyph0.isomorphisms)))
|
|
7
|
+
contour0 = glyph0.isomorphisms[ix]
|
|
8
|
+
contour1 = glyph1.isomorphisms[matching[ix]]
|
|
9
|
+
m0Vectors = glyph0.greenVectors
|
|
10
|
+
m1Vectors = [glyph1.greenVectors[i] for i in matching]
|
|
11
|
+
|
|
12
|
+
c0 = contour0[0]
|
|
13
|
+
# Next few lines duplicated below.
|
|
14
|
+
costs = [vdiff_hypot2_complex(c0[0], c1[0]) for c1 in contour1]
|
|
15
|
+
min_cost_idx, min_cost = min(enumerate(costs), key=lambda x: x[1])
|
|
16
|
+
first_cost = costs[0]
|
|
17
|
+
proposed_point = contour1[min_cost_idx][1]
|
|
18
|
+
reverse = contour1[min_cost_idx][2]
|
|
19
|
+
|
|
20
|
+
if min_cost < first_cost * tolerance:
|
|
21
|
+
# c0 is the first isomorphism of the m0 master
|
|
22
|
+
# contour1 is list of all isomorphisms of the m1 master
|
|
23
|
+
#
|
|
24
|
+
# If the two shapes are both circle-ish and slightly
|
|
25
|
+
# rotated, we detect wrong start point. This is for
|
|
26
|
+
# example the case hundreds of times in
|
|
27
|
+
# RobotoSerif-Italic[GRAD,opsz,wdth,wght].ttf
|
|
28
|
+
#
|
|
29
|
+
# If the proposed point is only one off from the first
|
|
30
|
+
# point (and not reversed), try harder:
|
|
31
|
+
#
|
|
32
|
+
# Find the major eigenvector of the covariance matrix,
|
|
33
|
+
# and rotate the contours by that angle. Then find the
|
|
34
|
+
# closest point again. If it matches this time, let it
|
|
35
|
+
# pass.
|
|
36
|
+
|
|
37
|
+
num_points = len(glyph1.points[ix])
|
|
38
|
+
leeway = 3
|
|
39
|
+
if not reverse and (
|
|
40
|
+
proposed_point <= leeway or proposed_point >= num_points - leeway
|
|
41
|
+
):
|
|
42
|
+
# Try harder
|
|
43
|
+
|
|
44
|
+
# Recover the covariance matrix from the GreenVectors.
|
|
45
|
+
# This is a 2x2 matrix.
|
|
46
|
+
transforms = []
|
|
47
|
+
for vector in (m0Vectors[ix], m1Vectors[ix]):
|
|
48
|
+
meanX = vector[1]
|
|
49
|
+
meanY = vector[2]
|
|
50
|
+
stddevX = vector[3] * 0.5
|
|
51
|
+
stddevY = vector[4] * 0.5
|
|
52
|
+
correlation = vector[5]
|
|
53
|
+
if correlation:
|
|
54
|
+
correlation /= abs(vector[0])
|
|
55
|
+
|
|
56
|
+
# https://cookierobotics.com/007/
|
|
57
|
+
a = stddevX * stddevX # VarianceX
|
|
58
|
+
c = stddevY * stddevY # VarianceY
|
|
59
|
+
b = correlation * stddevX * stddevY # Covariance
|
|
60
|
+
|
|
61
|
+
delta = (((a - c) * 0.5) ** 2 + b * b) ** 0.5
|
|
62
|
+
lambda1 = (a + c) * 0.5 + delta # Major eigenvalue
|
|
63
|
+
lambda2 = (a + c) * 0.5 - delta # Minor eigenvalue
|
|
64
|
+
theta = atan2(lambda1 - a, b) if b != 0 else (pi * 0.5 if a < c else 0)
|
|
65
|
+
trans = Transform()
|
|
66
|
+
# Don't translate here. We are working on the complex-vector
|
|
67
|
+
# that includes more than just the points. It's horrible what
|
|
68
|
+
# we are doing anyway...
|
|
69
|
+
# trans = trans.translate(meanX, meanY)
|
|
70
|
+
trans = trans.rotate(theta)
|
|
71
|
+
trans = trans.scale(sqrt(lambda1), sqrt(lambda2))
|
|
72
|
+
transforms.append(trans)
|
|
73
|
+
|
|
74
|
+
trans = transforms[0]
|
|
75
|
+
new_c0 = (
|
|
76
|
+
[complex(*trans.transformPoint((pt.real, pt.imag))) for pt in c0[0]],
|
|
77
|
+
) + c0[1:]
|
|
78
|
+
trans = transforms[1]
|
|
79
|
+
new_contour1 = []
|
|
80
|
+
for c1 in contour1:
|
|
81
|
+
new_c1 = (
|
|
82
|
+
[
|
|
83
|
+
complex(*trans.transformPoint((pt.real, pt.imag)))
|
|
84
|
+
for pt in c1[0]
|
|
85
|
+
],
|
|
86
|
+
) + c1[1:]
|
|
87
|
+
new_contour1.append(new_c1)
|
|
88
|
+
|
|
89
|
+
# Next few lines duplicate from above.
|
|
90
|
+
costs = [
|
|
91
|
+
vdiff_hypot2_complex(new_c0[0], new_c1[0]) for new_c1 in new_contour1
|
|
92
|
+
]
|
|
93
|
+
min_cost_idx, min_cost = min(enumerate(costs), key=lambda x: x[1])
|
|
94
|
+
first_cost = costs[0]
|
|
95
|
+
if min_cost < first_cost * tolerance:
|
|
96
|
+
# Don't report this
|
|
97
|
+
# min_cost = first_cost
|
|
98
|
+
# reverse = False
|
|
99
|
+
# proposed_point = 0 # new_contour1[min_cost_idx][1]
|
|
100
|
+
pass
|
|
101
|
+
|
|
102
|
+
this_tolerance = min_cost / first_cost if first_cost else 1
|
|
103
|
+
log.debug(
|
|
104
|
+
"test-starting-point: tolerance %g",
|
|
105
|
+
this_tolerance,
|
|
106
|
+
)
|
|
107
|
+
return this_tolerance, proposed_point, reverse
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Interpolate OpenType Layout tables (GDEF / GPOS / GSUB).
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from fontTools.ttLib import TTFont
|
|
6
|
+
from fontTools.varLib import models, VarLibError, load_designspace, load_masters
|
|
7
|
+
from fontTools.varLib.merger import InstancerMerger
|
|
8
|
+
import os.path
|
|
9
|
+
import logging
|
|
10
|
+
from copy import deepcopy
|
|
11
|
+
from pprint import pformat
|
|
12
|
+
|
|
13
|
+
log = logging.getLogger("fontTools.varLib.interpolate_layout")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def interpolate_layout(designspace, loc, master_finder=lambda s: s, mapped=False):
|
|
17
|
+
"""
|
|
18
|
+
Interpolate GPOS from a designspace file and location.
|
|
19
|
+
|
|
20
|
+
If master_finder is set, it should be a callable that takes master
|
|
21
|
+
filename as found in designspace file and map it to master font
|
|
22
|
+
binary as to be opened (eg. .ttf or .otf).
|
|
23
|
+
|
|
24
|
+
If mapped is False (default), then location is mapped using the
|
|
25
|
+
map element of the axes in designspace file. If mapped is True,
|
|
26
|
+
it is assumed that location is in designspace's internal space and
|
|
27
|
+
no mapping is performed.
|
|
28
|
+
"""
|
|
29
|
+
if hasattr(designspace, "sources"): # Assume a DesignspaceDocument
|
|
30
|
+
pass
|
|
31
|
+
else: # Assume a file path
|
|
32
|
+
from fontTools.designspaceLib import DesignSpaceDocument
|
|
33
|
+
|
|
34
|
+
designspace = DesignSpaceDocument.fromfile(designspace)
|
|
35
|
+
|
|
36
|
+
ds = load_designspace(designspace)
|
|
37
|
+
log.info("Building interpolated font")
|
|
38
|
+
|
|
39
|
+
log.info("Loading master fonts")
|
|
40
|
+
master_fonts = load_masters(designspace, master_finder)
|
|
41
|
+
font = deepcopy(master_fonts[ds.base_idx])
|
|
42
|
+
|
|
43
|
+
log.info("Location: %s", pformat(loc))
|
|
44
|
+
if not mapped:
|
|
45
|
+
loc = {name: ds.axes[name].map_forward(v) for name, v in loc.items()}
|
|
46
|
+
log.info("Internal location: %s", pformat(loc))
|
|
47
|
+
loc = models.normalizeLocation(loc, ds.internal_axis_supports)
|
|
48
|
+
log.info("Normalized location: %s", pformat(loc))
|
|
49
|
+
|
|
50
|
+
# Assume single-model for now.
|
|
51
|
+
model = models.VariationModel(ds.normalized_master_locs)
|
|
52
|
+
assert 0 == model.mapping[ds.base_idx]
|
|
53
|
+
|
|
54
|
+
merger = InstancerMerger(font, model, loc)
|
|
55
|
+
|
|
56
|
+
log.info("Building interpolated tables")
|
|
57
|
+
# TODO GSUB/GDEF
|
|
58
|
+
merger.mergeTables(font, master_fonts, ["GPOS"])
|
|
59
|
+
return font
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def main(args=None):
|
|
63
|
+
"""Interpolate GDEF/GPOS/GSUB tables for a point on a designspace"""
|
|
64
|
+
from fontTools import configLogger
|
|
65
|
+
import argparse
|
|
66
|
+
import sys
|
|
67
|
+
|
|
68
|
+
parser = argparse.ArgumentParser(
|
|
69
|
+
"fonttools varLib.interpolate_layout",
|
|
70
|
+
description=main.__doc__,
|
|
71
|
+
)
|
|
72
|
+
parser.add_argument(
|
|
73
|
+
"designspace_filename", metavar="DESIGNSPACE", help="Input TTF files"
|
|
74
|
+
)
|
|
75
|
+
parser.add_argument(
|
|
76
|
+
"locations",
|
|
77
|
+
metavar="LOCATION",
|
|
78
|
+
type=str,
|
|
79
|
+
nargs="+",
|
|
80
|
+
help="Axis locations (e.g. wdth=120",
|
|
81
|
+
)
|
|
82
|
+
parser.add_argument(
|
|
83
|
+
"-o",
|
|
84
|
+
"--output",
|
|
85
|
+
metavar="OUTPUT",
|
|
86
|
+
help="Output font file (defaults to <designspacename>-instance.ttf)",
|
|
87
|
+
)
|
|
88
|
+
parser.add_argument(
|
|
89
|
+
"-l",
|
|
90
|
+
"--loglevel",
|
|
91
|
+
metavar="LEVEL",
|
|
92
|
+
default="INFO",
|
|
93
|
+
help="Logging level (defaults to INFO)",
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
args = parser.parse_args(args)
|
|
97
|
+
|
|
98
|
+
if not args.output:
|
|
99
|
+
args.output = os.path.splitext(args.designspace_filename)[0] + "-instance.ttf"
|
|
100
|
+
|
|
101
|
+
configLogger(level=args.loglevel)
|
|
102
|
+
|
|
103
|
+
finder = lambda s: s.replace("master_ufo", "master_ttf_interpolatable").replace(
|
|
104
|
+
".ufo", ".ttf"
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
loc = {}
|
|
108
|
+
for arg in args.locations:
|
|
109
|
+
tag, val = arg.split("=")
|
|
110
|
+
loc[tag] = float(val)
|
|
111
|
+
|
|
112
|
+
font = interpolate_layout(args.designspace_filename, loc, finder)
|
|
113
|
+
log.info("Saving font %s", args.output)
|
|
114
|
+
font.save(args.output)
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
if __name__ == "__main__":
|
|
118
|
+
import sys
|
|
119
|
+
|
|
120
|
+
if len(sys.argv) > 1:
|
|
121
|
+
sys.exit(main())
|
|
122
|
+
import doctest
|
|
123
|
+
|
|
124
|
+
sys.exit(doctest.testmod().failed)
|