diff options
Diffstat (limited to 'src/layout/text.rs')
| -rw-r--r-- | src/layout/text.rs | 53 |
1 files changed, 44 insertions, 9 deletions
diff --git a/src/layout/text.rs b/src/layout/text.rs index 6aa5ef71..c1f4e464 100644 --- a/src/layout/text.rs +++ b/src/layout/text.rs @@ -1,22 +1,26 @@ //! Layouting of text into boxes. +use toddle::query::{FontQuery, SharedFontLoader}; +use toddle::tables::{Header, CharMap, HorizontalMetrics}; + use crate::doc::LayoutAction; -use crate::font::FontQuery; use crate::size::{Size, Size2D}; use super::*; /// The context for text layouting. -#[derive(Debug, Copy, Clone)] +#[derive(Copy, Clone)] pub struct TextContext<'a, 'p> { /// Loads fonts matching queries. - pub loader: &'a FontLoader<'p>, + pub loader: &'a SharedFontLoader<'p>, /// Base style to set text with. pub style: &'a TextStyle, } /// Layout one piece of text without any breaks as one continous box. pub fn layout(text: &str, ctx: TextContext) -> LayoutResult<BoxLayout> { + let mut loader = ctx.loader.borrow_mut(); + let mut actions = Vec::new(); let mut active_font = std::usize::MAX; let mut buffer = String::new(); @@ -25,14 +29,45 @@ pub fn layout(text: &str, ctx: TextContext) -> LayoutResult<BoxLayout> { // Walk the characters. for character in text.chars() { // Retrieve the best font for this character. - let (index, font) = ctx.loader.get(FontQuery { - classes: ctx.style.classes.clone(), - fallback: ctx.style.fallback.clone(), - character, - }).ok_or_else(|| LayoutError::NoSuitableFont(character))?; + let mut font = None; + let mut classes = ctx.style.classes.clone(); + for class in &ctx.style.fallback { + classes.push(class.clone()); + + font = loader.get(FontQuery { + chars: &[character], + classes: &classes, + }); + + if font.is_some() { + break; + } + + classes.pop(); + } + + let (font, index) = match font { + Some(f) => f, + None => return Err(LayoutError::NoSuitableFont(character)), + }; + + // Create a conversion function between font units and sizes. + let font_unit_ratio = 1.0 / (font.read_table::<Header>()?.units_per_em as f32); + let font_unit_to_size = |x| Size::pt(font_unit_ratio * x); // Add the char width to the total box width. - let char_width = font.widths[font.encode(character) as usize] * ctx.style.font_size; + let glyph = font.read_table::<CharMap>()? + .get(character) + .expect("layout text: font should have char"); + + let glyph_width = font_unit_to_size( + font.read_table::<HorizontalMetrics>()? + .get(glyph) + .expect("layout text: font should have glyph") + .advance_width as f32 + ); + + let char_width = glyph_width * ctx.style.font_size; width += char_width; // Change the font if necessary. |
