summaryrefslogtreecommitdiff
path: root/src/layout
diff options
context:
space:
mode:
Diffstat (limited to 'src/layout')
-rw-r--r--src/layout/frame.rs3
-rw-r--r--src/layout/mod.rs47
-rw-r--r--src/layout/shaping.rs25
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 {