fonttools 4.59.1__cp312-cp312-win_amd64.whl → 4.60.0__cp312-cp312-win_amd64.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/annotations.py +30 -0
- fontTools/cu2qu/cu2qu.c +1185 -971
- fontTools/cu2qu/cu2qu.cp312-win_amd64.pyd +0 -0
- fontTools/cu2qu/cu2qu.py +36 -4
- fontTools/feaLib/builder.py +9 -3
- fontTools/feaLib/lexer.c +18 -12
- fontTools/feaLib/lexer.cp312-win_amd64.pyd +0 -0
- fontTools/feaLib/parser.py +11 -1
- fontTools/feaLib/variableScalar.py +6 -1
- fontTools/misc/bezierTools.c +18 -12
- fontTools/misc/bezierTools.cp312-win_amd64.pyd +0 -0
- fontTools/misc/enumTools.py +23 -0
- fontTools/misc/textTools.py +4 -2
- fontTools/pens/filterPen.py +218 -26
- fontTools/pens/momentsPen.c +18 -12
- fontTools/pens/momentsPen.cp312-win_amd64.pyd +0 -0
- fontTools/pens/pointPen.py +40 -6
- fontTools/qu2cu/qu2cu.c +30 -16
- fontTools/qu2cu/qu2cu.cp312-win_amd64.pyd +0 -0
- fontTools/subset/__init__.py +1 -0
- fontTools/ttLib/tables/_a_v_a_r.py +4 -2
- fontTools/ttLib/tables/_n_a_m_e.py +11 -6
- fontTools/ttLib/tables/_p_o_s_t.py +5 -5
- fontTools/ufoLib/__init__.py +279 -176
- fontTools/ufoLib/converters.py +14 -5
- fontTools/ufoLib/filenames.py +16 -6
- fontTools/ufoLib/glifLib.py +286 -190
- fontTools/ufoLib/kerning.py +32 -12
- fontTools/ufoLib/utils.py +41 -13
- fontTools/ufoLib/validators.py +121 -97
- fontTools/varLib/__init__.py +80 -1
- 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.py → avar/unbuild.py} +70 -59
- fontTools/varLib/avarPlanner.py +3 -999
- fontTools/varLib/instancer/__init__.py +56 -18
- fontTools/varLib/interpolatableHelpers.py +3 -0
- fontTools/varLib/iup.c +24 -14
- fontTools/varLib/iup.cp312-win_amd64.pyd +0 -0
- {fonttools-4.59.1.dist-info → fonttools-4.60.0.dist-info}/METADATA +43 -2
- {fonttools-4.59.1.dist-info → fonttools-4.60.0.dist-info}/RECORD +51 -44
- {fonttools-4.59.1.data → fonttools-4.60.0.data}/data/share/man/man1/ttx.1 +0 -0
- {fonttools-4.59.1.dist-info → fonttools-4.60.0.dist-info}/WHEEL +0 -0
- {fonttools-4.59.1.dist-info → fonttools-4.60.0.dist-info}/entry_points.txt +0 -0
- {fonttools-4.59.1.dist-info → fonttools-4.60.0.dist-info}/licenses/LICENSE +0 -0
- {fonttools-4.59.1.dist-info → fonttools-4.60.0.dist-info}/licenses/LICENSE.external +0 -0
- {fonttools-4.59.1.dist-info → fonttools-4.60.0.dist-info}/top_level.txt +0 -0
fontTools/pens/pointPen.py
CHANGED
|
@@ -17,6 +17,7 @@ from __future__ import annotations
|
|
|
17
17
|
import math
|
|
18
18
|
from typing import Any, Dict, List, Optional, Tuple
|
|
19
19
|
|
|
20
|
+
from fontTools.misc.enumTools import StrEnum
|
|
20
21
|
from fontTools.misc.loggingTools import LogMixin
|
|
21
22
|
from fontTools.misc.transform import DecomposedTransform, Identity
|
|
22
23
|
from fontTools.pens.basePen import AbstractPen, MissingComponentError, PenError
|
|
@@ -28,6 +29,7 @@ __all__ = [
|
|
|
28
29
|
"SegmentToPointPen",
|
|
29
30
|
"GuessSmoothPointPen",
|
|
30
31
|
"ReverseContourPointPen",
|
|
32
|
+
"ReverseFlipped",
|
|
31
33
|
]
|
|
32
34
|
|
|
33
35
|
# Some type aliases to make it easier below
|
|
@@ -39,6 +41,19 @@ SegmentType = Optional[str]
|
|
|
39
41
|
SegmentList = List[Tuple[SegmentType, SegmentPointList]]
|
|
40
42
|
|
|
41
43
|
|
|
44
|
+
class ReverseFlipped(StrEnum):
|
|
45
|
+
"""How to handle flipped components during decomposition.
|
|
46
|
+
|
|
47
|
+
NO: Don't reverse flipped components
|
|
48
|
+
KEEP_START: Reverse flipped components, keeping original starting point
|
|
49
|
+
ON_CURVE_FIRST: Reverse flipped components, ensuring first point is on-curve
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
NO = "no"
|
|
53
|
+
KEEP_START = "keep_start"
|
|
54
|
+
ON_CURVE_FIRST = "on_curve_first"
|
|
55
|
+
|
|
56
|
+
|
|
42
57
|
class AbstractPointPen:
|
|
43
58
|
"""Baseclass for all PointPens."""
|
|
44
59
|
|
|
@@ -559,15 +574,20 @@ class DecomposingPointPen(LogMixin, AbstractPointPen):
|
|
|
559
574
|
glyphSet,
|
|
560
575
|
*args,
|
|
561
576
|
skipMissingComponents=None,
|
|
562
|
-
reverseFlipped=False,
|
|
577
|
+
reverseFlipped: bool | ReverseFlipped = False,
|
|
563
578
|
**kwargs,
|
|
564
579
|
):
|
|
565
580
|
"""Takes a 'glyphSet' argument (dict), in which the glyphs that are referenced
|
|
566
581
|
as components are looked up by their name.
|
|
567
582
|
|
|
568
|
-
If the optional 'reverseFlipped' argument is True
|
|
569
|
-
matrix has a negative determinant will be decomposed
|
|
570
|
-
to compensate for the flip.
|
|
583
|
+
If the optional 'reverseFlipped' argument is True or a ReverseFlipped enum value,
|
|
584
|
+
components whose transformation matrix has a negative determinant will be decomposed
|
|
585
|
+
with a reversed path direction to compensate for the flip.
|
|
586
|
+
|
|
587
|
+
The reverseFlipped parameter can be:
|
|
588
|
+
- False or ReverseFlipped.NO: Don't reverse flipped components
|
|
589
|
+
- True or ReverseFlipped.KEEP_START: Reverse, keeping original starting point
|
|
590
|
+
- ReverseFlipped.ON_CURVE_FIRST: Reverse, ensuring first point is on-curve
|
|
571
591
|
|
|
572
592
|
The optional 'skipMissingComponents' argument can be set to True/False to
|
|
573
593
|
override the homonymous class attribute for a given pen instance.
|
|
@@ -579,7 +599,13 @@ class DecomposingPointPen(LogMixin, AbstractPointPen):
|
|
|
579
599
|
if skipMissingComponents is None
|
|
580
600
|
else skipMissingComponents
|
|
581
601
|
)
|
|
582
|
-
|
|
602
|
+
# Handle backward compatibility and validate string inputs
|
|
603
|
+
if reverseFlipped is False:
|
|
604
|
+
self.reverseFlipped = ReverseFlipped.NO
|
|
605
|
+
elif reverseFlipped is True:
|
|
606
|
+
self.reverseFlipped = ReverseFlipped.KEEP_START
|
|
607
|
+
else:
|
|
608
|
+
self.reverseFlipped = ReverseFlipped(reverseFlipped)
|
|
583
609
|
|
|
584
610
|
def addComponent(self, baseGlyphName, transformation, identifier=None, **kwargs):
|
|
585
611
|
"""Transform the points of the base glyph and draw it onto self.
|
|
@@ -600,10 +626,18 @@ class DecomposingPointPen(LogMixin, AbstractPointPen):
|
|
|
600
626
|
pen = self
|
|
601
627
|
if transformation != Identity:
|
|
602
628
|
pen = TransformPointPen(pen, transformation)
|
|
603
|
-
if self.reverseFlipped:
|
|
629
|
+
if self.reverseFlipped != ReverseFlipped.NO:
|
|
604
630
|
# if the transformation has a negative determinant, it will
|
|
605
631
|
# reverse the contour direction of the component
|
|
606
632
|
a, b, c, d = transformation[:4]
|
|
607
633
|
if a * d - b * c < 0:
|
|
608
634
|
pen = ReverseContourPointPen(pen)
|
|
635
|
+
|
|
636
|
+
if self.reverseFlipped == ReverseFlipped.ON_CURVE_FIRST:
|
|
637
|
+
from fontTools.pens.filterPen import OnCurveFirstPointPen
|
|
638
|
+
|
|
639
|
+
# Ensure the starting point is an on-curve.
|
|
640
|
+
# Wrap last so this filter runs first during drawPoints
|
|
641
|
+
pen = OnCurveFirstPointPen(pen)
|
|
642
|
+
|
|
609
643
|
glyph.drawPoints(pen)
|
fontTools/qu2cu/qu2cu.c
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Generated by Cython 3.1.
|
|
1
|
+
/* Generated by Cython 3.1.4 */
|
|
2
2
|
|
|
3
3
|
/* BEGIN: Cython Metadata
|
|
4
4
|
{
|
|
@@ -32,8 +32,8 @@ END: Cython Metadata */
|
|
|
32
32
|
#elif PY_VERSION_HEX < 0x03080000
|
|
33
33
|
#error Cython requires Python 3.8+.
|
|
34
34
|
#else
|
|
35
|
-
#define __PYX_ABI_VERSION "
|
|
36
|
-
#define CYTHON_HEX_VERSION
|
|
35
|
+
#define __PYX_ABI_VERSION "3_1_4"
|
|
36
|
+
#define CYTHON_HEX_VERSION 0x030104F0
|
|
37
37
|
#define CYTHON_FUTURE_DIVISION 1
|
|
38
38
|
/* CModulePreamble */
|
|
39
39
|
#include <stddef.h>
|
|
@@ -3887,8 +3887,12 @@ static PyObject *__pyx_f_9fontTools_5qu2cu_5qu2cu_merge_curves(PyObject *__pyx_v
|
|
|
3887
3887
|
__pyx_t_14 = __Pyx_c_diff_double(__pyx_v_p1, __pyx_v_p0);
|
|
3888
3888
|
__pyx_t_7 = __pyx_PyComplex_FromComplex(__pyx_t_14); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 146, __pyx_L1_error)
|
|
3889
3889
|
__Pyx_GOTREF(__pyx_t_7);
|
|
3890
|
-
|
|
3891
|
-
|
|
3890
|
+
{
|
|
3891
|
+
Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_v_ts);
|
|
3892
|
+
if (unlikely(((!CYTHON_ASSUME_SAFE_SIZE) && __pyx_temp < 0))) __PYX_ERR(0, 146, __pyx_L1_error)
|
|
3893
|
+
__pyx_t_9 = (__pyx_temp != 0);
|
|
3894
|
+
}
|
|
3895
|
+
|
|
3892
3896
|
if (__pyx_t_9) {
|
|
3893
3897
|
__pyx_t_1 = __Pyx_GetItemInt_List(__pyx_v_ts, 0, long, 1, __Pyx_PyLong_From_long, 1, 0, 1, 1); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 146, __pyx_L1_error)
|
|
3894
3898
|
__Pyx_GOTREF(__pyx_t_1);
|
|
@@ -3922,8 +3926,12 @@ static PyObject *__pyx_f_9fontTools_5qu2cu_5qu2cu_merge_curves(PyObject *__pyx_v
|
|
|
3922
3926
|
__pyx_t_14 = __Pyx_c_diff_double(__pyx_v_p2, __pyx_v_p3);
|
|
3923
3927
|
__pyx_t_1 = __pyx_PyComplex_FromComplex(__pyx_t_14); if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 147, __pyx_L1_error)
|
|
3924
3928
|
__Pyx_GOTREF(__pyx_t_1);
|
|
3925
|
-
|
|
3926
|
-
|
|
3929
|
+
{
|
|
3930
|
+
Py_ssize_t __pyx_temp = __Pyx_PyList_GET_SIZE(__pyx_v_ts);
|
|
3931
|
+
if (unlikely(((!CYTHON_ASSUME_SAFE_SIZE) && __pyx_temp < 0))) __PYX_ERR(0, 147, __pyx_L1_error)
|
|
3932
|
+
__pyx_t_9 = (__pyx_temp != 0);
|
|
3933
|
+
}
|
|
3934
|
+
|
|
3927
3935
|
if (__pyx_t_9) {
|
|
3928
3936
|
__pyx_t_7 = __Pyx_GetItemInt_List(__pyx_v_ts, -1L, long, 1, __Pyx_PyLong_From_long, 1, 1, 1, 1); if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 147, __pyx_L1_error)
|
|
3929
3937
|
__Pyx_GOTREF(__pyx_t_7);
|
|
@@ -9031,15 +9039,16 @@ static int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate) {
|
|
|
9031
9039
|
return -1;
|
|
9032
9040
|
}
|
|
9033
9041
|
/* #### Code section: init_codeobjects ### */
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
|
|
9041
|
-
|
|
9042
|
-
|
|
9042
|
+
\
|
|
9043
|
+
typedef struct {
|
|
9044
|
+
unsigned int argcount : 3;
|
|
9045
|
+
unsigned int num_posonly_args : 1;
|
|
9046
|
+
unsigned int num_kwonly_args : 1;
|
|
9047
|
+
unsigned int nlocals : 6;
|
|
9048
|
+
unsigned int flags : 10;
|
|
9049
|
+
unsigned int first_line : 9;
|
|
9050
|
+
unsigned int line_table_length : 15;
|
|
9051
|
+
} __Pyx_PyCode_New_function_description;
|
|
9043
9052
|
/* NewCodeObj.proto */
|
|
9044
9053
|
static PyObject* __Pyx_PyCode_New(
|
|
9045
9054
|
const __Pyx_PyCode_New_function_description descr,
|
|
@@ -12270,6 +12279,7 @@ static int __pyx_CommonTypesMetaclass_init(PyObject *module) {
|
|
|
12270
12279
|
return -1;
|
|
12271
12280
|
}
|
|
12272
12281
|
mstate->__pyx_CommonTypesMetaclassType = __Pyx_FetchCommonTypeFromSpec(NULL, module, &__pyx_CommonTypesMetaclass_spec, bases);
|
|
12282
|
+
Py_DECREF(bases);
|
|
12273
12283
|
if (unlikely(mstate->__pyx_CommonTypesMetaclassType == NULL)) {
|
|
12274
12284
|
return -1;
|
|
12275
12285
|
}
|
|
@@ -16097,6 +16107,10 @@ static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt
|
|
|
16097
16107
|
PyCode_NewWithPosOnlyArgs
|
|
16098
16108
|
#endif
|
|
16099
16109
|
(a, p, k, l, s, f, code, c, n, v, fv, cell, fn, name, name, fline, lnos, __pyx_mstate_global->__pyx_empty_bytes);
|
|
16110
|
+
#if CYTHON_COMPILING_IN_CPYTHON && PY_VERSION_HEX >= 0x030c00A1
|
|
16111
|
+
if (likely(result))
|
|
16112
|
+
result->_co_firsttraceable = 0;
|
|
16113
|
+
#endif
|
|
16100
16114
|
return result;
|
|
16101
16115
|
}
|
|
16102
16116
|
#elif PY_VERSION_HEX >= 0x030800B2 && !CYTHON_COMPILING_IN_PYPY
|
|
Binary file
|
fontTools/subset/__init__.py
CHANGED
|
@@ -1530,6 +1530,7 @@ def subset_glyphs(self, s):
|
|
|
1530
1530
|
if self.MarkFilteringSet not in s.used_mark_sets:
|
|
1531
1531
|
self.MarkFilteringSet = None
|
|
1532
1532
|
self.LookupFlag &= ~0x10
|
|
1533
|
+
self.LookupFlag |= 0x8
|
|
1533
1534
|
else:
|
|
1534
1535
|
self.MarkFilteringSet = s.used_mark_sets.index(self.MarkFilteringSet)
|
|
1535
1536
|
return bool(self.SubTableCount)
|
|
@@ -143,7 +143,7 @@ class table__a_v_a_r(BaseTTXConverter):
|
|
|
143
143
|
else:
|
|
144
144
|
super().fromXML(name, attrs, content, ttFont)
|
|
145
145
|
|
|
146
|
-
def renormalizeLocation(self, location, font):
|
|
146
|
+
def renormalizeLocation(self, location, font, dropZeroes=True):
|
|
147
147
|
|
|
148
148
|
majorVersion = getattr(self, "majorVersion", 1)
|
|
149
149
|
|
|
@@ -185,7 +185,9 @@ class table__a_v_a_r(BaseTTXConverter):
|
|
|
185
185
|
out.append(v)
|
|
186
186
|
|
|
187
187
|
mappedLocation = {
|
|
188
|
-
axis.axisTag: fi2fl(v, 14)
|
|
188
|
+
axis.axisTag: fi2fl(v, 14)
|
|
189
|
+
for v, axis in zip(out, axes)
|
|
190
|
+
if v != 0 or not dropZeroes
|
|
189
191
|
}
|
|
190
192
|
|
|
191
193
|
return mappedLocation
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
2
4
|
from fontTools.misc import sstruct
|
|
3
5
|
from fontTools.misc.textTools import (
|
|
4
6
|
bytechr,
|
|
@@ -63,7 +65,7 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|
|
63
65
|
)
|
|
64
66
|
stringData = data[stringOffset:]
|
|
65
67
|
data = data[6:]
|
|
66
|
-
self.names = []
|
|
68
|
+
self.names: list[NameRecord] = []
|
|
67
69
|
for i in range(n):
|
|
68
70
|
if len(data) < 12:
|
|
69
71
|
log.error("skipping malformed name record #%d", i)
|
|
@@ -112,7 +114,9 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|
|
112
114
|
self.names.append(name)
|
|
113
115
|
name.fromXML(name, attrs, content, ttFont)
|
|
114
116
|
|
|
115
|
-
def getName(
|
|
117
|
+
def getName(
|
|
118
|
+
self, nameID: int, platformID: int, platEncID: int, langID: int | None = None
|
|
119
|
+
) -> "NameRecord | None":
|
|
116
120
|
for namerecord in self.names:
|
|
117
121
|
if (
|
|
118
122
|
namerecord.nameID == nameID
|
|
@@ -123,8 +127,9 @@ class table__n_a_m_e(DefaultTable.DefaultTable):
|
|
|
123
127
|
return namerecord
|
|
124
128
|
return None # not found
|
|
125
129
|
|
|
126
|
-
def getDebugName(self, nameID):
|
|
127
|
-
englishName
|
|
130
|
+
def getDebugName(self, nameID: int) -> str | None:
|
|
131
|
+
englishName: str | None = None
|
|
132
|
+
someName: str | None = None
|
|
128
133
|
for name in self.names:
|
|
129
134
|
if name.nameID != nameID:
|
|
130
135
|
continue
|
|
@@ -513,7 +518,7 @@ class NameRecord(object):
|
|
|
513
518
|
self.platformID == 3 and self.platEncID in [0, 1, 10]
|
|
514
519
|
)
|
|
515
520
|
|
|
516
|
-
def toUnicode(self, errors="strict"):
|
|
521
|
+
def toUnicode(self, errors: str = "strict") -> str:
|
|
517
522
|
"""
|
|
518
523
|
If self.string is a Unicode string, return it; otherwise try decoding the
|
|
519
524
|
bytes in self.string to a Unicode string using the encoding of this
|
|
@@ -533,7 +538,7 @@ class NameRecord(object):
|
|
|
533
538
|
and saving it back will not change them.
|
|
534
539
|
"""
|
|
535
540
|
|
|
536
|
-
def isascii(b):
|
|
541
|
+
def isascii(b: int) -> bool:
|
|
537
542
|
return (b >= 0x20 and b <= 0x7E) or b in [0x09, 0x0A, 0x0D]
|
|
538
543
|
|
|
539
544
|
encoding = self.getEncoding()
|
|
@@ -118,6 +118,7 @@ class table__p_o_s_t(DefaultTable.DefaultTable):
|
|
|
118
118
|
def build_psNameMapping(self, ttFont):
|
|
119
119
|
mapping = {}
|
|
120
120
|
allNames = {}
|
|
121
|
+
glyphOrderNames = set(self.glyphOrder)
|
|
121
122
|
for i in range(ttFont["maxp"].numGlyphs):
|
|
122
123
|
glyphName = psName = self.glyphOrder[i]
|
|
123
124
|
if glyphName == "":
|
|
@@ -126,16 +127,15 @@ class table__p_o_s_t(DefaultTable.DefaultTable):
|
|
|
126
127
|
if glyphName in allNames:
|
|
127
128
|
# make up a new glyphName that's unique
|
|
128
129
|
n = allNames[glyphName]
|
|
129
|
-
# check if the exists in
|
|
130
|
-
|
|
131
|
-
while (glyphName + "." + str(n)) in names:
|
|
130
|
+
# check if the glyph name exists in the glyph order
|
|
131
|
+
while f"{glyphName}.{n}" in glyphOrderNames:
|
|
132
132
|
n += 1
|
|
133
133
|
allNames[glyphName] = n + 1
|
|
134
|
-
glyphName = glyphName
|
|
134
|
+
glyphName = f"{glyphName}.{n}"
|
|
135
135
|
|
|
136
|
-
self.glyphOrder[i] = glyphName
|
|
137
136
|
allNames[glyphName] = 1
|
|
138
137
|
if glyphName != psName:
|
|
138
|
+
self.glyphOrder[i] = glyphName
|
|
139
139
|
mapping[glyphName] = psName
|
|
140
140
|
|
|
141
141
|
self.mapping = mapping
|