@@ -52,7 +52,7 @@ def union(self, other: "Rect") -> "Rect":
5252
5353class TextRun (NamedTuple ):
5454 font : "Font"
55- features : str
55+ features : Features
5656 location : str
5757 string : str
5858
@@ -216,54 +216,13 @@ def _make_glyphs(
216216 )
217217 return GlyphRun (font = self , location = location , glyphs = glyphs )
218218
219- @staticmethod
220- def _parse_features (text : str ) -> Features :
221- if not text :
222- return {}
223- features = {}
224- for feature in text .split ("," ):
225- value = None
226- start = None
227- end = None
228-
229- feature = feature .strip ()
230- if feature [0 ] == "-" :
231- value = 0
232- if feature [0 ] in ("+" , "-" ):
233- feature = feature [1 :]
234- tag = feature
235- if "[" in tag :
236- assert "]" in tag , f"Invalid feature tag: { tag } "
237- tag , extra = tag .split ("[" )
238- extra , tag2 = extra .split ("]" )
239- tag += tag2
240- start = end = extra
241- if ":" in extra :
242- start , end = extra .split (":" )
243- if "=" in tag :
244- tag , value = tag .split ("=" )
245- if value is None :
246- value = 1
247- if start is None or start == "" :
248- start = 0
249- if end is None or end == "" :
250- end = 0xFFFFFFFF
251- features .setdefault (tag , []).append ([int (start ), int (end ), int (value )])
252- for tag , value in features .items ():
253- if len (value ) != 1 :
254- continue
255- if value [0 ][:2 ] == [0 , 0xFFFFFFFF ]:
256- features [tag ] = value [0 ][2 ]
257- return features
258-
259219 def shape (
260220 self ,
261221 text : str ,
262222 location : Location ,
263- features : str ,
223+ features : Features ,
264224 ) -> Tuple [GlyphRun , float ]:
265225 buf = hb .Buffer ()
266- features = self ._parse_features (features )
267226 width = self ._shape (buf , text , location , features )
268227 glyphs = self ._make_glyphs (buf , location )
269228 return glyphs , width
@@ -272,11 +231,10 @@ def shape_justify(
272231 self ,
273232 text : str ,
274233 location : Location ,
275- features : str ,
234+ features : Features ,
276235 target_width : float ,
277236 ) -> Tuple [GlyphRun , float ]:
278237 buf = hb .Buffer ()
279- features = self ._parse_features (features )
280238
281239 width = self ._shape (buf , text , location , features )
282240 if width >= target_width :
@@ -524,6 +482,8 @@ def draw(
524482 x = 0
525483 fonts = [Font (font_path ) for font_path in font_paths ]
526484
485+ features : Features = parseFeatures (features )
486+
527487 fonts_locations = []
528488 if len (fonts ) == 1 :
529489 fonts_locations = [(fonts [0 ], location ) for location in fonts [0 ].locations ]
@@ -581,6 +541,46 @@ def parseColor(color):
581541 return tuple (int (color [i : i + 2 ], 16 ) / 255 for i in (0 , 2 , 4 )) + (1 ,)
582542
583543
544+ def parseFeatures (text : str ) -> Features :
545+ if not text :
546+ return {}
547+ features = {}
548+ for feature in text .split ("," ):
549+ value = None
550+ start = None
551+ end = None
552+
553+ feature = feature .strip ()
554+ if feature [0 ] == "-" :
555+ value = 0
556+ if feature [0 ] in ("+" , "-" ):
557+ feature = feature [1 :]
558+ tag = feature
559+ if "[" in tag :
560+ assert "]" in tag , f"Invalid feature tag: { tag } "
561+ tag , extra = tag .split ("[" )
562+ extra , tag2 = extra .split ("]" )
563+ tag += tag2
564+ start = end = extra
565+ if ":" in extra :
566+ start , end = extra .split (":" )
567+ if "=" in tag :
568+ tag , value = tag .split ("=" )
569+ if value is None :
570+ value = 1
571+ if start is None or start == "" :
572+ start = 0
573+ if end is None or end == "" :
574+ end = 0xFFFFFFFF
575+ features .setdefault (tag , []).append ([int (start ), int (end ), int (value )])
576+ for tag , value in features .items ():
577+ if len (value ) != 1 :
578+ continue
579+ if value [0 ][:2 ] == [0 , 0xFFFFFFFF ]:
580+ features [tag ] = value [0 ][2 ]
581+ return features
582+
583+
584584def main (argv = None ):
585585 parser = argparse .ArgumentParser (description = "Create SVG sample." )
586586 parser .add_argument ("fonts" , help = "input font" , nargs = "+" , type = pathlib .Path )
0 commit comments