fonttools 4.58.0__cp312-cp312-macosx_10_13_x86_64.whl → 4.58.2__cp312-cp312-macosx_10_13_x86_64.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/specializer.py +4 -1
- fontTools/cu2qu/cu2qu.c +36 -24
- fontTools/cu2qu/cu2qu.cpython-312-darwin.so +0 -0
- fontTools/feaLib/ast.py +1 -72
- fontTools/feaLib/builder.py +55 -45
- fontTools/feaLib/lexer.c +60 -43
- fontTools/feaLib/lexer.cpython-312-darwin.so +0 -0
- fontTools/merge/cmap.py +33 -1
- fontTools/merge/tables.py +12 -1
- fontTools/misc/bezierTools.c +137 -125
- fontTools/misc/bezierTools.cpython-312-darwin.so +0 -0
- fontTools/misc/loggingTools.py +1 -1
- fontTools/misc/symfont.py +6 -8
- fontTools/mtiLib/__init__.py +1 -1
- fontTools/otlLib/builder.py +164 -0
- fontTools/pens/momentsPen.c +42 -25
- fontTools/pens/momentsPen.cpython-312-darwin.so +0 -0
- fontTools/pens/t2CharStringPen.py +31 -11
- fontTools/qu2cu/qu2cu.c +47 -35
- fontTools/qu2cu/qu2cu.cpython-312-darwin.so +0 -0
- fontTools/subset/__init__.py +82 -2
- fontTools/ttLib/reorderGlyphs.py +8 -7
- fontTools/ufoLib/__init__.py +1 -1
- fontTools/varLib/__init__.py +18 -6
- fontTools/varLib/featureVars.py +13 -7
- fontTools/varLib/hvar.py +1 -1
- fontTools/varLib/instancer/__init__.py +14 -5
- fontTools/varLib/iup.c +52 -40
- fontTools/varLib/iup.cpython-312-darwin.so +0 -0
- {fonttools-4.58.0.dist-info → fonttools-4.58.2.dist-info}/METADATA +26 -1
- {fonttools-4.58.0.dist-info → fonttools-4.58.2.dist-info}/RECORD +38 -38
- {fonttools-4.58.0.dist-info → fonttools-4.58.2.dist-info}/WHEEL +1 -1
- {fonttools-4.58.0.data → fonttools-4.58.2.data}/data/share/man/man1/ttx.1 +0 -0
- {fonttools-4.58.0.dist-info → fonttools-4.58.2.dist-info}/entry_points.txt +0 -0
- {fonttools-4.58.0.dist-info → fonttools-4.58.2.dist-info}/licenses/LICENSE +0 -0
- {fonttools-4.58.0.dist-info → fonttools-4.58.2.dist-info}/licenses/LICENSE.external +0 -0
- {fonttools-4.58.0.dist-info → fonttools-4.58.2.dist-info}/top_level.txt +0 -0
fontTools/__init__.py
CHANGED
fontTools/cffLib/specializer.py
CHANGED
|
@@ -580,7 +580,10 @@ def specializeCommands(
|
|
|
580
580
|
for i in range(len(commands) - 1, 0, -1):
|
|
581
581
|
if "rmoveto" == commands[i][0] == commands[i - 1][0]:
|
|
582
582
|
v1, v2 = commands[i - 1][1], commands[i][1]
|
|
583
|
-
commands[i - 1] = (
|
|
583
|
+
commands[i - 1] = (
|
|
584
|
+
"rmoveto",
|
|
585
|
+
[_addArgs(v1[0], v2[0]), _addArgs(v1[1], v2[1])],
|
|
586
|
+
)
|
|
584
587
|
del commands[i]
|
|
585
588
|
|
|
586
589
|
# 2. Specialize rmoveto/rlineto/rrcurveto operators into horizontal/vertical variants.
|
fontTools/cu2qu/cu2qu.c
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* Generated by Cython 3.1.
|
|
1
|
+
/* Generated by Cython 3.1.1 */
|
|
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_1"
|
|
36
|
+
#define CYTHON_HEX_VERSION 0x030101F0
|
|
37
37
|
#define CYTHON_FUTURE_DIVISION 1
|
|
38
38
|
/* CModulePreamble */
|
|
39
39
|
#include <stddef.h>
|
|
@@ -8031,8 +8031,8 @@ static int __Pyx_InitConstants(__pyx_mstatetype *__pyx_mstate) {
|
|
|
8031
8031
|
} __Pyx_PyCode_New_function_description;
|
|
8032
8032
|
/* NewCodeObj.proto */
|
|
8033
8033
|
static PyObject* __Pyx_PyCode_New(
|
|
8034
|
-
__Pyx_PyCode_New_function_description descr,
|
|
8035
|
-
PyObject
|
|
8034
|
+
const __Pyx_PyCode_New_function_description descr,
|
|
8035
|
+
PyObject * const *varnames,
|
|
8036
8036
|
PyObject *filename,
|
|
8037
8037
|
PyObject *funcname,
|
|
8038
8038
|
const char *line_table,
|
|
@@ -8044,18 +8044,18 @@ static int __Pyx_CreateCodeObjects(__pyx_mstatetype *__pyx_mstate) {
|
|
|
8044
8044
|
PyObject* tuple_dedup_map = PyDict_New();
|
|
8045
8045
|
if (unlikely(!tuple_dedup_map)) return -1;
|
|
8046
8046
|
{
|
|
8047
|
-
__Pyx_PyCode_New_function_description descr = {5, 0, 0, 19, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR), 124, 2};
|
|
8048
|
-
PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_p0, __pyx_mstate->__pyx_n_u_p1, __pyx_mstate->__pyx_n_u_p2, __pyx_mstate->__pyx_n_u_p3, __pyx_mstate->__pyx_n_u_n, __pyx_mstate->__pyx_n_u_a1, __pyx_mstate->__pyx_n_u_b1, __pyx_mstate->__pyx_n_u_c1, __pyx_mstate->__pyx_n_u_d1, __pyx_mstate->__pyx_n_u_dt, __pyx_mstate->__pyx_n_u_delta_2, __pyx_mstate->__pyx_n_u_delta_3, __pyx_mstate->__pyx_n_u_i, __pyx_mstate->__pyx_n_u_a, __pyx_mstate->__pyx_n_u_b, __pyx_mstate->__pyx_n_u_c, __pyx_mstate->__pyx_n_u_d, __pyx_mstate->__pyx_n_u_t1, __pyx_mstate->__pyx_n_u_t1_2};
|
|
8047
|
+
const __Pyx_PyCode_New_function_description descr = {5, 0, 0, 19, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS|CO_GENERATOR), 124, 2};
|
|
8048
|
+
PyObject* const varnames[] = {__pyx_mstate->__pyx_n_u_p0, __pyx_mstate->__pyx_n_u_p1, __pyx_mstate->__pyx_n_u_p2, __pyx_mstate->__pyx_n_u_p3, __pyx_mstate->__pyx_n_u_n, __pyx_mstate->__pyx_n_u_a1, __pyx_mstate->__pyx_n_u_b1, __pyx_mstate->__pyx_n_u_c1, __pyx_mstate->__pyx_n_u_d1, __pyx_mstate->__pyx_n_u_dt, __pyx_mstate->__pyx_n_u_delta_2, __pyx_mstate->__pyx_n_u_delta_3, __pyx_mstate->__pyx_n_u_i, __pyx_mstate->__pyx_n_u_a, __pyx_mstate->__pyx_n_u_b, __pyx_mstate->__pyx_n_u_c, __pyx_mstate->__pyx_n_u_d, __pyx_mstate->__pyx_n_u_t1, __pyx_mstate->__pyx_n_u_t1_2};
|
|
8049
8049
|
__pyx_mstate_global->__pyx_codeobj_tab[0] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_Lib_fontTools_cu2qu_cu2qu_py, __pyx_mstate->__pyx_n_u_split_cubic_into_n_gen, __pyx_k__3, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[0])) goto bad;
|
|
8050
8050
|
}
|
|
8051
8051
|
{
|
|
8052
|
-
__Pyx_PyCode_New_function_description descr = {3, 0, 0, 7, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 436, 97};
|
|
8053
|
-
PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_curve, __pyx_mstate->__pyx_n_u_max_err, __pyx_mstate->__pyx_n_u_all_quadratic, __pyx_mstate->__pyx_n_u_n, __pyx_mstate->__pyx_n_u_spline, __pyx_mstate->__pyx_n_u_p, __pyx_mstate->__pyx_n_u_s};
|
|
8052
|
+
const __Pyx_PyCode_New_function_description descr = {3, 0, 0, 7, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 436, 97};
|
|
8053
|
+
PyObject* const varnames[] = {__pyx_mstate->__pyx_n_u_curve, __pyx_mstate->__pyx_n_u_max_err, __pyx_mstate->__pyx_n_u_all_quadratic, __pyx_mstate->__pyx_n_u_n, __pyx_mstate->__pyx_n_u_spline, __pyx_mstate->__pyx_n_u_p, __pyx_mstate->__pyx_n_u_s};
|
|
8054
8054
|
__pyx_mstate_global->__pyx_codeobj_tab[1] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_Lib_fontTools_cu2qu_cu2qu_py, __pyx_mstate->__pyx_n_u_curve_to_quadratic, __pyx_k_AWBc_U_U_3fBa_AWCy_7_2QgQgT_a_Q, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[1])) goto bad;
|
|
8055
8055
|
}
|
|
8056
8056
|
{
|
|
8057
|
-
__Pyx_PyCode_New_function_description descr = {3, 0, 0, 13, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 471, 211};
|
|
8058
|
-
PyObject* varnames[] = {__pyx_mstate->__pyx_n_u_curves, __pyx_mstate->__pyx_n_u_max_errors, __pyx_mstate->__pyx_n_u_all_quadratic, __pyx_mstate->__pyx_n_u_l, __pyx_mstate->__pyx_n_u_last_i, __pyx_mstate->__pyx_n_u_i, __pyx_mstate->__pyx_n_u_splines, __pyx_mstate->__pyx_n_u_n, __pyx_mstate->__pyx_n_u_spline, __pyx_mstate->__pyx_n_u_curve, __pyx_mstate->__pyx_n_u_p, __pyx_mstate->__pyx_n_u_spline, __pyx_mstate->__pyx_n_u_s};
|
|
8057
|
+
const __Pyx_PyCode_New_function_description descr = {3, 0, 0, 13, (unsigned int)(CO_OPTIMIZED|CO_NEWLOCALS), 471, 211};
|
|
8058
|
+
PyObject* const varnames[] = {__pyx_mstate->__pyx_n_u_curves, __pyx_mstate->__pyx_n_u_max_errors, __pyx_mstate->__pyx_n_u_all_quadratic, __pyx_mstate->__pyx_n_u_l, __pyx_mstate->__pyx_n_u_last_i, __pyx_mstate->__pyx_n_u_i, __pyx_mstate->__pyx_n_u_splines, __pyx_mstate->__pyx_n_u_n, __pyx_mstate->__pyx_n_u_spline, __pyx_mstate->__pyx_n_u_curve, __pyx_mstate->__pyx_n_u_p, __pyx_mstate->__pyx_n_u_spline, __pyx_mstate->__pyx_n_u_s};
|
|
8059
8059
|
__pyx_mstate_global->__pyx_codeobj_tab[2] = __Pyx_PyCode_New(descr, varnames, __pyx_mstate->__pyx_kp_u_Lib_fontTools_cu2qu_cu2qu_py, __pyx_mstate->__pyx_n_u_curves_to_quadratic, __pyx_k_J_Qawb_4uG4y_3a_3c_1A_avRq_T_AV, tuple_dedup_map); if (unlikely(!__pyx_mstate_global->__pyx_codeobj_tab[2])) goto bad;
|
|
8060
8060
|
}
|
|
8061
8061
|
Py_DECREF(tuple_dedup_map);
|
|
@@ -9034,6 +9034,11 @@ static PyObject *__Pyx_SelflessCall(PyObject *method, PyObject *args, PyObject *
|
|
|
9034
9034
|
Py_DECREF(selfless_args);
|
|
9035
9035
|
return result;
|
|
9036
9036
|
}
|
|
9037
|
+
#elif CYTHON_COMPILING_IN_PYPY && PY_VERSION_HEX < 0x03090000
|
|
9038
|
+
static PyObject *__Pyx_SelflessCall(PyObject *method, PyObject **args, Py_ssize_t nargs, PyObject *kwnames) {
|
|
9039
|
+
return _PyObject_Vectorcall
|
|
9040
|
+
(method, args ? args+1 : NULL, nargs ? nargs-1 : 0, kwnames);
|
|
9041
|
+
}
|
|
9037
9042
|
#else
|
|
9038
9043
|
static PyObject *__Pyx_SelflessCall(PyObject *method, PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames) {
|
|
9039
9044
|
return
|
|
@@ -9357,7 +9362,9 @@ static int __Pyx_ParseKeywordDict(
|
|
|
9357
9362
|
PyObject** const *name;
|
|
9358
9363
|
PyObject** const *first_kw_arg = argnames + num_pos_args;
|
|
9359
9364
|
Py_ssize_t extracted = 0;
|
|
9365
|
+
#if !CYTHON_COMPILING_IN_PYPY || defined(PyArg_ValidateKeywordArguments)
|
|
9360
9366
|
if (unlikely(!PyArg_ValidateKeywordArguments(kwds))) return -1;
|
|
9367
|
+
#endif
|
|
9361
9368
|
name = first_kw_arg;
|
|
9362
9369
|
while (*name && num_kwargs > extracted) {
|
|
9363
9370
|
PyObject * key = **name;
|
|
@@ -9405,7 +9412,9 @@ static int __Pyx_ParseKeywordDictToDict(
|
|
|
9405
9412
|
PyObject** const *name;
|
|
9406
9413
|
PyObject** const *first_kw_arg = argnames + num_pos_args;
|
|
9407
9414
|
Py_ssize_t len;
|
|
9415
|
+
#if !CYTHON_COMPILING_IN_PYPY || defined(PyArg_ValidateKeywordArguments)
|
|
9408
9416
|
if (unlikely(!PyArg_ValidateKeywordArguments(kwds))) return -1;
|
|
9417
|
+
#endif
|
|
9409
9418
|
if (PyDict_Update(kwds2, kwds) < 0) goto bad;
|
|
9410
9419
|
name = first_kw_arg;
|
|
9411
9420
|
while (*name) {
|
|
@@ -10530,7 +10539,8 @@ static PyObject *__Pyx_Import(PyObject *name, PyObject *from_list, int level) {
|
|
|
10530
10539
|
if (unlikely(!empty_dict))
|
|
10531
10540
|
goto bad;
|
|
10532
10541
|
if (level == -1) {
|
|
10533
|
-
|
|
10542
|
+
const char* package_sep = strchr(__Pyx_MODULE_NAME, '.');
|
|
10543
|
+
if (package_sep != (0)) {
|
|
10534
10544
|
module = PyImport_ImportModuleLevelObject(
|
|
10535
10545
|
name, __pyx_mstate_global->__pyx_d, empty_dict, from_list, 1);
|
|
10536
10546
|
if (unlikely(!module)) {
|
|
@@ -12900,7 +12910,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyLong_From_long(long value) {
|
|
|
12900
12910
|
return PyLong_FromLong((long) value);
|
|
12901
12911
|
} else if (sizeof(long) <= sizeof(unsigned long)) {
|
|
12902
12912
|
return PyLong_FromUnsignedLong((unsigned long) value);
|
|
12903
|
-
#
|
|
12913
|
+
#if defined(HAVE_LONG_LONG) && !CYTHON_COMPILING_IN_PYPY
|
|
12904
12914
|
} else if (sizeof(long) <= sizeof(unsigned PY_LONG_LONG)) {
|
|
12905
12915
|
return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
|
|
12906
12916
|
#endif
|
|
@@ -12971,7 +12981,7 @@ static CYTHON_INLINE PyObject* __Pyx_PyLong_From_int(int value) {
|
|
|
12971
12981
|
return PyLong_FromLong((long) value);
|
|
12972
12982
|
} else if (sizeof(int) <= sizeof(unsigned long)) {
|
|
12973
12983
|
return PyLong_FromUnsignedLong((unsigned long) value);
|
|
12974
|
-
#
|
|
12984
|
+
#if defined(HAVE_LONG_LONG) && !CYTHON_COMPILING_IN_PYPY
|
|
12975
12985
|
} else if (sizeof(int) <= sizeof(unsigned PY_LONG_LONG)) {
|
|
12976
12986
|
return PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) value);
|
|
12977
12987
|
#endif
|
|
@@ -13511,8 +13521,8 @@ static void __Pyx__ReturnWithStopIteration(PyObject* value, int async) {
|
|
|
13511
13521
|
PyObject *exc;
|
|
13512
13522
|
PyObject *exc_type = async ? PyExc_StopAsyncIteration : PyExc_StopIteration;
|
|
13513
13523
|
#if CYTHON_COMPILING_IN_CPYTHON
|
|
13514
|
-
if ((PY_VERSION_HEX >= 0x030C00A6) || unlikely(PyTuple_Check(value) || PyExceptionInstance_Check(value))) {
|
|
13515
|
-
if (
|
|
13524
|
+
if ((PY_VERSION_HEX >= (0x030C00A6)) || unlikely(PyTuple_Check(value) || PyExceptionInstance_Check(value))) {
|
|
13525
|
+
if (PY_VERSION_HEX >= (0x030e00A1)) {
|
|
13516
13526
|
exc = __Pyx_PyObject_CallOneArg(exc_type, value);
|
|
13517
13527
|
} else {
|
|
13518
13528
|
PyObject *args_tuple = PyTuple_New(1);
|
|
@@ -13877,17 +13887,19 @@ __Pyx_Coroutine_FinishDelegation(__pyx_CoroutineObject *gen, PyObject** retval)
|
|
|
13877
13887
|
static __Pyx_PySendResult
|
|
13878
13888
|
__Pyx_Coroutine_SendToDelegate(__pyx_CoroutineObject *gen, __Pyx_pyiter_sendfunc gen_am_send, PyObject *value, PyObject **retval) {
|
|
13879
13889
|
PyObject *ret = NULL;
|
|
13880
|
-
__Pyx_PySendResult result;
|
|
13890
|
+
__Pyx_PySendResult delegate_result, result;
|
|
13881
13891
|
assert(__Pyx_Coroutine_get_is_running(gen));
|
|
13882
|
-
|
|
13883
|
-
if (
|
|
13892
|
+
delegate_result = gen_am_send(gen->yieldfrom, value, &ret);
|
|
13893
|
+
if (delegate_result == PYGEN_NEXT) {
|
|
13884
13894
|
assert (ret != NULL);
|
|
13885
13895
|
*retval = ret;
|
|
13886
13896
|
return PYGEN_NEXT;
|
|
13887
13897
|
}
|
|
13888
|
-
assert (
|
|
13898
|
+
assert (delegate_result != PYGEN_ERROR || ret == NULL);
|
|
13889
13899
|
__Pyx_Coroutine_Undelegate(gen);
|
|
13890
|
-
|
|
13900
|
+
result = __Pyx_Coroutine_SendEx(gen, ret, retval, 0);
|
|
13901
|
+
Py_XDECREF(ret);
|
|
13902
|
+
return result;
|
|
13891
13903
|
}
|
|
13892
13904
|
#endif
|
|
13893
13905
|
static PyObject *__Pyx_Coroutine_Send(PyObject *self, PyObject *value) {
|
|
@@ -14700,9 +14712,9 @@ static int __Pyx_check_binary_version(unsigned long ct_version, unsigned long rt
|
|
|
14700
14712
|
PyCode_New(a, k, l, s, f, code, c, n, v, fv, cell, fn, name, fline, lnos)
|
|
14701
14713
|
#endif
|
|
14702
14714
|
static PyObject* __Pyx_PyCode_New(
|
|
14703
|
-
__Pyx_PyCode_New_function_description descr,
|
|
14704
|
-
PyObject
|
|
14705
|
-
PyObject*
|
|
14715
|
+
const __Pyx_PyCode_New_function_description descr,
|
|
14716
|
+
PyObject * const *varnames,
|
|
14717
|
+
PyObject *filename,
|
|
14706
14718
|
PyObject *funcname,
|
|
14707
14719
|
const char *line_table,
|
|
14708
14720
|
PyObject *tuple_dedup_map
|
|
Binary file
|
fontTools/feaLib/ast.py
CHANGED
|
@@ -337,76 +337,6 @@ class AnonymousBlock(Statement):
|
|
|
337
337
|
return res
|
|
338
338
|
|
|
339
339
|
|
|
340
|
-
def _upgrade_mixed_subst_statements(statements):
|
|
341
|
-
# https://github.com/fonttools/fonttools/issues/612
|
|
342
|
-
# A multiple substitution may have a single destination, in which case
|
|
343
|
-
# it will look just like a single substitution. So if there are both
|
|
344
|
-
# multiple and single substitutions, upgrade all the single ones to
|
|
345
|
-
# multiple substitutions. Similarly, a ligature substitution may have a
|
|
346
|
-
# single source glyph, so if there are both ligature and single
|
|
347
|
-
# substitutions, upgrade all the single ones to ligature substitutions.
|
|
348
|
-
|
|
349
|
-
has_single = False
|
|
350
|
-
has_multiple = False
|
|
351
|
-
has_ligature = False
|
|
352
|
-
for s in statements:
|
|
353
|
-
if isinstance(s, SingleSubstStatement):
|
|
354
|
-
has_single = not any([s.prefix, s.suffix, s.forceChain])
|
|
355
|
-
elif isinstance(s, MultipleSubstStatement):
|
|
356
|
-
has_multiple = not any([s.prefix, s.suffix, s.forceChain])
|
|
357
|
-
elif isinstance(s, LigatureSubstStatement):
|
|
358
|
-
has_ligature = not any([s.prefix, s.suffix, s.forceChain])
|
|
359
|
-
|
|
360
|
-
to_multiple = False
|
|
361
|
-
to_ligature = False
|
|
362
|
-
|
|
363
|
-
# If we have mixed single and multiple substitutions,
|
|
364
|
-
# upgrade all single substitutions to multiple substitutions.
|
|
365
|
-
if has_single and has_multiple and not has_ligature:
|
|
366
|
-
to_multiple = True
|
|
367
|
-
|
|
368
|
-
# If we have mixed single and ligature substitutions,
|
|
369
|
-
# upgrade all single substitutions to ligature substitutions.
|
|
370
|
-
elif has_single and has_ligature and not has_multiple:
|
|
371
|
-
to_ligature = True
|
|
372
|
-
|
|
373
|
-
if to_multiple or to_ligature:
|
|
374
|
-
ret = []
|
|
375
|
-
for s in statements:
|
|
376
|
-
if isinstance(s, SingleSubstStatement):
|
|
377
|
-
glyphs = s.glyphs[0].glyphSet()
|
|
378
|
-
replacements = s.replacements[0].glyphSet()
|
|
379
|
-
if len(replacements) == 1:
|
|
380
|
-
replacements *= len(glyphs)
|
|
381
|
-
for glyph, replacement in zip(glyphs, replacements):
|
|
382
|
-
if to_multiple:
|
|
383
|
-
ret.append(
|
|
384
|
-
MultipleSubstStatement(
|
|
385
|
-
s.prefix,
|
|
386
|
-
glyph,
|
|
387
|
-
s.suffix,
|
|
388
|
-
[replacement],
|
|
389
|
-
s.forceChain,
|
|
390
|
-
location=s.location,
|
|
391
|
-
)
|
|
392
|
-
)
|
|
393
|
-
elif to_ligature:
|
|
394
|
-
ret.append(
|
|
395
|
-
LigatureSubstStatement(
|
|
396
|
-
s.prefix,
|
|
397
|
-
[GlyphName(glyph)],
|
|
398
|
-
s.suffix,
|
|
399
|
-
replacement,
|
|
400
|
-
s.forceChain,
|
|
401
|
-
location=s.location,
|
|
402
|
-
)
|
|
403
|
-
)
|
|
404
|
-
else:
|
|
405
|
-
ret.append(s)
|
|
406
|
-
return ret
|
|
407
|
-
return statements
|
|
408
|
-
|
|
409
|
-
|
|
410
340
|
class Block(Statement):
|
|
411
341
|
"""A block of statements: feature, lookup, etc."""
|
|
412
342
|
|
|
@@ -418,8 +348,7 @@ class Block(Statement):
|
|
|
418
348
|
"""When handed a 'builder' object of comparable interface to
|
|
419
349
|
:class:`fontTools.feaLib.builder`, walks the statements in this
|
|
420
350
|
block, calling the builder callbacks."""
|
|
421
|
-
|
|
422
|
-
for s in statements:
|
|
351
|
+
for s in self.statements:
|
|
423
352
|
s.build(builder)
|
|
424
353
|
|
|
425
354
|
def asFea(self, indent=""):
|
fontTools/feaLib/builder.py
CHANGED
|
@@ -29,6 +29,7 @@ from fontTools.otlLib.builder import (
|
|
|
29
29
|
PairPosBuilder,
|
|
30
30
|
SinglePosBuilder,
|
|
31
31
|
ChainContextualRule,
|
|
32
|
+
AnySubstBuilder,
|
|
32
33
|
)
|
|
33
34
|
from fontTools.otlLib.error import OpenTypeLibError
|
|
34
35
|
from fontTools.varLib.varStore import OnlineVarStoreBuilder
|
|
@@ -866,13 +867,22 @@ class Builder(object):
|
|
|
866
867
|
for lookup in self.lookups_:
|
|
867
868
|
if lookup.table != tag:
|
|
868
869
|
continue
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
870
|
+
name = self.get_lookup_name_(lookup)
|
|
871
|
+
resolved = lookup.promote_lookup_type(is_named_lookup=name is not None)
|
|
872
|
+
if resolved is None:
|
|
873
|
+
raise FeatureLibError(
|
|
874
|
+
"Within a named lookup block, all rules must be of "
|
|
875
|
+
"the same lookup type and flag",
|
|
876
|
+
lookup.location,
|
|
877
|
+
)
|
|
878
|
+
for l in resolved:
|
|
879
|
+
lookup.lookup_index = len(lookups)
|
|
880
|
+
self.lookup_locations[tag][str(lookup.lookup_index)] = LookupDebugInfo(
|
|
881
|
+
location=str(lookup.location),
|
|
882
|
+
name=name,
|
|
883
|
+
feature=None,
|
|
884
|
+
)
|
|
885
|
+
lookups.append(l)
|
|
876
886
|
otLookups = []
|
|
877
887
|
for l in lookups:
|
|
878
888
|
try:
|
|
@@ -1294,6 +1304,24 @@ class Builder(object):
|
|
|
1294
1304
|
|
|
1295
1305
|
# GSUB rules
|
|
1296
1306
|
|
|
1307
|
+
def add_any_subst_(self, location, mapping):
|
|
1308
|
+
lookup = self.get_lookup_(location, AnySubstBuilder)
|
|
1309
|
+
for key, value in mapping.items():
|
|
1310
|
+
if key in lookup.mapping:
|
|
1311
|
+
if value == lookup.mapping[key]:
|
|
1312
|
+
log.info(
|
|
1313
|
+
'Removing duplicate substitution from "%s" to "%s" at %s',
|
|
1314
|
+
", ".join(key),
|
|
1315
|
+
", ".join(value),
|
|
1316
|
+
location,
|
|
1317
|
+
)
|
|
1318
|
+
else:
|
|
1319
|
+
raise FeatureLibError(
|
|
1320
|
+
'Already defined substitution for "%s"' % ", ".join(key),
|
|
1321
|
+
location,
|
|
1322
|
+
)
|
|
1323
|
+
lookup.mapping[key] = value
|
|
1324
|
+
|
|
1297
1325
|
# GSUB 1
|
|
1298
1326
|
def add_single_subst(self, location, prefix, suffix, mapping, forceChain):
|
|
1299
1327
|
if self.cur_feature_name_ == "aalt":
|
|
@@ -1305,24 +1333,11 @@ class Builder(object):
|
|
|
1305
1333
|
if prefix or suffix or forceChain:
|
|
1306
1334
|
self.add_single_subst_chained_(location, prefix, suffix, mapping)
|
|
1307
1335
|
return
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
"Removing duplicate single substitution from glyph"
|
|
1314
|
-
' "%s" to "%s" at %s',
|
|
1315
|
-
from_glyph,
|
|
1316
|
-
to_glyph,
|
|
1317
|
-
location,
|
|
1318
|
-
)
|
|
1319
|
-
else:
|
|
1320
|
-
raise FeatureLibError(
|
|
1321
|
-
'Already defined rule for replacing glyph "%s" by "%s"'
|
|
1322
|
-
% (from_glyph, lookup.mapping[from_glyph]),
|
|
1323
|
-
location,
|
|
1324
|
-
)
|
|
1325
|
-
lookup.mapping[from_glyph] = to_glyph
|
|
1336
|
+
|
|
1337
|
+
self.add_any_subst_(
|
|
1338
|
+
location,
|
|
1339
|
+
{(key,): (value,) for key, value in mapping.items()},
|
|
1340
|
+
)
|
|
1326
1341
|
|
|
1327
1342
|
# GSUB 2
|
|
1328
1343
|
def add_multiple_subst(
|
|
@@ -1331,21 +1346,10 @@ class Builder(object):
|
|
|
1331
1346
|
if prefix or suffix or forceChain:
|
|
1332
1347
|
self.add_multi_subst_chained_(location, prefix, glyph, suffix, replacements)
|
|
1333
1348
|
return
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
"Removing duplicate multiple substitution from glyph"
|
|
1339
|
-
' "%s" to %s%s',
|
|
1340
|
-
glyph,
|
|
1341
|
-
replacements,
|
|
1342
|
-
f" at {location}" if location else "",
|
|
1343
|
-
)
|
|
1344
|
-
else:
|
|
1345
|
-
raise FeatureLibError(
|
|
1346
|
-
'Already defined substitution for glyph "%s"' % glyph, location
|
|
1347
|
-
)
|
|
1348
|
-
lookup.mapping[glyph] = replacements
|
|
1349
|
+
self.add_any_subst_(
|
|
1350
|
+
location,
|
|
1351
|
+
{(glyph,): tuple(replacements)},
|
|
1352
|
+
)
|
|
1349
1353
|
|
|
1350
1354
|
# GSUB 3
|
|
1351
1355
|
def add_alternate_subst(self, location, prefix, glyph, suffix, replacement):
|
|
@@ -1375,9 +1379,6 @@ class Builder(object):
|
|
|
1375
1379
|
location, prefix, glyphs, suffix, replacement
|
|
1376
1380
|
)
|
|
1377
1381
|
return
|
|
1378
|
-
else:
|
|
1379
|
-
lookup = self.get_lookup_(location, LigatureSubstBuilder)
|
|
1380
|
-
|
|
1381
1382
|
if not all(glyphs):
|
|
1382
1383
|
raise FeatureLibError("Empty glyph class in substitution", location)
|
|
1383
1384
|
|
|
@@ -1386,8 +1387,10 @@ class Builder(object):
|
|
|
1386
1387
|
# substitutions to be specified on target sequences that contain
|
|
1387
1388
|
# glyph classes, the implementation software will enumerate
|
|
1388
1389
|
# all specific glyph sequences if glyph classes are detected"
|
|
1389
|
-
|
|
1390
|
-
|
|
1390
|
+
self.add_any_subst_(
|
|
1391
|
+
location,
|
|
1392
|
+
{g: (replacement,) for g in itertools.product(*glyphs)},
|
|
1393
|
+
)
|
|
1391
1394
|
|
|
1392
1395
|
# GSUB 5/6
|
|
1393
1396
|
def add_chain_context_subst(self, location, prefix, glyphs, suffix, lookups):
|
|
@@ -1445,6 +1448,13 @@ class Builder(object):
|
|
|
1445
1448
|
sub = self.get_chained_lookup_(location, LigatureSubstBuilder)
|
|
1446
1449
|
|
|
1447
1450
|
for g in itertools.product(*glyphs):
|
|
1451
|
+
existing = sub.ligatures.get(g, replacement)
|
|
1452
|
+
if existing != replacement:
|
|
1453
|
+
raise FeatureLibError(
|
|
1454
|
+
f"Conflicting ligature sub rules: '{g}' maps to '{existing}' and '{replacement}'",
|
|
1455
|
+
location,
|
|
1456
|
+
)
|
|
1457
|
+
|
|
1448
1458
|
sub.ligatures[g] = replacement
|
|
1449
1459
|
|
|
1450
1460
|
chain.rules.append(ChainContextualRule(prefix, glyphs, suffix, [sub]))
|