summaryrefslogtreecommitdiff
path: root/src/layout/text.rs
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2019-10-09 19:45:40 +0200
committerLaurenz <laurmaedje@gmail.com>2019-10-09 19:46:42 +0200
commitf22a3070001e9c8db6fcc7b83b036111a6559a3d (patch)
treea14c437a2ef71b08af5847c4f38330f668f724c2 /src/layout/text.rs
parentb96a7e0cf3c97463ecb746d859b675541a427774 (diff)
Extract into separate repository 🧱
Diffstat (limited to 'src/layout/text.rs')
-rw-r--r--src/layout/text.rs53
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.