| ... | @@ -1,7 +1,8 @@ | ... | @@ -1,7 +1,8 @@ |
| 1 | use onestore::page::text::Paragraph; | 1 | use onestore::page::text::Paragraph; |
| 2 | use parley::{ | 2 | use parley::{ |
| 3 | Affinity, Alignment, AlignmentOptions, BoundingBox, FontContext, FontFamily, FontStyle, | 3 | Affinity, Alignment, AlignmentOptions, BoundingBox, FontContext, FontFamily, FontFamilyName, |
| 4 | FontWeight, Layout, LayoutContext, OverflowWrap, PositionedLayoutItem, StyleProperty, | 4 | FontStyle, FontWeight, GenericFamily, Layout, LayoutContext, OverflowWrap, |
| | 5 | PositionedLayoutItem, StyleProperty, |
| 5 | editing::{Cursor, Selection}, | 6 | editing::{Cursor, Selection}, |
| 6 | }; | 7 | }; |
| 7 | use skrifa::{FontRef, MetadataProvider, raw::TableProvider, string::StringId}; | 8 | use skrifa::{FontRef, MetadataProvider, raw::TableProvider, string::StringId}; |
| ... | @@ -139,8 +140,13 @@ impl TextEngine { | ... | @@ -139,8 +140,13 @@ impl TextEngine { |
| 139 | return Err(LayoutError::InvalidFontSize); | 140 | return Err(LayoutError::InvalidFontSize); |
| 140 | } | 141 | } |
| 141 | let properties = [ | 142 | let properties = [ |
| 142 | StyleProperty::FontFamily(FontFamily::named( | 143 | StyleProperty::FontFamily(FontFamily::List( |
| 143 | format.font.as_deref().unwrap_or("Arial"), | 144 | vec![ |
| | 145 | FontFamilyName::named(format.font.as_deref().unwrap_or("Arial")), |
| | 146 | // A missing family otherwise falls back per script and can put digits in an emoji font. |
| | 147 | GenericFamily::SansSerif.into(), |
| | 148 | ] |
| | 149 | .into(), |
| 144 | )), | 150 | )), |
| 145 | StyleProperty::FontSize(size), | 151 | StyleProperty::FontSize(size), |
| 146 | StyleProperty::FontWeight(if format.bold == Some(true) { | 152 | StyleProperty::FontWeight(if format.bold == Some(true) { |
| ... | @@ -522,6 +528,27 @@ mod tests { | ... | @@ -522,6 +528,27 @@ mod tests { |
| 522 | ); | 528 | ); |
| 523 | } | 529 | } |
| 524 | | 530 | |
| | 531 | #[test] |
| | 532 | fn missing_family_keeps_digits_in_the_letters_face() { |
| | 533 | let paragraph = Paragraph::new( |
| | 534 | "Monday, August 10, 2026".into(), |
| | 535 | Format { |
| | 536 | font: Some("Snowbound Missing Family".into()), |
| | 537 | ..Format::default() |
| | 538 | }, |
| | 539 | ); |
| | 540 | let layout = TextEngine::default().layout(&paragraph, 468.0).unwrap(); |
| | 541 | let fonts = layout |
| | 542 | .lines() |
| | 543 | .flat_map(|(line, _)| { |
| | 544 | line.runs() |
| | 545 | .map(|run| run.font().font.data.id()) |
| | 546 | .collect::<Vec<_>>() |
| | 547 | }) |
| | 548 | .collect::<BTreeSet<_>>(); |
| | 549 | assert_eq!(fonts.len(), 1); |
| | 550 | } |
| | 551 | |
| 525 | #[test] | 552 | #[test] |
| 526 | fn highlights_share_line_geometry_without_changing_wraps() { | 553 | fn highlights_share_line_geometry_without_changing_wraps() { |
| 527 | let paragraph = Paragraph::from_runs([ | 554 | let paragraph = Paragraph::from_runs([ |