fonttools 4.59.0__cp313-cp313-win32.whl → 4.59.2__cp313-cp313-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.
Potentially problematic release.
This version of fonttools might be problematic. Click here for more details.
- fontTools/__init__.py +1 -1
- fontTools/cffLib/CFF2ToCFF.py +40 -10
- fontTools/cffLib/transforms.py +11 -6
- fontTools/cu2qu/cu2qu.c +760 -653
- fontTools/cu2qu/cu2qu.cp313-win32.pyd +0 -0
- fontTools/cu2qu/cu2qu.py +17 -2
- fontTools/feaLib/builder.py +15 -4
- fontTools/feaLib/lexer.c +30 -16
- fontTools/feaLib/lexer.cp313-win32.pyd +0 -0
- fontTools/feaLib/parser.py +11 -1
- fontTools/feaLib/variableScalar.py +6 -1
- fontTools/misc/bezierTools.c +33 -19
- fontTools/misc/bezierTools.cp313-win32.pyd +0 -0
- fontTools/misc/psCharStrings.py +17 -2
- fontTools/misc/textTools.py +4 -2
- fontTools/pens/momentsPen.c +20 -14
- fontTools/pens/momentsPen.cp313-win32.pyd +0 -0
- fontTools/qu2cu/qu2cu.c +32 -18
- fontTools/qu2cu/qu2cu.cp313-win32.pyd +0 -0
- fontTools/subset/__init__.py +1 -0
- fontTools/ttLib/tables/_a_v_a_r.py +4 -2
- fontTools/ttLib/tables/_g_v_a_r.py +6 -3
- fontTools/ttLib/tables/_h_m_t_x.py +7 -3
- fontTools/ttLib/tables/_n_a_m_e.py +11 -6
- fontTools/varLib/__init__.py +80 -1
- fontTools/varLib/featureVars.py +8 -0
- fontTools/varLib/instancer/__init__.py +120 -22
- fontTools/varLib/iup.c +32 -18
- fontTools/varLib/iup.cp313-win32.pyd +0 -0
- fontTools/varLib/mutator.py +11 -0
- {fonttools-4.59.0.dist-info → fonttools-4.59.2.dist-info}/METADATA +38 -10
- {fonttools-4.59.0.dist-info → fonttools-4.59.2.dist-info}/RECORD +38 -38
- {fonttools-4.59.0.data → fonttools-4.59.2.data}/data/share/man/man1/ttx.1 +0 -0
- {fonttools-4.59.0.dist-info → fonttools-4.59.2.dist-info}/WHEEL +0 -0
- {fonttools-4.59.0.dist-info → fonttools-4.59.2.dist-info}/entry_points.txt +0 -0
- {fonttools-4.59.0.dist-info → fonttools-4.59.2.dist-info}/licenses/LICENSE +0 -0
- {fonttools-4.59.0.dist-info → fonttools-4.59.2.dist-info}/licenses/LICENSE.external +0 -0
- {fonttools-4.59.0.dist-info → fonttools-4.59.2.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""
|
|
1
|
+
"""Partially instantiate a variable font.
|
|
2
2
|
|
|
3
3
|
The module exports an `instantiateVariableFont` function and CLI that allow to
|
|
4
4
|
create full instances (i.e. static fonts) from variable fonts, as well as "partial"
|
|
@@ -36,7 +36,7 @@ If the input location specifies all the axes, the resulting instance is no longe
|
|
|
36
36
|
'variable' (same as using fontools varLib.mutator):
|
|
37
37
|
.. code-block:: pycon
|
|
38
38
|
|
|
39
|
-
>>>
|
|
39
|
+
>>>
|
|
40
40
|
>> instance = instancer.instantiateVariableFont(
|
|
41
41
|
... varfont, {"wght": 700, "wdth": 67.5}
|
|
42
42
|
... )
|
|
@@ -56,8 +56,10 @@ From the console script, this is equivalent to passing `wght=drop` as input.
|
|
|
56
56
|
|
|
57
57
|
This module is similar to fontTools.varLib.mutator, which it's intended to supersede.
|
|
58
58
|
Note that, unlike varLib.mutator, when an axis is not mentioned in the input
|
|
59
|
-
location, the varLib.instancer will keep the axis and the corresponding
|
|
60
|
-
whereas mutator implicitly drops the axis at its default coordinate.
|
|
59
|
+
location, by default the varLib.instancer will keep the axis and the corresponding
|
|
60
|
+
deltas, whereas mutator implicitly drops the axis at its default coordinate.
|
|
61
|
+
To obtain the same behavior as mutator, pass the `static=True` parameter or
|
|
62
|
+
the `--static` CLI option.
|
|
61
63
|
|
|
62
64
|
The module supports all the following "levels" of instancing, which can of
|
|
63
65
|
course be combined:
|
|
@@ -72,7 +74,7 @@ L1
|
|
|
72
74
|
L2
|
|
73
75
|
dropping one or more axes while pinning them at non-default locations;
|
|
74
76
|
.. code-block:: pycon
|
|
75
|
-
|
|
77
|
+
|
|
76
78
|
>>>
|
|
77
79
|
>> font = instancer.instantiateVariableFont(varfont, {"wght": 700})
|
|
78
80
|
|
|
@@ -81,22 +83,18 @@ L3
|
|
|
81
83
|
a new minimum or maximum, potentially -- though not necessarily -- dropping
|
|
82
84
|
entire regions of variations that fall completely outside this new range.
|
|
83
85
|
.. code-block:: pycon
|
|
84
|
-
|
|
86
|
+
|
|
85
87
|
>>>
|
|
86
88
|
>> font = instancer.instantiateVariableFont(varfont, {"wght": (100, 300)})
|
|
87
89
|
|
|
88
90
|
L4
|
|
89
91
|
moving the default location of an axis, by specifying (min,defalt,max) values:
|
|
90
92
|
.. code-block:: pycon
|
|
91
|
-
|
|
93
|
+
|
|
92
94
|
>>>
|
|
93
95
|
>> font = instancer.instantiateVariableFont(varfont, {"wght": (100, 300, 700)})
|
|
94
96
|
|
|
95
|
-
|
|
96
|
-
are supported, but support for CFF2 variable fonts will be added soon.
|
|
97
|
-
|
|
98
|
-
The discussion and implementation of these features are tracked at
|
|
99
|
-
https://github.com/fonttools/fonttools/issues/1537
|
|
97
|
+
Both TrueType-flavored (glyf+gvar) variable and CFF2 variable fonts are supported.
|
|
100
98
|
"""
|
|
101
99
|
|
|
102
100
|
from fontTools.misc.fixedTools import (
|
|
@@ -120,6 +118,7 @@ from fontTools.cffLib.specializer import (
|
|
|
120
118
|
specializeCommands,
|
|
121
119
|
generalizeCommands,
|
|
122
120
|
)
|
|
121
|
+
from fontTools.cffLib.CFF2ToCFF import convertCFF2ToCFF
|
|
123
122
|
from fontTools.varLib import builder
|
|
124
123
|
from fontTools.varLib.mvar import MVAR_ENTRIES
|
|
125
124
|
from fontTools.varLib.merger import MutatorMerger
|
|
@@ -136,6 +135,7 @@ from enum import IntEnum
|
|
|
136
135
|
import logging
|
|
137
136
|
import os
|
|
138
137
|
import re
|
|
138
|
+
import io
|
|
139
139
|
from typing import Dict, Iterable, Mapping, Optional, Sequence, Tuple, Union
|
|
140
140
|
import warnings
|
|
141
141
|
|
|
@@ -433,7 +433,27 @@ class AxisLimits(_BaseAxisLimits):
|
|
|
433
433
|
|
|
434
434
|
avarSegments = {}
|
|
435
435
|
if usingAvar and "avar" in varfont:
|
|
436
|
-
|
|
436
|
+
avar = varfont["avar"]
|
|
437
|
+
avarSegments = avar.segments
|
|
438
|
+
|
|
439
|
+
if getattr(avar, "majorVersion", 1) >= 2 and avar.table.VarStore:
|
|
440
|
+
pinnedAxes = set(self.pinnedLocation())
|
|
441
|
+
if not pinnedAxes.issuperset(avarSegments):
|
|
442
|
+
raise NotImplementedError(
|
|
443
|
+
"Partial-instancing avar2 table is not supported"
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
# TODO: Merge this with the main codepath.
|
|
447
|
+
|
|
448
|
+
# Full instancing of avar2 font. Use avar table to normalize location and return.
|
|
449
|
+
location = self.pinnedLocation()
|
|
450
|
+
location = {
|
|
451
|
+
tag: normalize(value, axes[tag], avarSegments.get(tag, None))
|
|
452
|
+
for tag, value in location.items()
|
|
453
|
+
}
|
|
454
|
+
return NormalizedAxisLimits(
|
|
455
|
+
**avar.renormalizeLocation(location, varfont, dropZeroes=False)
|
|
456
|
+
)
|
|
437
457
|
|
|
438
458
|
normalizedLimits = {}
|
|
439
459
|
|
|
@@ -643,7 +663,11 @@ def instantiateCFF2(
|
|
|
643
663
|
# the Private dicts.
|
|
644
664
|
#
|
|
645
665
|
# Then prune unused things and possibly drop the VarStore if it's empty.
|
|
646
|
-
#
|
|
666
|
+
#
|
|
667
|
+
# If the downgrade parameter is True, no actual downgrading is done, but
|
|
668
|
+
# the function returns True if the VarStore was empty after instantiation,
|
|
669
|
+
# and hence a downgrade to CFF is possible. In all other cases it returns
|
|
670
|
+
# False.
|
|
647
671
|
|
|
648
672
|
log.info("Instantiating CFF2 table")
|
|
649
673
|
|
|
@@ -882,9 +906,9 @@ def instantiateCFF2(
|
|
|
882
906
|
del private.vstore
|
|
883
907
|
|
|
884
908
|
if downgrade:
|
|
885
|
-
|
|
909
|
+
return True
|
|
886
910
|
|
|
887
|
-
|
|
911
|
+
return False
|
|
888
912
|
|
|
889
913
|
|
|
890
914
|
def _instantiateGvarGlyph(
|
|
@@ -1116,7 +1140,8 @@ def _instantiateVHVAR(varfont, axisLimits, tableFields, *, round=round):
|
|
|
1116
1140
|
varIdx = advMapping.mapping[glyphName]
|
|
1117
1141
|
else:
|
|
1118
1142
|
varIdx = varfont.getGlyphID(glyphName)
|
|
1119
|
-
|
|
1143
|
+
delta = round(defaultDeltas[varIdx])
|
|
1144
|
+
metrics[glyphName] = (max(0, advanceWidth + delta), sb)
|
|
1120
1145
|
|
|
1121
1146
|
if (
|
|
1122
1147
|
tableTag == "VVAR"
|
|
@@ -1377,12 +1402,55 @@ def _isValidAvarSegmentMap(axisTag, segmentMap):
|
|
|
1377
1402
|
return True
|
|
1378
1403
|
|
|
1379
1404
|
|
|
1405
|
+
def downgradeCFF2ToCFF(varfont):
|
|
1406
|
+
# Save these properties
|
|
1407
|
+
recalcTimestamp = varfont.recalcTimestamp
|
|
1408
|
+
recalcBBoxes = varfont.recalcBBoxes
|
|
1409
|
+
|
|
1410
|
+
# Disable them
|
|
1411
|
+
varfont.recalcTimestamp = False
|
|
1412
|
+
varfont.recalcBBoxes = False
|
|
1413
|
+
|
|
1414
|
+
# Save to memory, reload, downgrade and save again, reload.
|
|
1415
|
+
# We do this dance because the convertCFF2ToCFF changes glyph
|
|
1416
|
+
# names, so following save would fail if any other table was
|
|
1417
|
+
# loaded and referencing glyph names.
|
|
1418
|
+
#
|
|
1419
|
+
# The second save+load is unfortunate but also necessary.
|
|
1420
|
+
|
|
1421
|
+
stream = io.BytesIO()
|
|
1422
|
+
log.info("Saving CFF2 font to memory for downgrade")
|
|
1423
|
+
varfont.save(stream)
|
|
1424
|
+
stream.seek(0)
|
|
1425
|
+
varfont = TTFont(stream, recalcTimestamp=False, recalcBBoxes=False)
|
|
1426
|
+
|
|
1427
|
+
convertCFF2ToCFF(varfont)
|
|
1428
|
+
|
|
1429
|
+
stream = io.BytesIO()
|
|
1430
|
+
log.info("Saving downgraded CFF font to memory")
|
|
1431
|
+
varfont.save(stream)
|
|
1432
|
+
stream.seek(0)
|
|
1433
|
+
varfont = TTFont(stream, recalcTimestamp=False, recalcBBoxes=False)
|
|
1434
|
+
|
|
1435
|
+
# Uncomment, to see test all tables can be loaded. This fails without
|
|
1436
|
+
# the extra save+load above.
|
|
1437
|
+
"""
|
|
1438
|
+
for tag in varfont.keys():
|
|
1439
|
+
print("Loading", tag)
|
|
1440
|
+
varfont[tag]
|
|
1441
|
+
"""
|
|
1442
|
+
|
|
1443
|
+
# Restore them
|
|
1444
|
+
varfont.recalcTimestamp = recalcTimestamp
|
|
1445
|
+
varfont.recalcBBoxes = recalcBBoxes
|
|
1446
|
+
|
|
1447
|
+
return varfont
|
|
1448
|
+
|
|
1449
|
+
|
|
1380
1450
|
def instantiateAvar(varfont, axisLimits):
|
|
1381
1451
|
# 'axisLimits' dict must contain user-space (non-normalized) coordinates.
|
|
1382
1452
|
|
|
1383
1453
|
avar = varfont["avar"]
|
|
1384
|
-
if getattr(avar, "majorVersion", 1) >= 2 and avar.table.VarStore:
|
|
1385
|
-
raise NotImplementedError("avar table with VarStore is not supported")
|
|
1386
1454
|
|
|
1387
1455
|
segments = avar.segments
|
|
1388
1456
|
|
|
@@ -1393,6 +1461,9 @@ def instantiateAvar(varfont, axisLimits):
|
|
|
1393
1461
|
del varfont["avar"]
|
|
1394
1462
|
return
|
|
1395
1463
|
|
|
1464
|
+
if getattr(avar, "majorVersion", 1) >= 2 and avar.table.VarStore:
|
|
1465
|
+
raise NotImplementedError("avar table with VarStore is not supported")
|
|
1466
|
+
|
|
1396
1467
|
log.info("Instantiating avar table")
|
|
1397
1468
|
for axis in pinnedAxes:
|
|
1398
1469
|
if axis in segments:
|
|
@@ -1594,6 +1665,7 @@ def instantiateVariableFont(
|
|
|
1594
1665
|
updateFontNames=False,
|
|
1595
1666
|
*,
|
|
1596
1667
|
downgradeCFF2=False,
|
|
1668
|
+
static=False,
|
|
1597
1669
|
):
|
|
1598
1670
|
"""Instantiate variable font, either fully or partially.
|
|
1599
1671
|
|
|
@@ -1637,12 +1709,23 @@ def instantiateVariableFont(
|
|
|
1637
1709
|
software that does not support CFF2. Defaults to False. Note that this
|
|
1638
1710
|
operation also removes overlaps within glyph shapes, as CFF does not support
|
|
1639
1711
|
overlaps but CFF2 does.
|
|
1712
|
+
static (bool): if True, generate a full instance (static font) instead of a partial
|
|
1713
|
+
instance (variable font).
|
|
1640
1714
|
"""
|
|
1641
1715
|
# 'overlap' used to be bool and is now enum; for backward compat keep accepting bool
|
|
1642
1716
|
overlap = OverlapMode(int(overlap))
|
|
1643
1717
|
|
|
1644
1718
|
sanityCheckVariableTables(varfont)
|
|
1645
1719
|
|
|
1720
|
+
if static:
|
|
1721
|
+
unspecified = []
|
|
1722
|
+
for axis in varfont["fvar"].axes:
|
|
1723
|
+
if axis.axisTag not in axisLimits:
|
|
1724
|
+
axisLimits[axis.axisTag] = None
|
|
1725
|
+
unspecified.append(axis.axisTag)
|
|
1726
|
+
if unspecified:
|
|
1727
|
+
log.info("Pinning unspecified axes to default: %s", unspecified)
|
|
1728
|
+
|
|
1646
1729
|
axisLimits = AxisLimits(axisLimits).limitAxesAndPopulateDefaults(varfont)
|
|
1647
1730
|
|
|
1648
1731
|
log.info("Restricted limits: %s", axisLimits)
|
|
@@ -1665,7 +1748,9 @@ def instantiateVariableFont(
|
|
|
1665
1748
|
instantiateVARC(varfont, normalizedLimits)
|
|
1666
1749
|
|
|
1667
1750
|
if "CFF2" in varfont:
|
|
1668
|
-
instantiateCFF2(
|
|
1751
|
+
downgradeCFF2 = instantiateCFF2(
|
|
1752
|
+
varfont, normalizedLimits, downgrade=downgradeCFF2
|
|
1753
|
+
)
|
|
1669
1754
|
|
|
1670
1755
|
if "gvar" in varfont:
|
|
1671
1756
|
instantiateGvar(varfont, normalizedLimits, optimize=optimize)
|
|
@@ -1720,6 +1805,12 @@ def instantiateVariableFont(
|
|
|
1720
1805
|
# name table has been updated.
|
|
1721
1806
|
setRibbiBits(varfont)
|
|
1722
1807
|
|
|
1808
|
+
if downgradeCFF2:
|
|
1809
|
+
origVarfont = varfont
|
|
1810
|
+
varfont = downgradeCFF2ToCFF(varfont)
|
|
1811
|
+
if inplace:
|
|
1812
|
+
origVarfont.__dict__ = varfont.__dict__.copy()
|
|
1813
|
+
|
|
1723
1814
|
return varfont
|
|
1724
1815
|
|
|
1725
1816
|
|
|
@@ -1826,6 +1917,12 @@ def parseArgs(args):
|
|
|
1826
1917
|
default=None,
|
|
1827
1918
|
help="Output instance TTF file (default: INPUT-instance.ttf).",
|
|
1828
1919
|
)
|
|
1920
|
+
parser.add_argument(
|
|
1921
|
+
"--static",
|
|
1922
|
+
dest="static",
|
|
1923
|
+
action="store_true",
|
|
1924
|
+
help="Make a static font: pin unspecified axes to their default location.",
|
|
1925
|
+
)
|
|
1829
1926
|
parser.add_argument(
|
|
1830
1927
|
"--no-optimize",
|
|
1831
1928
|
dest="optimize",
|
|
@@ -1923,13 +2020,13 @@ def main(args=None):
|
|
|
1923
2020
|
recalcBBoxes=options.recalc_bounds,
|
|
1924
2021
|
)
|
|
1925
2022
|
|
|
1926
|
-
isFullInstance = {
|
|
2023
|
+
isFullInstance = options.static or {
|
|
1927
2024
|
axisTag
|
|
1928
2025
|
for axisTag, limit in axisLimits.items()
|
|
1929
2026
|
if limit is None or limit[0] == limit[2]
|
|
1930
2027
|
}.issuperset(axis.axisTag for axis in varfont["fvar"].axes)
|
|
1931
2028
|
|
|
1932
|
-
instantiateVariableFont(
|
|
2029
|
+
varfont = instantiateVariableFont(
|
|
1933
2030
|
varfont,
|
|
1934
2031
|
axisLimits,
|
|
1935
2032
|
inplace=True,
|
|
@@ -1937,6 +2034,7 @@ def main(args=None):
|
|
|
1937
2034
|
overlap=options.overlap,
|
|
1938
2035
|
updateFontNames=options.update_name_table,
|
|
1939
2036
|
downgradeCFF2=options.downgrade_cff2,
|
|
2037
|
+
static=options.static,
|
|
1940
2038
|
)
|
|
1941
2039
|
|
|
1942
2040
|
suffix = "-instance" if isFullInstance else "-partial"
|
fontTools/varLib/iup.c
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Generated by Cython 3.1.
|
|
1
|
+
/* Generated by Cython 3.1.3 */
|
|
2
2
|
|
|
3
3
|
/* BEGIN: Cython Metadata
|
|
4
4
|
{
|
|
@@ -26,8 +26,8 @@ END: Cython Metadata */
|
|
|
26
26
|
#elif PY_VERSION_HEX < 0x03080000
|
|
27
27
|
#error Cython requires Python 3.8+.
|
|
28
28
|
#else
|
|
29
|
-
#define __PYX_ABI_VERSION "
|
|
30
|
-
#define CYTHON_HEX_VERSION
|
|
29
|
+
#define __PYX_ABI_VERSION "3_1_3"
|
|
30
|
+
#define CYTHON_HEX_VERSION 0x030103F0
|
|
31
31
|
#define CYTHON_FUTURE_DIVISION 1
|
|
32
32
|
/* CModulePreamble */
|
|
33
33
|
#include <stddef.h>
|
|
@@ -390,6 +390,9 @@ END: Cython Metadata */
|
|
|
390
390
|
enum { __pyx_check_sizeof_voidp = 1 / (int)(SIZEOF_VOID_P == sizeof(void*)) };
|
|
391
391
|
#endif
|
|
392
392
|
#endif
|
|
393
|
+
#ifndef CYTHON_LOCK_AND_GIL_DEADLOCK_AVOIDANCE_TIME
|
|
394
|
+
#define CYTHON_LOCK_AND_GIL_DEADLOCK_AVOIDANCE_TIME 100
|
|
395
|
+
#endif
|
|
393
396
|
#ifndef __has_attribute
|
|
394
397
|
#define __has_attribute(x) 0
|
|
395
398
|
#endif
|
|
@@ -2141,7 +2144,7 @@ static int __Pyx_IternextUnpackEndCheck(PyObject *retval, Py_ssize_t expected);
|
|
|
2141
2144
|
static PyObject *__Pyx_PyLong_AbsNeg(PyObject *num);
|
|
2142
2145
|
#define __Pyx_PyNumber_Absolute(x)\
|
|
2143
2146
|
((likely(PyLong_CheckExact(x))) ?\
|
|
2144
|
-
(likely(__Pyx_PyLong_IsNonNeg(x)) ? (
|
|
2147
|
+
(likely(__Pyx_PyLong_IsNonNeg(x)) ? __Pyx_NewRef(x) : __Pyx_PyLong_AbsNeg(x)) :\
|
|
2145
2148
|
PyNumber_Absolute(x))
|
|
2146
2149
|
#else
|
|
2147
2150
|
#define __Pyx_PyNumber_Absolute(x) PyNumber_Absolute(x)
|
|
@@ -12093,16 +12096,15 @@ static int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate) {
|
|
|
12093
12096
|
return -1;
|
|
12094
12097
|
}
|
|
12095
12098
|
/* #### Code section: init_codeobjects ### */
|
|
12096
|
-
|
|
12097
|
-
|
|
12098
|
-
|
|
12099
|
-
|
|
12100
|
-
|
|
12101
|
-
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
|
|
12105
|
-
} __Pyx_PyCode_New_function_description;
|
|
12099
|
+
typedef struct {
|
|
12100
|
+
unsigned int argcount : 3;
|
|
12101
|
+
unsigned int num_posonly_args : 1;
|
|
12102
|
+
unsigned int num_kwonly_args : 1;
|
|
12103
|
+
unsigned int nlocals : 5;
|
|
12104
|
+
unsigned int flags : 10;
|
|
12105
|
+
unsigned int first_line : 9;
|
|
12106
|
+
unsigned int line_table_length : 14;
|
|
12107
|
+
} __Pyx_PyCode_New_function_description;
|
|
12106
12108
|
/* NewCodeObj.proto */
|
|
12107
12109
|
static PyObject* __Pyx_PyCode_New(
|
|
12108
12110
|
const __Pyx_PyCode_New_function_description descr,
|
|
@@ -14329,7 +14331,7 @@ static PyObject *__Pyx_PyLong_AbsNeg(PyObject *n) {
|
|
|
14329
14331
|
PyObject *copy = _PyLong_Copy((PyLongObject*)n);
|
|
14330
14332
|
if (likely(copy)) {
|
|
14331
14333
|
#if PY_VERSION_HEX >= 0x030C00A7
|
|
14332
|
-
((PyLongObject*)copy)->long_value.lv_tag
|
|
14334
|
+
((PyLongObject*)copy)->long_value.lv_tag ^= ((PyLongObject*)copy)->long_value.lv_tag & _PyLong_SIGN_MASK;
|
|
14333
14335
|
#else
|
|
14334
14336
|
__Pyx_SET_SIZE(copy, -Py_SIZE(copy));
|
|
14335
14337
|
#endif
|
|
@@ -14942,6 +14944,7 @@ static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject
|
|
|
14942
14944
|
changed = 1;
|
|
14943
14945
|
}
|
|
14944
14946
|
#endif // CYTHON_METH_FASTCALL
|
|
14947
|
+
#if !CYTHON_COMPILING_IN_PYPY
|
|
14945
14948
|
else if (strcmp(memb->name, "__module__") == 0) {
|
|
14946
14949
|
PyObject *descr;
|
|
14947
14950
|
assert(memb->type == T_OBJECT);
|
|
@@ -14956,11 +14959,13 @@ static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject
|
|
|
14956
14959
|
}
|
|
14957
14960
|
changed = 1;
|
|
14958
14961
|
}
|
|
14962
|
+
#endif // !CYTHON_COMPILING_IN_PYPY
|
|
14959
14963
|
}
|
|
14960
14964
|
memb++;
|
|
14961
14965
|
}
|
|
14962
14966
|
}
|
|
14963
14967
|
#endif // !CYTHON_COMPILING_IN_LIMITED_API
|
|
14968
|
+
#if !CYTHON_COMPILING_IN_PYPY
|
|
14964
14969
|
slot = spec->slots;
|
|
14965
14970
|
while (slot && slot->slot && slot->slot != Py_tp_getset)
|
|
14966
14971
|
slot++;
|
|
@@ -14992,6 +14997,7 @@ static int __Pyx_fix_up_extension_type_from_spec(PyType_Spec *spec, PyTypeObject
|
|
|
14992
14997
|
++getset;
|
|
14993
14998
|
}
|
|
14994
14999
|
}
|
|
15000
|
+
#endif // !CYTHON_COMPILING_IN_PYPY
|
|
14995
15001
|
if (changed)
|
|
14996
15002
|
PyType_Modified(type);
|
|
14997
15003
|
#endif // PY_VERSION_HEX > 0x030900B1
|
|
@@ -15090,6 +15096,13 @@ try_unpack:
|
|
|
15090
15096
|
|
|
15091
15097
|
/* PyObjectCallMethod0 */
|
|
15092
15098
|
static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name) {
|
|
15099
|
+
#if CYTHON_VECTORCALL && (__PYX_LIMITED_VERSION_HEX >= 0x030C0000 || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x03090000))
|
|
15100
|
+
PyObject *args[1] = {obj};
|
|
15101
|
+
(void) __Pyx_PyObject_GetMethod;
|
|
15102
|
+
(void) __Pyx_PyObject_CallOneArg;
|
|
15103
|
+
(void) __Pyx_PyObject_CallNoArg;
|
|
15104
|
+
return PyObject_VectorcallMethod(method_name, args, 1 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL);
|
|
15105
|
+
#else
|
|
15093
15106
|
PyObject *method = NULL, *result = NULL;
|
|
15094
15107
|
int is_method = __Pyx_PyObject_GetMethod(obj, method_name, &method);
|
|
15095
15108
|
if (likely(is_method)) {
|
|
@@ -15102,6 +15115,7 @@ static PyObject* __Pyx_PyObject_CallMethod0(PyObject* obj, PyObject* method_name
|
|
|
15102
15115
|
Py_DECREF(method);
|
|
15103
15116
|
bad:
|
|
15104
15117
|
return result;
|
|
15118
|
+
#endif
|
|
15105
15119
|
}
|
|
15106
15120
|
|
|
15107
15121
|
/* ValidateBasesTuple */
|
|
@@ -15489,7 +15503,7 @@ bad:
|
|
|
15489
15503
|
}
|
|
15490
15504
|
|
|
15491
15505
|
/* CommonTypesMetaclass */
|
|
15492
|
-
PyObject* __pyx_CommonTypesMetaclass_get_module(CYTHON_UNUSED PyObject *self, CYTHON_UNUSED void* context) {
|
|
15506
|
+
static PyObject* __pyx_CommonTypesMetaclass_get_module(CYTHON_UNUSED PyObject *self, CYTHON_UNUSED void* context) {
|
|
15493
15507
|
return PyUnicode_FromString(__PYX_ABI_MODULE_NAME);
|
|
15494
15508
|
}
|
|
15495
15509
|
static PyGetSetDef __pyx_CommonTypesMetaclass_getset[] = {
|
|
@@ -17939,7 +17953,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyObject_Call2Args(PyObject* function, PyOb
|
|
|
17939
17953
|
}
|
|
17940
17954
|
|
|
17941
17955
|
/* PyObjectCallMethod1 */
|
|
17942
|
-
#if !(CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C0000)
|
|
17956
|
+
#if !(CYTHON_VECTORCALL && (__PYX_LIMITED_VERSION_HEX >= 0x030C0000 || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x03090000)))
|
|
17943
17957
|
static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) {
|
|
17944
17958
|
PyObject *result = __Pyx_PyObject_CallOneArg(method, arg);
|
|
17945
17959
|
Py_DECREF(method);
|
|
@@ -17947,7 +17961,7 @@ static PyObject* __Pyx__PyObject_CallMethod1(PyObject* method, PyObject* arg) {
|
|
|
17947
17961
|
}
|
|
17948
17962
|
#endif
|
|
17949
17963
|
static PyObject* __Pyx_PyObject_CallMethod1(PyObject* obj, PyObject* method_name, PyObject* arg) {
|
|
17950
|
-
#if CYTHON_VECTORCALL && __PYX_LIMITED_VERSION_HEX >= 0x030C0000
|
|
17964
|
+
#if CYTHON_VECTORCALL && (__PYX_LIMITED_VERSION_HEX >= 0x030C0000 || (!CYTHON_COMPILING_IN_LIMITED_API && PY_VERSION_HEX >= 0x03090000))
|
|
17951
17965
|
PyObject *args[2] = {obj, arg};
|
|
17952
17966
|
(void) __Pyx_PyObject_GetMethod;
|
|
17953
17967
|
(void) __Pyx_PyObject_CallOneArg;
|
|
Binary file
|
fontTools/varLib/mutator.py
CHANGED
|
@@ -4,9 +4,16 @@ Instantiate a variation font. Run, eg:
|
|
|
4
4
|
.. code-block:: sh
|
|
5
5
|
|
|
6
6
|
$ fonttools varLib.mutator ./NotoSansArabic-VF.ttf wght=140 wdth=85
|
|
7
|
+
|
|
8
|
+
.. warning::
|
|
9
|
+
``fontTools.varLib.mutator`` is deprecated in favor of :mod:`fontTools.varLib.instancer`
|
|
10
|
+
which provides equivalent full instancing and also supports partial instancing.
|
|
11
|
+
Please migrate CLI usage to ``fonttools varLib.instancer`` and API usage to
|
|
12
|
+
:func:`fontTools.varLib.instancer.instantiateVariableFont`.
|
|
7
13
|
"""
|
|
8
14
|
|
|
9
15
|
from fontTools.misc.fixedTools import floatToFixedToFloat, floatToFixed
|
|
16
|
+
from fontTools.misc.loggingTools import deprecateFunction
|
|
10
17
|
from fontTools.misc.roundTools import otRound
|
|
11
18
|
from fontTools.pens.boundsPen import BoundsPen
|
|
12
19
|
from fontTools.ttLib import TTFont, newTable
|
|
@@ -159,6 +166,10 @@ def interpolate_cff2_metrics(varfont, topDict, glyphOrder, loc):
|
|
|
159
166
|
hmtx[gname] = tuple(entry)
|
|
160
167
|
|
|
161
168
|
|
|
169
|
+
@deprecateFunction(
|
|
170
|
+
"use fontTools.varLib.instancer.instantiateVariableFont instead "
|
|
171
|
+
"for either full or partial instancing",
|
|
172
|
+
)
|
|
162
173
|
def instantiateVariableFont(varfont, location, inplace=False, overlap=True):
|
|
163
174
|
"""Generate a static instance from a variable TTFont and a dictionary
|
|
164
175
|
defining the desired location along the variable font's axes.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fonttools
|
|
3
|
-
Version: 4.59.
|
|
3
|
+
Version: 4.59.2
|
|
4
4
|
Summary: Tools to manipulate font files
|
|
5
5
|
Home-page: http://github.com/fonttools/fonttools
|
|
6
6
|
Author: Just van Rossum
|
|
@@ -168,15 +168,6 @@ are required to unlock the extra features named "ufo", etc.
|
|
|
168
168
|
|
|
169
169
|
*Extra:* ``lxml``
|
|
170
170
|
|
|
171
|
-
- ``Lib/fontTools/ufoLib``
|
|
172
|
-
|
|
173
|
-
Package for reading and writing UFO source files; it requires:
|
|
174
|
-
|
|
175
|
-
* `fs <https://pypi.org/pypi/fs>`__: (aka ``pyfilesystem2``) filesystem
|
|
176
|
-
abstraction layer.
|
|
177
|
-
|
|
178
|
-
*Extra:* ``ufo``
|
|
179
|
-
|
|
180
171
|
- ``Lib/fontTools/ttLib/woff2.py``
|
|
181
172
|
|
|
182
173
|
Module to compress/decompress WOFF 2.0 web fonts; it requires:
|
|
@@ -269,6 +260,17 @@ are required to unlock the extra features named "ufo", etc.
|
|
|
269
260
|
|
|
270
261
|
*Extra:* ``pathops``
|
|
271
262
|
|
|
263
|
+
- ``Lib/fontTools/ufoLib``
|
|
264
|
+
|
|
265
|
+
Package for reading and writing UFO source files; if available, it will use:
|
|
266
|
+
|
|
267
|
+
* `fs <https://pypi.org/pypi/fs>`__: (aka ``pyfilesystem2``) filesystem abstraction layer
|
|
268
|
+
|
|
269
|
+
for reading and writing UFOs to the local filesystem or zip files (.ufoz), instead of
|
|
270
|
+
the built-in ``fontTools.misc.filesystem`` package.
|
|
271
|
+
The reader and writer classes can in theory also accept any object compatible the
|
|
272
|
+
``fs.base.FS`` interface, although not all have been tested.
|
|
273
|
+
|
|
272
274
|
- ``Lib/fontTools/pens/cocoaPen.py`` and ``Lib/fontTools/pens/quartzPen.py``
|
|
273
275
|
|
|
274
276
|
Pens for drawing glyphs with Cocoa ``NSBezierPath`` or ``CGPath`` require:
|
|
@@ -386,6 +388,32 @@ Have fun!
|
|
|
386
388
|
Changelog
|
|
387
389
|
~~~~~~~~~
|
|
388
390
|
|
|
391
|
+
4.59.2 (released 2025-08-27)
|
|
392
|
+
----------------------------
|
|
393
|
+
|
|
394
|
+
- [varLib] Clear ``USE_MY_METRICS`` component flags when inconsistent across masters (#3912).
|
|
395
|
+
- [varLib.instancer] Avoid negative advance width/height values when instatiating HVAR/VVAR,
|
|
396
|
+
(unlikely in well-behaved fonts) (#3918).
|
|
397
|
+
- [subset] Fix shaping behaviour when pruning empty mark sets (#3915, harfbuzz/harfbuzz#5499).
|
|
398
|
+
- [cu2qu] Fixed ``dot()`` product of perpendicular vectors not always returning exactly 0.0
|
|
399
|
+
in all Python implementations (#3911)
|
|
400
|
+
- [varLib.instancer] Implemented fully-instantiating ``avar2`` fonts (#3909).
|
|
401
|
+
- [feaLib] Allow float values in ``VariableScalar``'s axis locations (#3906, #3907).
|
|
402
|
+
- [cu2qu] Handle special case in ``calc_intersect`` for degenerate cubic curves where 3 to 4
|
|
403
|
+
control points are equal (#3904).
|
|
404
|
+
|
|
405
|
+
4.59.1 (released 2025-08-14)
|
|
406
|
+
----------------------------
|
|
407
|
+
|
|
408
|
+
- [featureVars] Update OS/2.usMaxContext if possible after addFeatureVariationsRaw (#3894).
|
|
409
|
+
- [vhmtx] raise TTLibError('not enough data...') when hmtx/vmtx are truncated (#3843, #3901).
|
|
410
|
+
- [feaLib] Combine duplicate features that have the same set of lookups regardless of the order in which those lookups are added to the feature (#3895).
|
|
411
|
+
- [varLib] Deprecate ``varLib.mutator`` in favor of ``varLib.instancer``. The latter
|
|
412
|
+
provides equivalent full (static font) instancing in addition to partial VF instancing.
|
|
413
|
+
CLI users should replace ``fonttools varLib.mutator`` with ``fonttools varLib.instancer``.
|
|
414
|
+
API users should migrate to ``fontTools.varLib.instancer.instantiateVariableFont`` (#2680).
|
|
415
|
+
|
|
416
|
+
|
|
389
417
|
4.59.0 (released 2025-07-16)
|
|
390
418
|
----------------------------
|
|
391
419
|
|