11use std:: collections:: hash_map:: DefaultHasher ;
2- use std:: collections:: HashMap ;
2+ use std:: collections:: { HashMap , HashSet } ;
33use std:: hash:: { Hash , Hasher } ;
44
55use imgref:: ImgVec ;
@@ -124,6 +124,22 @@ fn glyph_image_is_visible(img: &Image) -> bool {
124124 img. placement . width > 0 && img. placement . height > 0 && !img. data . is_empty ( )
125125}
126126
127+ fn font_weight ( bold : bool ) -> fontdb:: Weight {
128+ if bold {
129+ fontdb:: Weight :: BOLD
130+ } else {
131+ fontdb:: Weight :: NORMAL
132+ }
133+ }
134+
135+ fn font_style ( italic : bool ) -> fontdb:: Style {
136+ if italic {
137+ fontdb:: Style :: Italic
138+ } else {
139+ fontdb:: Style :: Normal
140+ }
141+ }
142+
127143impl SwashRenderer {
128144 pub fn new ( settings : Settings ) -> Self {
129145 let col_width = col_width ( & settings. font_db , & settings. text_family , settings. font_size )
@@ -155,21 +171,16 @@ impl SwashRenderer {
155171 }
156172
157173 fn get_font_id ( & mut self , name : & str , bold : bool , italic : bool ) -> & Option < fontdb:: ID > {
158- let weight = if bold {
159- fontdb:: Weight :: BOLD
160- } else {
161- fontdb:: Weight :: NORMAL
162- } ;
163-
164- let style = if italic {
165- fontdb:: Style :: Italic
166- } else {
167- fontdb:: Style :: Normal
168- } ;
169-
170174 self . font_id_cache
171175 . entry ( ( name. to_owned ( ) , bold, italic) )
172- . or_insert_with ( || get_font_id ( & self . font_db , & [ name] , weight, style) )
176+ . or_insert_with ( || {
177+ get_font_id (
178+ & self . font_db ,
179+ & [ name] ,
180+ font_weight ( bold) ,
181+ font_style ( italic) ,
182+ )
183+ } )
173184 }
174185
175186 fn ensure_glyph ( & mut self , ch : char , bold : bool , italic : bool ) {
@@ -179,13 +190,28 @@ impl SwashRenderer {
179190 return ;
180191 }
181192
182- if let Some ( glyph) = self . rasterize_glyph ( ch, bold, italic) {
193+ let mut tried_font_ids = HashSet :: new ( ) ;
194+
195+ if let Some ( glyph) = self . rasterize_family_glyph ( ch, bold, italic, & mut tried_font_ids) {
183196 self . glyph_cache . insert ( key, Some ( glyph) ) ;
184197 return ;
185198 }
186199
187200 if bold || italic {
188- if let Some ( glyph) = self . rasterize_glyph ( ch, false , false ) {
201+ if let Some ( glyph) = self . rasterize_family_glyph ( ch, false , false , & mut tried_font_ids)
202+ {
203+ self . glyph_cache . insert ( key, Some ( glyph) ) ;
204+ return ;
205+ }
206+ }
207+
208+ if let Some ( glyph) = self . rasterize_fallback_glyph ( ch, bold, italic, & tried_font_ids) {
209+ self . glyph_cache . insert ( key, Some ( glyph) ) ;
210+ return ;
211+ }
212+
213+ if bold || italic {
214+ if let Some ( glyph) = self . rasterize_fallback_glyph ( ch, false , false , & tried_font_ids) {
189215 self . glyph_cache . insert ( key, Some ( glyph) ) ;
190216 return ;
191217 }
@@ -200,14 +226,52 @@ impl SwashRenderer {
200226 . expect ( "caller must invoke ensure_glyph first" )
201227 }
202228
203- fn rasterize_glyph ( & mut self , ch : char , bold : bool , italic : bool ) -> Option < Image > {
229+ fn rasterize_family_glyph (
230+ & mut self ,
231+ ch : char ,
232+ bold : bool ,
233+ italic : bool ,
234+ tried_font_ids : & mut HashSet < fontdb:: ID > ,
235+ ) -> Option < Image > {
204236 let families = self . font_families . clone ( ) ;
205237
206238 for name in & families {
207239 let Some ( font_id) = * self . get_font_id ( name, bold, italic) else {
208240 continue ;
209241 } ;
210242
243+ tried_font_ids. insert ( font_id) ;
244+
245+ if let Some ( glyph) = self . rasterize_font_glyph ( font_id, ch) {
246+ return Some ( glyph) ;
247+ }
248+ }
249+
250+ None
251+ }
252+
253+ fn rasterize_fallback_glyph (
254+ & mut self ,
255+ ch : char ,
256+ bold : bool ,
257+ italic : bool ,
258+ tried_font_ids : & HashSet < fontdb:: ID > ,
259+ ) -> Option < Image > {
260+ let weight = font_weight ( bold) ;
261+ let style = font_style ( italic) ;
262+
263+ // Match resvg/usvg behavior: if configured families miss, try any
264+ // loaded face so system fonts and --font-dir fonts can cover unlisted scripts.
265+ let fallback_font_ids: Vec < _ > = self
266+ . font_db
267+ . faces ( )
268+ . filter ( |face| {
269+ !tried_font_ids. contains ( & face. id ) && face. weight == weight && face. style == style
270+ } )
271+ . map ( |face| face. id )
272+ . collect ( ) ;
273+
274+ for font_id in fallback_font_ids {
211275 if let Some ( glyph) = self . rasterize_font_glyph ( font_id, ch) {
212276 return Some ( glyph) ;
213277 }
0 commit comments