typst/src/layout/text.rs
2019-06-22 12:51:06 +02:00

63 lines
1.8 KiB
Rust

//! Layouting of text into boxes.
use crate::doc::LayoutAction;
use crate::font::FontQuery;
use crate::size::{Size, Size2D};
use super::*;
/// The context for text layouting.
#[derive(Debug, Clone)]
pub struct TextContext<'a, 'p> {
/// Loads fonts matching queries.
pub loader: &'a FontLoader<'p>,
/// Base style to set text with.
pub style: TextStyle,
}
/// Layout one piece of text without any breaks as one continous box.
pub fn layout(text: &str, ctx: &TextContext) -> LayoutResult<BoxLayout> {
let mut actions = Vec::new();
let mut active_font = std::usize::MAX;
let mut buffer = String::new();
let mut width = Size::zero();
// Walk the characters.
for character in text.chars() {
// Retrieve the best font for this character.
let (index, font) = ctx.loader.get(FontQuery {
families: ctx.style.font_families.clone(),
italic: ctx.style.italic,
bold: ctx.style.bold,
character,
}).ok_or_else(|| LayoutError::NoSuitableFont(character))?;
// Add the char width to the total box width.
let char_width = font.widths[font.map(character) as usize] * ctx.style.font_size;
width += char_width;
// Change the font if necessary.
if active_font != index {
if !buffer.is_empty() {
actions.push(LayoutAction::WriteText(buffer));
buffer = String::new();
}
actions.push(LayoutAction::SetFont(index, ctx.style.font_size));
active_font = index;
}
buffer.push(character);
}
// Write the remaining characters.
if !buffer.is_empty() {
actions.push(LayoutAction::WriteText(buffer));
}
Ok(BoxLayout {
dimensions: Size2D::new(width, Size::pt(ctx.style.font_size)),
actions,
})
}