1
1
from collections import defaultdict
2
2
from functools import partial
3
3
from typing import Any
4
- import copy
5
4
6
5
from fontTools import designspaceLib
7
6
from fontTools .varLib import FEAVAR_FEATURETAG_LIB_KEY
@@ -23,8 +22,6 @@ def to_designspace_bracket_layers(self):
23
22
"Cannot apply bracket layers unless at least one axis is defined."
24
23
)
25
24
26
- find_component_use (self )
27
-
28
25
# At this stage we will naively emit a designspace rule for every layer.
29
26
bracket_layer_map = defaultdict (partial (defaultdict , list ))
30
27
rules = []
@@ -170,122 +167,3 @@ def _expand_kerning_to_brackets(
170
167
elif second_match :
171
168
bracket_kerning [(first , ufo_glyph_name )] = value
172
169
ufo_font .kerning .update (bracket_kerning )
173
-
174
-
175
- def find_component_use (self ):
176
- """If a glyph uses a component which has alternate layers, that
177
- glyph also must have the same alternate layers or else it will not
178
- correctly swap. We copy the layer locations from the component into
179
- the glyph which uses it."""
180
- # First let's put all the layers in a sensible order so we can
181
- # query them efficiently
182
- master_layers = defaultdict (dict )
183
- alternate_layers = defaultdict (lambda : defaultdict (list ))
184
- master_ids = set (master .id for master in self .font .masters )
185
-
186
- for glyph in self .font .glyphs :
187
- for layer in glyph .layers :
188
- if layer .layerId in master_ids :
189
- master_layers [layer .layerId ][glyph .name ] = layer
190
- elif layer .associatedMasterId in master_ids :
191
- alternate_layers [layer .associatedMasterId ][glyph .name ].append (layer )
192
-
193
- # Now let's find those which have a problem: they use components,
194
- # the components have some alternate layers, but the layer doesn't
195
- # have the same.
196
- # Because of the possibility of deeply nested components, we need
197
- # to keep doing this, bubbling up fixes until there's nothing left
198
- # to do.
199
- while True :
200
- problematic_glyphs = defaultdict (set )
201
- for master , layers in master_layers .items ():
202
- for glyph_name , layer in layers .items ():
203
- my_bracket_layers = [
204
- layer ._bracket_info (self ._designspace .axes )
205
- for layer in alternate_layers [master ][glyph_name ]
206
- ]
207
- for comp in layer .components :
208
- # Check our alternate layer set-up agrees with theirs
209
- components_bracket_layers = [
210
- layer ._bracket_info (self ._designspace .axes )
211
- for layer in alternate_layers [master ][comp .name ]
212
- ]
213
- if my_bracket_layers != components_bracket_layers :
214
- # Find what we need to add, and make them hashable
215
- they_have = set (
216
- tuple (x .items ())
217
- for x in components_bracket_layers
218
- if x .items ()
219
- )
220
- i_have = set (
221
- tuple (x .items ()) for x in my_bracket_layers if x .items ()
222
- )
223
- needed = they_have - i_have
224
- if needed :
225
- problematic_glyphs [(glyph_name , master )] |= needed
226
-
227
- if not problematic_glyphs :
228
- break
229
-
230
- # And now, fix the problem.
231
- for (glyph_name , master ), needed_brackets in problematic_glyphs .items ():
232
- my_bracket_layers = [
233
- layer ._bracket_info (self ._designspace .axes )
234
- for layer in alternate_layers [master ][glyph_name ]
235
- ]
236
- if my_bracket_layers :
237
- # We have some bracket layers, but they're not the ones we
238
- # expect. Do the wrong thing, because doing the right thing
239
- # requires major investment.
240
- master_name = self .font .masters [master ].name
241
- self .logger .warning (
242
- f"Glyph { glyph_name } in master { master_name } has different "
243
- "alternate layers to components that it uses. We don't "
244
- "currently support this case, so some alternate layers will "
245
- "not be applied. Consider fixing the source instead."
246
- )
247
- # Just copy the master layer for each thing we need.
248
- for box in needed_brackets :
249
- new_layer = synthesize_bracket_layer (
250
- master_layers [master ][glyph_name ], dict (box ), self ._designspace .axes
251
- )
252
- self .font .glyphs [glyph_name ].layers .append (new_layer )
253
- self .bracket_layers .append (new_layer )
254
- alternate_layers [master ][glyph_name ].append (new_layer )
255
-
256
- # any components have now just been appended to the end; let's sort bracket
257
- # layers by glyph order to maintain a consistent, understandable order.
258
- glyphOrder = {g .name : i for (i , g ) in enumerate (self .font .glyphs )}
259
- self .bracket_layers .sort (key = lambda layer : glyphOrder .get (layer .parent .name ))
260
-
261
-
262
- def synthesize_bracket_layer (old_layer , box , axes ):
263
- new_layer = copy .copy (old_layer ) # We don't need a deep copy of everything
264
- new_layer .layerId = ""
265
- new_layer .associatedMasterId = old_layer .layerId
266
-
267
- if new_layer .parent .parent .format_version == 2 :
268
- axis , (bottom , top ) = next (iter (box .items ()))
269
- designspace_min , designspace_max = util .designspace_min_max (axes [0 ])
270
- if designspace_min == bottom :
271
- new_layer .name = old_layer .name + f" ]{ top } ]"
272
- else :
273
- new_layer .name = old_layer .name + f"[{ bottom } ]"
274
- else :
275
- new_layer .attributes = dict (
276
- new_layer .attributes
277
- ) # But we do need our own version of this
278
- new_layer .attributes ["axisRules" ] = []
279
- for axis in axes :
280
- if axis .tag in box :
281
- new_layer .attributes ["axisRules" ].append (
282
- {
283
- "min" : box [axis .tag ][0 ],
284
- "max" : box [axis .tag ][1 ],
285
- }
286
- )
287
- else :
288
- new_layer .attributes ["axisRules" ].append ({})
289
-
290
- assert new_layer ._bracket_info (axes ) == box
291
- return new_layer
0 commit comments