From 2ee5810fecb96a8d4e0d078faecc8c91096d6881 Mon Sep 17 00:00:00 2001 From: Laurenz Date: Mon, 6 Jan 2020 12:41:42 +0100 Subject: =?UTF-8?q?Asyncify=20font=20loading=20=F0=9F=AA=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/layout/text.rs | 18 +++--- src/layout/tree.rs | 179 +++++++++++++++++++++++++++-------------------------- 2 files changed, 100 insertions(+), 97 deletions(-) (limited to 'src/layout') diff --git a/src/layout/text.rs b/src/layout/text.rs index 96704f60..2fdb3f6d 100644 --- a/src/layout/text.rs +++ b/src/layout/text.rs @@ -20,8 +20,8 @@ pub struct TextContext<'a, 'p> { /// /// There is no complex layout involved. The text is simply laid out left- /// to-right using the correct font for each character. -pub fn layout_text(text: &str, ctx: TextContext) -> LayoutResult { - TextLayouter::new(text, ctx).layout() +pub async fn layout_text(text: &str, ctx: TextContext<'_, '_>) -> LayoutResult { + TextLayouter::new(text, ctx).layout().await } /// Layouts text into boxes. @@ -48,14 +48,14 @@ impl<'a, 'p> TextLayouter<'a, 'p> { } /// Layout the text - fn layout(mut self) -> LayoutResult { + async fn layout(mut self) -> LayoutResult { if self.ctx.axes.primary.is_positive() { for c in self.text.chars() { - self.layout_char(c)?; + self.layout_char(c).await?; } } else { for c in self.text.chars().rev() { - self.layout_char(c)?; + self.layout_char(c).await?; } } @@ -71,8 +71,8 @@ impl<'a, 'p> TextLayouter<'a, 'p> { } /// Layout an individual character. - fn layout_char(&mut self, c: char) -> LayoutResult<()> { - let (index, char_width) = self.select_font(c)?; + async fn layout_char(&mut self, c: char) -> LayoutResult<()> { + let (index, char_width) = self.select_font(c).await?; self.width += char_width; @@ -93,7 +93,7 @@ impl<'a, 'p> TextLayouter<'a, 'p> { /// Select the best font for a character and return its index along with /// the width of the char in the font. - fn select_font(&mut self, c: char) -> LayoutResult<(FontIndex, Size)> { + async fn select_font(&mut self, c: char) -> LayoutResult<(FontIndex, Size)> { let mut loader = self.ctx.loader.borrow_mut(); let query = FontQuery { @@ -102,7 +102,7 @@ impl<'a, 'p> TextLayouter<'a, 'p> { c, }; - if let Some((font, index)) = loader.get(query) { + if let Some((font, index)) = loader.get(query).await { let font_unit_ratio = 1.0 / (font.read_table::
()?.units_per_em as f32); let font_unit_to_size = |x| Size::pt(font_unit_ratio * x); diff --git a/src/layout/tree.rs b/src/layout/tree.rs index 4ed3d82a..f645a35d 100644 --- a/src/layout/tree.rs +++ b/src/layout/tree.rs @@ -1,3 +1,5 @@ +use std::pin::Pin; +use std::future::Future; use smallvec::smallvec; use crate::func::Command; @@ -5,10 +7,13 @@ use crate::syntax::{SyntaxTree, Node, FuncCall}; use crate::style::TextStyle; use super::*; + +type RecursiveResult<'a, T> = Pin> + 'a>>; + /// Layout a syntax tree into a multibox. -pub fn layout(tree: &SyntaxTree, ctx: LayoutContext) -> LayoutResult { +pub async fn layout(tree: &SyntaxTree, ctx: LayoutContext<'_, '_>) -> LayoutResult { let mut layouter = TreeLayouter::new(ctx); - layouter.layout(tree)?; + layouter.layout(tree).await?; layouter.finish() } @@ -36,42 +41,44 @@ impl<'a, 'p> TreeLayouter<'a, 'p> { } } - fn layout(&mut self, tree: &SyntaxTree) -> LayoutResult<()> { - for node in &tree.nodes { - match &node.v { - Node::Text(text) => self.layout_text(text)?, + fn layout<'b>(&'b mut self, tree: &'b SyntaxTree) -> RecursiveResult<'b, ()> { + Box::pin(async move { + for node in &tree.nodes { + match &node.v { + Node::Text(text) => self.layout_text(text).await?, - Node::Space => self.layout_space(), - Node::Newline => self.layout_paragraph()?, + Node::Space => self.layout_space(), + Node::Newline => self.layout_paragraph()?, - Node::ToggleItalics => self.style.text.variant.style.toggle(), - Node::ToggleBolder => { - self.style.text.variant.weight.0 += 300 * - if self.style.text.bolder { -1 } else { 1 }; - self.style.text.bolder = !self.style.text.bolder; - } - Node::ToggleMonospace => { - let list = &mut self.style.text.fallback.list; - match list.get(0).map(|s| s.as_str()) { - Some("monospace") => { list.remove(0); }, - _ => list.insert(0, "monospace".to_string()), + Node::ToggleItalics => self.style.text.variant.style.toggle(), + Node::ToggleBolder => { + self.style.text.variant.weight.0 += 300 * + if self.style.text.bolder { -1 } else { 1 }; + self.style.text.bolder = !self.style.text.bolder; + } + Node::ToggleMonospace => { + let list = &mut self.style.text.fallback.list; + match list.get(0).map(|s| s.as_str()) { + Some("monospace") => { list.remove(0); }, + _ => list.insert(0, "monospace".to_string()), + } } - } - Node::Func(func) => self.layout_func(func)?, + Node::Func(func) => self.layout_func(func).await?, + } } - } - Ok(()) + Ok(()) + }) } - fn layout_text(&mut self, text: &str) -> LayoutResult<()> { + async fn layout_text(&mut self, text: &str) -> LayoutResult<()> { let layout = layout_text(text, TextContext { loader: &self.ctx.loader, style: &self.style.text, axes: self.ctx.axes, alignment: self.ctx.alignment, - })?; + }).await?; self.layouter.add(layout) } @@ -84,75 +91,71 @@ impl<'a, 'p> TreeLayouter<'a, 'p> { self.layouter.add_secondary_spacing(self.style.text.paragraph_spacing(), PARAGRAPH_KIND) } - fn layout_func(&mut self, func: &FuncCall) -> LayoutResult<()> { - let commands = func.0.layout(LayoutContext { - style: &self.style, - spaces: self.layouter.remaining(), - nested: true, - debug: false, - .. self.ctx - })?; - - for command in commands { - self.execute(command)?; - } - - Ok(()) - } - - fn execute(&mut self, command: Command) -> LayoutResult<()> { - use Command::*; - - match command { - LayoutTree(tree) => self.layout(tree)?, - - Add(layout) => self.layouter.add(layout)?, - AddMultiple(layouts) => self.layouter.add_multiple(layouts)?, - SpacingFunc(space, kind, axis) => match axis { - Primary => self.layouter.add_primary_spacing(space, kind), - Secondary => self.layouter.add_secondary_spacing(space, kind)?, - } - - FinishLine => self.layouter.finish_line()?, - FinishSpace => self.layouter.finish_space(true)?, - BreakParagraph => self.layout_paragraph()?, - BreakPage => { - if self.ctx.nested { - error!("page break cannot be issued from nested context"); - } - - self.layouter.finish_space(true)? - } + fn layout_func<'b>(&'b mut self, func: &'b FuncCall) -> RecursiveResult<'b, ()> { + Box::pin(async move { + let commands = func.0.layout(LayoutContext { + style: &self.style, + spaces: self.layouter.remaining(), + nested: true, + debug: false, + .. self.ctx + }).await?; + + for command in commands { + use Command::*; + + match command { + LayoutTree(tree) => self.layout(tree).await?, + + Add(layout) => self.layouter.add(layout)?, + AddMultiple(layouts) => self.layouter.add_multiple(layouts)?, + SpacingFunc(space, kind, axis) => match axis { + Primary => self.layouter.add_primary_spacing(space, kind), + Secondary => self.layouter.add_secondary_spacing(space, kind)?, + } - SetTextStyle(style) => { - self.layouter.set_line_spacing(style.line_spacing()); - self.style.text = style; - } - SetPageStyle(style) => { - if self.ctx.nested { - error!("page style cannot be altered in nested context"); - } + FinishLine => self.layouter.finish_line()?, + FinishSpace => self.layouter.finish_space(true)?, + BreakParagraph => self.layout_paragraph()?, + BreakPage => { + if self.ctx.nested { + error!("page break cannot be issued from nested context"); + } - self.style.page = style; + self.layouter.finish_space(true)? + } - let margins = style.margins(); - self.ctx.base = style.dimensions.unpadded(margins); - self.layouter.set_spaces(smallvec![ - LayoutSpace { - dimensions: style.dimensions, - padding: margins, - expansion: LayoutExpansion::new(true, true), + SetTextStyle(style) => { + self.layouter.set_line_spacing(style.line_spacing()); + self.style.text = style; } - ], true); - } - SetAlignment(alignment) => self.ctx.alignment = alignment, - SetAxes(axes) => { - self.layouter.set_axes(axes); - self.ctx.axes = axes; + SetPageStyle(style) => { + if self.ctx.nested { + error!("page style cannot be altered in nested context"); + } + + self.style.page = style; + + let margins = style.margins(); + self.ctx.base = style.dimensions.unpadded(margins); + self.layouter.set_spaces(smallvec![ + LayoutSpace { + dimensions: style.dimensions, + padding: margins, + expansion: LayoutExpansion::new(true, true), + } + ], true); + } + SetAlignment(alignment) => self.ctx.alignment = alignment, + SetAxes(axes) => { + self.layouter.set_axes(axes); + self.ctx.axes = axes; + } + } } - } - Ok(()) + Ok(()) + }) } fn finish(self) -> LayoutResult { -- cgit v1.2.3