diff options
Diffstat (limited to 'src/layout')
| -rw-r--r-- | src/layout/frame.rs | 3 | ||||
| -rw-r--r-- | src/layout/mod.rs | 47 | ||||
| -rw-r--r-- | src/layout/shaping.rs | 25 |
3 files changed, 53 insertions, 22 deletions
diff --git a/src/layout/frame.rs b/src/layout/frame.rs index 61a84d6d..6cecc7a3 100644 --- a/src/layout/frame.rs +++ b/src/layout/frame.rs @@ -1,6 +1,7 @@ use crate::color::Color; -use crate::env::{FaceId, ImageId}; +use crate::font::FaceId; use crate::geom::{Length, Path, Point, Size}; +use crate::image::ImageId; use serde::{Deserialize, Serialize}; diff --git a/src/layout/mod.rs b/src/layout/mod.rs index bdcf5ec4..30776fa2 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -17,19 +17,20 @@ pub use shaping::*; pub use stack::*; use std::any::Any; +use std::collections::HashMap; use std::fmt::{self, Debug, Formatter}; use std::hash::{Hash, Hasher}; use decorum::N64; use fxhash::FxHasher64; -use crate::cache::{Cache, FramesEntry}; -use crate::env::Env; +use crate::cache::Cache; use crate::geom::*; +use crate::loading::Loader; /// Layout a tree into a collection of frames. -pub fn layout(env: &mut Env, cache: &mut Cache, tree: &Tree) -> Vec<Frame> { - tree.layout(&mut LayoutContext { env, cache }) +pub fn layout(loader: &mut dyn Loader, cache: &mut Cache, tree: &Tree) -> Vec<Frame> { + tree.layout(&mut LayoutContext { loader, cache }) } /// A tree of layout nodes. @@ -92,14 +93,14 @@ impl AnyNode { impl Layout for AnyNode { fn layout(&self, ctx: &mut LayoutContext, regions: &Regions) -> Vec<Frame> { - if let Some(hit) = ctx.cache.frames.get(&self.hash) { + if let Some(hit) = ctx.cache.layout.frames.get(&self.hash) { if &hit.regions == regions { return hit.frames.clone(); } } let frames = self.node.layout(ctx, regions); - ctx.cache.frames.insert(self.hash, FramesEntry { + ctx.cache.layout.frames.insert(self.hash, FramesEntry { regions: regions.clone(), frames: frames.clone(), }); @@ -170,13 +171,39 @@ pub trait Layout { /// The context for layouting. pub struct LayoutContext<'a> { - /// The environment from which fonts are gathered. - pub env: &'a mut Env, - /// A cache which enables reuse of layout artifacts from past compilation - /// cycles. + /// The loader from which fonts are loaded. + pub loader: &'a mut dyn Loader, + /// A cache for loaded fonts and artifacts from past layouting. pub cache: &'a mut Cache, } +/// Caches layouting artifacts. +pub struct LayoutCache { + /// Maps from node hashes to the resulting frames and regions in which the + /// frames are valid. + pub frames: HashMap<u64, FramesEntry>, +} + +impl LayoutCache { + /// Create a new, empty layout cache. + pub fn new() -> Self { + Self { frames: HashMap::new() } + } + + /// Clear the cache. + pub fn clear(&mut self) { + self.frames.clear(); + } +} + +/// Cached frames from past layouting. +pub struct FramesEntry { + /// The regions in which these frames are valid. + pub regions: Regions, + /// The cached frames for a node. + pub frames: Vec<Frame>, +} + /// A sequence of regions to layout into. #[derive(Debug, Clone, PartialEq)] pub struct Regions { diff --git a/src/layout/shaping.rs b/src/layout/shaping.rs index f8ab7037..14ea8611 100644 --- a/src/layout/shaping.rs +++ b/src/layout/shaping.rs @@ -5,9 +5,8 @@ use std::ops::Range; use rustybuzz::UnicodeBuffer; use super::{Element, Frame, Glyph, LayoutContext, Text}; -use crate::env::FaceId; use crate::exec::FontProps; -use crate::font::Face; +use crate::font::{Face, FaceId}; use crate::geom::{Dir, Length, Point, Size}; use crate::util::SliceExt; @@ -215,10 +214,12 @@ fn shape_segment<'a>( let (face_id, fallback) = loop { // Try to load the next available font family. match families.next() { - Some(family) => match ctx.env.query_face(family, props.variant) { - Some(id) => break (id, true), - None => {} - }, + Some(family) => { + match ctx.cache.font.select(ctx.loader, family, props.variant) { + Some(id) => break (id, true), + None => {} + } + } // We're out of families, so we don't do any more fallback and just // shape the tofus with the first face we originally used. None => match first_face { @@ -242,7 +243,7 @@ fn shape_segment<'a>( }); // Shape! - let mut face = ctx.env.face(face_id); + let mut face = ctx.cache.font.get(face_id); let buffer = rustybuzz::shape(face.ttf(), &[], buffer); let infos = buffer.glyph_infos(); let pos = buffer.glyph_positions(); @@ -317,7 +318,7 @@ fn shape_segment<'a>( first_face, ); - face = ctx.env.face(face_id); + face = ctx.cache.font.get(face_id); } i += 1; @@ -331,6 +332,8 @@ fn measure( glyphs: &[ShapedGlyph], props: &FontProps, ) -> (Size, Length) { + let cache = &mut ctx.cache.font; + let mut width = Length::zero(); let mut top = Length::zero(); let mut bottom = Length::zero(); @@ -343,14 +346,14 @@ fn measure( // When there are no glyphs, we just use the vertical metrics of the // first available font. for family in props.families.iter() { - if let Some(face_id) = ctx.env.query_face(family, props.variant) { - expand_vertical(ctx.env.face(face_id)); + if let Some(face_id) = cache.select(ctx.loader, family, props.variant) { + expand_vertical(cache.get(face_id)); break; } } } else { for (face_id, group) in glyphs.group_by_key(|g| g.face_id) { - let face = ctx.env.face(face_id); + let face = cache.get(face_id); expand_vertical(face); for glyph in group { |
