Skip to content

Commit fd02a6e

Browse files
committed
instantiate all variable fonts in stack (not just first)
- the previous implementation didn't account for fallbacks handling glyphs not provided by the first-matched typeface - fixes #260
1 parent 719c962 commit fd02a6e

File tree

2 files changed

+49
-44
lines changed

2 files changed

+49
-44
lines changed

src/font_library.rs

Lines changed: 48 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ pub struct FontLibrary{
8383
fn font_collection(&mut self) -> FontCollection{
8484
// lazily initialize font collection on first actual use
8585
if self.collection.is_none(){
86-
// set up generic font family mappings
86+
// set up generic font family mappings (to be used in build_font_collection())
8787
if self.generics.is_empty(){
8888
let mut generics = vec![];
8989
let mut font_stacks = HashMap::new();
@@ -115,7 +115,7 @@ pub struct FontLibrary{
115115
self.generics = generics;
116116
}
117117

118-
self.rebuild_collection(); // assigns to self.collection
118+
self.collection = Some(self.build_font_collection());
119119
};
120120

121121
self.collection.as_ref().unwrap().clone()
@@ -219,10 +219,11 @@ pub struct FontLibrary{
219219

220220
// add the new typeface/alias and recreate the FontCollection to include it
221221
self.fonts.push((font, alias));
222-
self.rebuild_collection();
222+
self.collection = Some(self.build_font_collection());
223+
self.collection_cache.drain();
223224
}
224225

225-
fn rebuild_collection(&mut self){
226+
fn build_font_collection(&self) -> FontCollection{
226227
let mut assets = TypefaceFontProvider::new();
227228
for (font, alias) in &self.generics {
228229
assets.register_typeface(font.clone(), alias.as_deref());
@@ -240,8 +241,7 @@ pub struct FontLibrary{
240241
let mut collection = FontCollection::new();
241242
collection.set_default_font_manager(self.mgr.clone(), default_fam.as_deref());
242243
collection.set_asset_font_manager(Some(assets.into()));
243-
self.collection = Some(collection);
244-
self.collection_cache.drain();
244+
collection
245245
}
246246

247247
pub fn update_style(&mut self, orig_style:&TextStyle, spec: &FontSpec) -> Option<TextStyle>{
@@ -274,32 +274,35 @@ pub struct FontLibrary{
274274
self
275275
}
276276

277-
pub fn collect_fonts(&mut self, style: &TextStyle) -> FontCollection {
277+
pub fn fonts_for_style(&mut self, style: &TextStyle) -> FontCollection {
278278
let families = style.font_families();
279279
let families:Vec<&str> = families.iter().collect();
280280
let matches = self.font_collection().find_typefaces(&families, style.font_style());
281281

282-
// if the matched typeface is a variable font, create an instance that matches
283-
// the current weight settings and return early with a new FontCollection that
284-
// contains just that single font instance
285-
if let Some(font) = matches.first() {
286-
if let Some(params) = font.variation_design_parameters(){
287-
288-
// memoize the generation of single-weight FontCollections for variable fonts
289-
let key = CollectionKey::new(style);
290-
if let Some(collection) = self.collection_cache.get(&key){
291-
return collection.clone()
292-
}
293-
294-
// reconnect to the user-specified family name (if provided)
295-
let alias = self.fonts.iter().find_map(|(face, alias)|
296-
if Typeface::equal(font, face){ alias.clone() }else{ None }
297-
);
282+
// if any of the matched typefaces is a variable font, create an instance that
283+
// matches the current weight settings and add it to a dynamic font mgr
284+
if matches.iter().any(|font| font.variation_design_parameters().is_some()){
285+
// memoize the generation of single-weight FontCollections for variable fonts
286+
let key = CollectionKey::new(style);
287+
if let Some(collection) = self.collection_cache.get(&key){
288+
return collection.clone()
289+
}
298290

299-
for param in params {
300-
let chars = vec![param.tag.a(), param.tag.b(), param.tag.c(), param.tag.d()];
301-
let tag = String::from_utf8(chars).unwrap();
302-
if tag == "wght"{
291+
// collect any instantiated variable fonts in a TFP to be used as the 'dynamic'
292+
// font mgr (which is searched before the 'asset' or the 'default' mgr)
293+
let mut dynamic = TypefaceFontProvider::new();
294+
295+
for font in matches.into_iter(){
296+
font.variation_design_parameters()
297+
.and_then(|params|{
298+
// find the weight axis
299+
params.into_iter().find(|param|{
300+
let chars = vec![param.tag.a(), param.tag.b(), param.tag.c(), param.tag.d()];
301+
let tag = String::from_utf8(chars).unwrap();
302+
tag == "wght"
303+
})
304+
}).and_then(|param|{
305+
// create an instance at the proper 'wght' for this weight
303306
// NB: currently setting the value to *one less* than what was requested
304307
// to work around weird Skia behavior that returns something nonlinearly
305308
// weighted in many cases (but not for ±1 of that value). This makes it so
@@ -310,25 +313,27 @@ pub struct FontLibrary{
310313
let coords = [ Coordinate { axis: param.tag, value } ];
311314
let v_pos = VariationPosition { coordinates: &coords };
312315
let args = FontArguments::new().set_variation_design_position(v_pos);
313-
let face = font.clone_with_arguments(&args).unwrap();
314-
315-
let mut dynamic = TypefaceFontProvider::new();
316-
dynamic.register_typeface(face, alias.as_deref());
317-
318-
let mut collection = FontCollection::new();
319-
collection.set_default_font_manager(self.mgr.clone(), None);
320-
collection.set_asset_font_manager(Some(dynamic.into()));
321-
self.collection_cache.insert(key, collection.clone());
322-
return collection
323-
}
324-
}
316+
font.clone_with_arguments(&args)
317+
}).map(|face|{
318+
// maintain the user-defined family alias (if applicable)
319+
let alias = self.fonts.iter().find_map(|(orig, alias)|
320+
if Typeface::equal(&font, orig){ alias.clone() }else{ None }
321+
);
322+
323+
// add the font to the dynamic font mgr
324+
dynamic.register_typeface(face, alias.as_deref())
325+
});
325326
}
326-
}
327327

328-
// if the matched font wasn't variable, then just return the standard collection
329-
self.font_collection()
328+
let mut collection = self.build_font_collection();
329+
collection.set_dynamic_font_manager(Some(dynamic.into()));
330+
self.collection_cache.insert(key, collection.clone());
331+
collection
332+
}else{
333+
// if the matched font wasn't variable, then just return the standard collection
334+
self.font_collection()
335+
}
330336
}
331-
332337
}
333338

334339
//

src/typography.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ impl Typesetter{
3737
let typefaces = FontLibrary::with_shared(|lib|
3838
lib
3939
.set_hinting(graf_style.hinting_is_on())
40-
.collect_fonts(&char_style)
40+
.fonts_for_style(&char_style)
4141
);
4242
let width = width.unwrap_or(GALLEY);
4343
let text = match text_wrap{

0 commit comments

Comments
 (0)