fonttools 4.55.4__cp313-cp313-musllinux_1_2_aarch64.whl → 4.61.1__cp313-cp313-musllinux_1_2_aarch64.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 +1 -1
- fontTools/annotations.py +30 -0
- fontTools/cffLib/CFF2ToCFF.py +65 -10
- fontTools/cffLib/__init__.py +61 -26
- fontTools/cffLib/specializer.py +4 -1
- fontTools/cffLib/transforms.py +11 -6
- fontTools/config/__init__.py +15 -0
- fontTools/cu2qu/cu2qu.c +6567 -5579
- fontTools/cu2qu/cu2qu.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/cu2qu/cu2qu.py +36 -4
- fontTools/cu2qu/ufo.py +14 -0
- fontTools/designspaceLib/__init__.py +8 -3
- fontTools/designspaceLib/statNames.py +14 -7
- fontTools/feaLib/ast.py +24 -15
- fontTools/feaLib/builder.py +139 -66
- fontTools/feaLib/error.py +1 -1
- fontTools/feaLib/lexer.c +7038 -7995
- fontTools/feaLib/lexer.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/feaLib/parser.py +75 -40
- fontTools/feaLib/variableScalar.py +6 -1
- fontTools/fontBuilder.py +50 -44
- fontTools/merge/__init__.py +1 -1
- fontTools/merge/cmap.py +33 -1
- fontTools/merge/tables.py +12 -1
- fontTools/misc/bezierTools.c +14913 -17013
- fontTools/misc/bezierTools.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/misc/bezierTools.py +4 -1
- fontTools/misc/configTools.py +3 -1
- fontTools/misc/enumTools.py +23 -0
- fontTools/misc/etree.py +4 -27
- 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 +1 -1
- fontTools/misc/loggingTools.py +1 -1
- fontTools/misc/psCharStrings.py +17 -2
- fontTools/misc/sstruct.py +2 -6
- fontTools/misc/symfont.py +6 -8
- fontTools/misc/testTools.py +5 -1
- fontTools/misc/textTools.py +4 -2
- fontTools/misc/visitor.py +32 -16
- fontTools/misc/xmlWriter.py +44 -8
- fontTools/mtiLib/__init__.py +1 -3
- fontTools/otlLib/builder.py +402 -155
- fontTools/otlLib/optimize/gpos.py +49 -63
- fontTools/pens/filterPen.py +218 -26
- fontTools/pens/momentsPen.c +5514 -5584
- fontTools/pens/momentsPen.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/pens/pointPen.py +61 -18
- fontTools/pens/roundingPen.py +2 -2
- fontTools/pens/t2CharStringPen.py +31 -11
- fontTools/qu2cu/qu2cu.c +6581 -6168
- fontTools/qu2cu/qu2cu.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/subset/__init__.py +283 -25
- fontTools/subset/svg.py +2 -3
- fontTools/ttLib/__init__.py +4 -0
- fontTools/ttLib/__main__.py +47 -8
- fontTools/ttLib/removeOverlaps.py +7 -5
- fontTools/ttLib/reorderGlyphs.py +8 -7
- fontTools/ttLib/sfnt.py +11 -9
- fontTools/ttLib/tables/D__e_b_g.py +20 -2
- fontTools/ttLib/tables/G_V_A_R_.py +5 -0
- fontTools/ttLib/tables/S__i_l_f.py +2 -2
- fontTools/ttLib/tables/T_S_I__0.py +14 -3
- fontTools/ttLib/tables/T_S_I__1.py +2 -5
- fontTools/ttLib/tables/T_S_I__5.py +18 -7
- fontTools/ttLib/tables/__init__.py +1 -0
- fontTools/ttLib/tables/_a_v_a_r.py +12 -3
- fontTools/ttLib/tables/_c_m_a_p.py +20 -7
- fontTools/ttLib/tables/_c_v_t.py +3 -2
- fontTools/ttLib/tables/_f_p_g_m.py +3 -1
- fontTools/ttLib/tables/_g_l_y_f.py +45 -21
- fontTools/ttLib/tables/_g_v_a_r.py +67 -19
- fontTools/ttLib/tables/_h_d_m_x.py +4 -4
- fontTools/ttLib/tables/_h_m_t_x.py +7 -3
- fontTools/ttLib/tables/_l_o_c_a.py +2 -2
- fontTools/ttLib/tables/_n_a_m_e.py +11 -6
- fontTools/ttLib/tables/_p_o_s_t.py +9 -7
- fontTools/ttLib/tables/otBase.py +5 -12
- fontTools/ttLib/tables/otConverters.py +5 -2
- fontTools/ttLib/tables/otData.py +1 -1
- fontTools/ttLib/tables/otTables.py +33 -30
- fontTools/ttLib/tables/otTraverse.py +2 -1
- fontTools/ttLib/tables/sbixStrike.py +3 -3
- fontTools/ttLib/ttFont.py +666 -120
- fontTools/ttLib/ttGlyphSet.py +0 -10
- fontTools/ttLib/woff2.py +10 -13
- fontTools/ttx.py +13 -1
- fontTools/ufoLib/__init__.py +300 -202
- fontTools/ufoLib/converters.py +103 -30
- fontTools/ufoLib/errors.py +8 -0
- fontTools/ufoLib/etree.py +1 -1
- fontTools/ufoLib/filenames.py +171 -106
- fontTools/ufoLib/glifLib.py +303 -205
- fontTools/ufoLib/kerning.py +98 -48
- fontTools/ufoLib/utils.py +46 -15
- fontTools/ufoLib/validators.py +121 -99
- fontTools/unicodedata/Blocks.py +35 -20
- fontTools/unicodedata/Mirrored.py +446 -0
- fontTools/unicodedata/ScriptExtensions.py +63 -37
- fontTools/unicodedata/Scripts.py +173 -152
- fontTools/unicodedata/__init__.py +10 -2
- fontTools/varLib/__init__.py +198 -109
- 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/featureVars.py +21 -7
- fontTools/varLib/hvar.py +113 -0
- fontTools/varLib/instancer/__init__.py +180 -65
- fontTools/varLib/interpolatableHelpers.py +3 -0
- fontTools/varLib/iup.c +7564 -6903
- fontTools/varLib/iup.cpython-313-aarch64-linux-musl.so +0 -0
- fontTools/varLib/models.py +17 -2
- fontTools/varLib/mutator.py +11 -0
- fontTools/varLib/varStore.py +10 -38
- fontTools/voltLib/__main__.py +206 -0
- fontTools/voltLib/ast.py +4 -0
- fontTools/voltLib/parser.py +16 -8
- fontTools/voltLib/voltToFea.py +347 -166
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info}/METADATA +269 -1410
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info}/RECORD +318 -294
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info}/WHEEL +1 -1
- fonttools-4.61.1.dist-info/licenses/LICENSE.external +388 -0
- {fonttools-4.55.4.data → fonttools-4.61.1.data}/data/share/man/man1/ttx.1 +0 -0
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info}/entry_points.txt +0 -0
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info/licenses}/LICENSE +0 -0
- {fonttools-4.55.4.dist-info → fonttools-4.61.1.dist-info}/top_level.txt +0 -0
fontTools/feaLib/builder.py
CHANGED
|
@@ -29,8 +29,10 @@ 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
|
|
35
|
+
from fontTools.varLib.errors import VarLibError
|
|
34
36
|
from fontTools.varLib.varStore import OnlineVarStoreBuilder
|
|
35
37
|
from fontTools.varLib.builder import buildVarDevTable
|
|
36
38
|
from fontTools.varLib.featureVars import addFeatureVariationsRaw
|
|
@@ -126,6 +128,7 @@ class Builder(object):
|
|
|
126
128
|
self.script_ = None
|
|
127
129
|
self.lookupflag_ = 0
|
|
128
130
|
self.lookupflag_markFilterSet_ = None
|
|
131
|
+
self.use_extension_ = False
|
|
129
132
|
self.language_systems = set()
|
|
130
133
|
self.seen_non_DFLT_script_ = False
|
|
131
134
|
self.named_lookups_ = {}
|
|
@@ -141,6 +144,7 @@ class Builder(object):
|
|
|
141
144
|
self.aalt_features_ = [] # [(location, featureName)*], for 'aalt'
|
|
142
145
|
self.aalt_location_ = None
|
|
143
146
|
self.aalt_alternates_ = {}
|
|
147
|
+
self.aalt_use_extension_ = False
|
|
144
148
|
# for 'featureNames'
|
|
145
149
|
self.featureNames_ = set()
|
|
146
150
|
self.featureNames_ids_ = {}
|
|
@@ -247,6 +251,7 @@ class Builder(object):
|
|
|
247
251
|
result = builder_class(self.font, location)
|
|
248
252
|
result.lookupflag = self.lookupflag_
|
|
249
253
|
result.markFilterSet = self.lookupflag_markFilterSet_
|
|
254
|
+
result.extension = self.use_extension_
|
|
250
255
|
self.lookups_.append(result)
|
|
251
256
|
return result
|
|
252
257
|
|
|
@@ -255,12 +260,13 @@ class Builder(object):
|
|
|
255
260
|
key = (script, lang, feature_name)
|
|
256
261
|
self.features_.setdefault(key, []).append(lookup)
|
|
257
262
|
|
|
258
|
-
def get_lookup_(self, location, builder_class):
|
|
263
|
+
def get_lookup_(self, location, builder_class, mapping=None):
|
|
259
264
|
if (
|
|
260
265
|
self.cur_lookup_
|
|
261
266
|
and type(self.cur_lookup_) == builder_class
|
|
262
267
|
and self.cur_lookup_.lookupflag == self.lookupflag_
|
|
263
268
|
and self.cur_lookup_.markFilterSet == self.lookupflag_markFilterSet_
|
|
269
|
+
and self.cur_lookup_.can_add_mapping(mapping)
|
|
264
270
|
):
|
|
265
271
|
return self.cur_lookup_
|
|
266
272
|
if self.cur_lookup_name_ and self.cur_lookup_:
|
|
@@ -272,6 +278,7 @@ class Builder(object):
|
|
|
272
278
|
self.cur_lookup_ = builder_class(self.font, location)
|
|
273
279
|
self.cur_lookup_.lookupflag = self.lookupflag_
|
|
274
280
|
self.cur_lookup_.markFilterSet = self.lookupflag_markFilterSet_
|
|
281
|
+
self.cur_lookup_.extension = self.use_extension_
|
|
275
282
|
self.lookups_.append(self.cur_lookup_)
|
|
276
283
|
if self.cur_lookup_name_:
|
|
277
284
|
# We are starting a lookup rule inside a named lookup block.
|
|
@@ -323,7 +330,7 @@ class Builder(object):
|
|
|
323
330
|
}
|
|
324
331
|
old_lookups = self.lookups_
|
|
325
332
|
self.lookups_ = []
|
|
326
|
-
self.start_feature(self.aalt_location_, "aalt")
|
|
333
|
+
self.start_feature(self.aalt_location_, "aalt", self.aalt_use_extension_)
|
|
327
334
|
if single:
|
|
328
335
|
single_lookup = self.get_lookup_(location, SingleSubstBuilder)
|
|
329
336
|
single_lookup.mapping = single
|
|
@@ -341,6 +348,7 @@ class Builder(object):
|
|
|
341
348
|
table = self.font["head"] = newTable("head")
|
|
342
349
|
table.decompile(b"\0" * 54, self.font)
|
|
343
350
|
table.tableVersion = 1.0
|
|
351
|
+
table.magicNumber = 0x5F0F3CF5
|
|
344
352
|
table.created = table.modified = 3406620153 # 2011-12-13 11:22:33
|
|
345
353
|
table.fontRevision = self.fontRevision_
|
|
346
354
|
|
|
@@ -727,10 +735,16 @@ class Builder(object):
|
|
|
727
735
|
result.table = base
|
|
728
736
|
return result
|
|
729
737
|
|
|
738
|
+
def buildBASECoord(self, c):
|
|
739
|
+
coord = otTables.BaseCoord()
|
|
740
|
+
coord.Format = 1
|
|
741
|
+
coord.Coordinate = c
|
|
742
|
+
return coord
|
|
743
|
+
|
|
730
744
|
def buildBASEAxis(self, axis):
|
|
731
745
|
if not axis:
|
|
732
746
|
return
|
|
733
|
-
bases, scripts = axis
|
|
747
|
+
bases, scripts, minmax = axis
|
|
734
748
|
axis = otTables.Axis()
|
|
735
749
|
axis.BaseTagList = otTables.BaseTagList()
|
|
736
750
|
axis.BaseTagList.BaselineTag = bases
|
|
@@ -739,19 +753,35 @@ class Builder(object):
|
|
|
739
753
|
axis.BaseScriptList.BaseScriptRecord = []
|
|
740
754
|
axis.BaseScriptList.BaseScriptCount = len(scripts)
|
|
741
755
|
for script in sorted(scripts):
|
|
756
|
+
minmax_for_script = [
|
|
757
|
+
record[1:] for record in minmax if record[0] == script[0]
|
|
758
|
+
]
|
|
742
759
|
record = otTables.BaseScriptRecord()
|
|
743
760
|
record.BaseScriptTag = script[0]
|
|
744
761
|
record.BaseScript = otTables.BaseScript()
|
|
745
|
-
record.BaseScript.BaseLangSysCount = 0
|
|
746
762
|
record.BaseScript.BaseValues = otTables.BaseValues()
|
|
747
763
|
record.BaseScript.BaseValues.DefaultIndex = bases.index(script[1])
|
|
748
764
|
record.BaseScript.BaseValues.BaseCoord = []
|
|
749
765
|
record.BaseScript.BaseValues.BaseCoordCount = len(script[2])
|
|
766
|
+
record.BaseScript.BaseLangSysRecord = []
|
|
767
|
+
|
|
750
768
|
for c in script[2]:
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
769
|
+
record.BaseScript.BaseValues.BaseCoord.append(self.buildBASECoord(c))
|
|
770
|
+
for language, min_coord, max_coord in sorted(minmax_for_script):
|
|
771
|
+
minmax_record = otTables.MinMax()
|
|
772
|
+
minmax_record.MinCoord = self.buildBASECoord(min_coord)
|
|
773
|
+
minmax_record.MaxCoord = self.buildBASECoord(max_coord)
|
|
774
|
+
minmax_record.FeatMinMaxCount = 0
|
|
775
|
+
if language == "dflt":
|
|
776
|
+
record.BaseScript.DefaultMinMax = minmax_record
|
|
777
|
+
else:
|
|
778
|
+
lang_record = otTables.BaseLangSysRecord()
|
|
779
|
+
lang_record.BaseLangSysTag = language
|
|
780
|
+
lang_record.MinMax = minmax_record
|
|
781
|
+
record.BaseScript.BaseLangSysRecord.append(lang_record)
|
|
782
|
+
record.BaseScript.BaseLangSysCount = len(
|
|
783
|
+
record.BaseScript.BaseLangSysRecord
|
|
784
|
+
)
|
|
755
785
|
axis.BaseScriptList.BaseScriptRecord.append(record)
|
|
756
786
|
return axis
|
|
757
787
|
|
|
@@ -839,13 +869,22 @@ class Builder(object):
|
|
|
839
869
|
for lookup in self.lookups_:
|
|
840
870
|
if lookup.table != tag:
|
|
841
871
|
continue
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
872
|
+
name = self.get_lookup_name_(lookup)
|
|
873
|
+
resolved = lookup.promote_lookup_type(is_named_lookup=name is not None)
|
|
874
|
+
if resolved is None:
|
|
875
|
+
raise FeatureLibError(
|
|
876
|
+
"Within a named lookup block, all rules must be of "
|
|
877
|
+
"the same lookup type and flag",
|
|
878
|
+
lookup.location,
|
|
879
|
+
)
|
|
880
|
+
for l in resolved:
|
|
881
|
+
lookup.lookup_index = len(lookups)
|
|
882
|
+
self.lookup_locations[tag][str(lookup.lookup_index)] = LookupDebugInfo(
|
|
883
|
+
location=str(lookup.location),
|
|
884
|
+
name=name,
|
|
885
|
+
feature=None,
|
|
886
|
+
)
|
|
887
|
+
lookups.append(l)
|
|
849
888
|
otLookups = []
|
|
850
889
|
for l in lookups:
|
|
851
890
|
try:
|
|
@@ -888,6 +927,11 @@ class Builder(object):
|
|
|
888
927
|
l.lookup_index for l in lookups if l.lookup_index is not None
|
|
889
928
|
)
|
|
890
929
|
)
|
|
930
|
+
# order doesn't matter, but lookup_indices preserves it.
|
|
931
|
+
# We want to combine identical sets of lookups (order doesn't matter)
|
|
932
|
+
# but also respect the order provided by the user (although there's
|
|
933
|
+
# a reasonable argument to just sort and dedupe, which fontc does)
|
|
934
|
+
lookup_key = frozenset(lookup_indices)
|
|
891
935
|
|
|
892
936
|
size_feature = tag == "GPOS" and feature_tag == "size"
|
|
893
937
|
force_feature = self.any_feature_variations(feature_tag, tag)
|
|
@@ -905,7 +949,7 @@ class Builder(object):
|
|
|
905
949
|
"stash debug information. See fonttools#2065."
|
|
906
950
|
)
|
|
907
951
|
|
|
908
|
-
feature_key = (feature_tag,
|
|
952
|
+
feature_key = (feature_tag, lookup_key)
|
|
909
953
|
feature_index = feature_indices.get(feature_key)
|
|
910
954
|
if feature_index is None:
|
|
911
955
|
feature_index = len(table.FeatureList.FeatureRecord)
|
|
@@ -1031,15 +1075,22 @@ class Builder(object):
|
|
|
1031
1075
|
else:
|
|
1032
1076
|
return frozenset({("DFLT", "dflt")})
|
|
1033
1077
|
|
|
1034
|
-
def start_feature(self, location, name):
|
|
1078
|
+
def start_feature(self, location, name, use_extension=False):
|
|
1079
|
+
if use_extension and name != "aalt":
|
|
1080
|
+
raise FeatureLibError(
|
|
1081
|
+
"'useExtension' keyword for feature blocks is allowed only for 'aalt' feature",
|
|
1082
|
+
location,
|
|
1083
|
+
)
|
|
1035
1084
|
self.language_systems = self.get_default_language_systems_()
|
|
1036
1085
|
self.script_ = "DFLT"
|
|
1037
1086
|
self.cur_lookup_ = None
|
|
1038
1087
|
self.cur_feature_name_ = name
|
|
1039
1088
|
self.lookupflag_ = 0
|
|
1040
1089
|
self.lookupflag_markFilterSet_ = None
|
|
1090
|
+
self.use_extension_ = use_extension
|
|
1041
1091
|
if name == "aalt":
|
|
1042
1092
|
self.aalt_location_ = location
|
|
1093
|
+
self.aalt_use_extension_ = use_extension
|
|
1043
1094
|
|
|
1044
1095
|
def end_feature(self):
|
|
1045
1096
|
assert self.cur_feature_name_ is not None
|
|
@@ -1048,8 +1099,9 @@ class Builder(object):
|
|
|
1048
1099
|
self.cur_lookup_ = None
|
|
1049
1100
|
self.lookupflag_ = 0
|
|
1050
1101
|
self.lookupflag_markFilterSet_ = None
|
|
1102
|
+
self.use_extension_ = False
|
|
1051
1103
|
|
|
1052
|
-
def start_lookup_block(self, location, name):
|
|
1104
|
+
def start_lookup_block(self, location, name, use_extension=False):
|
|
1053
1105
|
if name in self.named_lookups_:
|
|
1054
1106
|
raise FeatureLibError(
|
|
1055
1107
|
'Lookup "%s" has already been defined' % name, location
|
|
@@ -1063,6 +1115,7 @@ class Builder(object):
|
|
|
1063
1115
|
self.cur_lookup_name_ = name
|
|
1064
1116
|
self.named_lookups_[name] = None
|
|
1065
1117
|
self.cur_lookup_ = None
|
|
1118
|
+
self.use_extension_ = use_extension
|
|
1066
1119
|
if self.cur_feature_name_ is None:
|
|
1067
1120
|
self.lookupflag_ = 0
|
|
1068
1121
|
self.lookupflag_markFilterSet_ = None
|
|
@@ -1071,6 +1124,7 @@ class Builder(object):
|
|
|
1071
1124
|
assert self.cur_lookup_name_ is not None
|
|
1072
1125
|
self.cur_lookup_name_ = None
|
|
1073
1126
|
self.cur_lookup_ = None
|
|
1127
|
+
self.use_extension_ = False
|
|
1074
1128
|
if self.cur_feature_name_ is None:
|
|
1075
1129
|
self.lookupflag_ = 0
|
|
1076
1130
|
self.lookupflag_markFilterSet_ = None
|
|
@@ -1106,7 +1160,13 @@ class Builder(object):
|
|
|
1106
1160
|
if (language == "dflt" or include_default) and lookups:
|
|
1107
1161
|
self.features_[key] = lookups[:]
|
|
1108
1162
|
else:
|
|
1109
|
-
|
|
1163
|
+
# if we aren't including default we need to manually remove the
|
|
1164
|
+
# default lookups, which were added to all declared langsystems
|
|
1165
|
+
# as they were encountered (we don't remove all lookups because
|
|
1166
|
+
# we want to allow duplicate script/lang statements;
|
|
1167
|
+
# see https://github.com/fonttools/fonttools/issues/3748
|
|
1168
|
+
cur_lookups = self.features_.get(key, [])
|
|
1169
|
+
self.features_[key] = [x for x in cur_lookups if x not in lookups]
|
|
1110
1170
|
self.language_systems = frozenset([(self.script_, language)])
|
|
1111
1171
|
|
|
1112
1172
|
if required:
|
|
@@ -1153,10 +1213,10 @@ class Builder(object):
|
|
|
1153
1213
|
|
|
1154
1214
|
def set_lookup_flag(self, location, value, markAttach, markFilter):
|
|
1155
1215
|
value = value & 0xFF
|
|
1156
|
-
if markAttach:
|
|
1216
|
+
if markAttach is not None:
|
|
1157
1217
|
markAttachClass = self.getMarkAttachClass_(location, markAttach)
|
|
1158
1218
|
value = value | (markAttachClass << 8)
|
|
1159
|
-
if markFilter:
|
|
1219
|
+
if markFilter is not None:
|
|
1160
1220
|
markFilterSet = self.getMarkFilterSet_(location, markFilter)
|
|
1161
1221
|
value = value | 0x10
|
|
1162
1222
|
self.lookupflag_markFilterSet_ = markFilterSet
|
|
@@ -1229,11 +1289,11 @@ class Builder(object):
|
|
|
1229
1289
|
def add_cv_character(self, character, tag):
|
|
1230
1290
|
self.cv_characters_[tag].append(character)
|
|
1231
1291
|
|
|
1232
|
-
def set_base_axis(self, bases, scripts, vertical):
|
|
1292
|
+
def set_base_axis(self, bases, scripts, vertical, minmax=[]):
|
|
1233
1293
|
if vertical:
|
|
1234
|
-
self.base_vert_axis_ = (bases, scripts)
|
|
1294
|
+
self.base_vert_axis_ = (bases, scripts, minmax)
|
|
1235
1295
|
else:
|
|
1236
|
-
self.base_horiz_axis_ = (bases, scripts)
|
|
1296
|
+
self.base_horiz_axis_ = (bases, scripts, minmax)
|
|
1237
1297
|
|
|
1238
1298
|
def set_size_parameters(
|
|
1239
1299
|
self, location, DesignSize, SubfamilyID, RangeStart, RangeEnd
|
|
@@ -1251,6 +1311,24 @@ class Builder(object):
|
|
|
1251
1311
|
|
|
1252
1312
|
# GSUB rules
|
|
1253
1313
|
|
|
1314
|
+
def add_any_subst_(self, location, mapping):
|
|
1315
|
+
lookup = self.get_lookup_(location, AnySubstBuilder, mapping=mapping)
|
|
1316
|
+
for key, value in mapping.items():
|
|
1317
|
+
if key in lookup.mapping:
|
|
1318
|
+
if value == lookup.mapping[key]:
|
|
1319
|
+
log.info(
|
|
1320
|
+
'Removing duplicate substitution from "%s" to "%s" at %s',
|
|
1321
|
+
", ".join(key),
|
|
1322
|
+
", ".join(value),
|
|
1323
|
+
location,
|
|
1324
|
+
)
|
|
1325
|
+
else:
|
|
1326
|
+
raise FeatureLibError(
|
|
1327
|
+
'Already defined substitution for "%s"' % ", ".join(key),
|
|
1328
|
+
location,
|
|
1329
|
+
)
|
|
1330
|
+
lookup.mapping[key] = value
|
|
1331
|
+
|
|
1254
1332
|
# GSUB 1
|
|
1255
1333
|
def add_single_subst(self, location, prefix, suffix, mapping, forceChain):
|
|
1256
1334
|
if self.cur_feature_name_ == "aalt":
|
|
@@ -1262,24 +1340,11 @@ class Builder(object):
|
|
|
1262
1340
|
if prefix or suffix or forceChain:
|
|
1263
1341
|
self.add_single_subst_chained_(location, prefix, suffix, mapping)
|
|
1264
1342
|
return
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
"Removing duplicate single substitution from glyph"
|
|
1271
|
-
' "%s" to "%s" at %s',
|
|
1272
|
-
from_glyph,
|
|
1273
|
-
to_glyph,
|
|
1274
|
-
location,
|
|
1275
|
-
)
|
|
1276
|
-
else:
|
|
1277
|
-
raise FeatureLibError(
|
|
1278
|
-
'Already defined rule for replacing glyph "%s" by "%s"'
|
|
1279
|
-
% (from_glyph, lookup.mapping[from_glyph]),
|
|
1280
|
-
location,
|
|
1281
|
-
)
|
|
1282
|
-
lookup.mapping[from_glyph] = to_glyph
|
|
1343
|
+
|
|
1344
|
+
self.add_any_subst_(
|
|
1345
|
+
location,
|
|
1346
|
+
{(key,): (value,) for key, value in mapping.items()},
|
|
1347
|
+
)
|
|
1283
1348
|
|
|
1284
1349
|
# GSUB 2
|
|
1285
1350
|
def add_multiple_subst(
|
|
@@ -1288,21 +1353,10 @@ class Builder(object):
|
|
|
1288
1353
|
if prefix or suffix or forceChain:
|
|
1289
1354
|
self.add_multi_subst_chained_(location, prefix, glyph, suffix, replacements)
|
|
1290
1355
|
return
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
"Removing duplicate multiple substitution from glyph"
|
|
1296
|
-
' "%s" to %s%s',
|
|
1297
|
-
glyph,
|
|
1298
|
-
replacements,
|
|
1299
|
-
f" at {location}" if location else "",
|
|
1300
|
-
)
|
|
1301
|
-
else:
|
|
1302
|
-
raise FeatureLibError(
|
|
1303
|
-
'Already defined substitution for glyph "%s"' % glyph, location
|
|
1304
|
-
)
|
|
1305
|
-
lookup.mapping[glyph] = replacements
|
|
1356
|
+
self.add_any_subst_(
|
|
1357
|
+
location,
|
|
1358
|
+
{(glyph,): tuple(replacements)},
|
|
1359
|
+
)
|
|
1306
1360
|
|
|
1307
1361
|
# GSUB 3
|
|
1308
1362
|
def add_alternate_subst(self, location, prefix, glyph, suffix, replacement):
|
|
@@ -1332,9 +1386,6 @@ class Builder(object):
|
|
|
1332
1386
|
location, prefix, glyphs, suffix, replacement
|
|
1333
1387
|
)
|
|
1334
1388
|
return
|
|
1335
|
-
else:
|
|
1336
|
-
lookup = self.get_lookup_(location, LigatureSubstBuilder)
|
|
1337
|
-
|
|
1338
1389
|
if not all(glyphs):
|
|
1339
1390
|
raise FeatureLibError("Empty glyph class in substitution", location)
|
|
1340
1391
|
|
|
@@ -1343,8 +1394,10 @@ class Builder(object):
|
|
|
1343
1394
|
# substitutions to be specified on target sequences that contain
|
|
1344
1395
|
# glyph classes, the implementation software will enumerate
|
|
1345
1396
|
# all specific glyph sequences if glyph classes are detected"
|
|
1346
|
-
|
|
1347
|
-
|
|
1397
|
+
self.add_any_subst_(
|
|
1398
|
+
location,
|
|
1399
|
+
{g: (replacement,) for g in itertools.product(*glyphs)},
|
|
1400
|
+
)
|
|
1348
1401
|
|
|
1349
1402
|
# GSUB 5/6
|
|
1350
1403
|
def add_chain_context_subst(self, location, prefix, glyphs, suffix, lookups):
|
|
@@ -1402,6 +1455,13 @@ class Builder(object):
|
|
|
1402
1455
|
sub = self.get_chained_lookup_(location, LigatureSubstBuilder)
|
|
1403
1456
|
|
|
1404
1457
|
for g in itertools.product(*glyphs):
|
|
1458
|
+
existing = sub.ligatures.get(g, replacement)
|
|
1459
|
+
if existing != replacement:
|
|
1460
|
+
raise FeatureLibError(
|
|
1461
|
+
f"Conflicting ligature sub rules: '{g}' maps to '{existing}' and '{replacement}'",
|
|
1462
|
+
location,
|
|
1463
|
+
)
|
|
1464
|
+
|
|
1405
1465
|
sub.ligatures[g] = replacement
|
|
1406
1466
|
|
|
1407
1467
|
chain.rules.append(ChainContextualRule(prefix, glyphs, suffix, [sub]))
|
|
@@ -1442,7 +1502,9 @@ class Builder(object):
|
|
|
1442
1502
|
lookup = self.get_lookup_(location, PairPosBuilder)
|
|
1443
1503
|
v1 = self.makeOpenTypeValueRecord(location, value1, pairPosContext=True)
|
|
1444
1504
|
v2 = self.makeOpenTypeValueRecord(location, value2, pairPosContext=True)
|
|
1445
|
-
|
|
1505
|
+
cls1 = tuple(sorted(set(glyphclass1)))
|
|
1506
|
+
cls2 = tuple(sorted(set(glyphclass2)))
|
|
1507
|
+
lookup.addClassPair(location, cls1, v1, cls2, v2)
|
|
1446
1508
|
|
|
1447
1509
|
def add_specific_pair_pos(self, location, glyph1, value1, glyph2, value2):
|
|
1448
1510
|
if not glyph1 or not glyph2:
|
|
@@ -1628,6 +1690,12 @@ class Builder(object):
|
|
|
1628
1690
|
location,
|
|
1629
1691
|
)
|
|
1630
1692
|
|
|
1693
|
+
if key in self.conditionsets_:
|
|
1694
|
+
raise FeatureLibError(
|
|
1695
|
+
f"Condition set '{key}' has the same name as a previous condition set",
|
|
1696
|
+
location,
|
|
1697
|
+
)
|
|
1698
|
+
|
|
1631
1699
|
# Normalize
|
|
1632
1700
|
axisMap = {
|
|
1633
1701
|
axis.axisTag: (axis.minValue, axis.defaultValue, axis.maxValue)
|
|
@@ -1667,9 +1735,14 @@ class Builder(object):
|
|
|
1667
1735
|
if not varscalar.does_vary:
|
|
1668
1736
|
return varscalar.default, None
|
|
1669
1737
|
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1738
|
+
try:
|
|
1739
|
+
default, index = varscalar.add_to_variation_store(
|
|
1740
|
+
self.varstorebuilder, self.model_cache, self.font.get("avar")
|
|
1741
|
+
)
|
|
1742
|
+
except VarLibError as e:
|
|
1743
|
+
raise FeatureLibError(
|
|
1744
|
+
"Failed to compute deltas for variable scalar", location
|
|
1745
|
+
) from e
|
|
1673
1746
|
|
|
1674
1747
|
device = None
|
|
1675
1748
|
if index is not None and index != 0xFFFFFFFF:
|
fontTools/feaLib/error.py
CHANGED