summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2020-10-05 13:39:33 +0200
committerLaurenz <laurmaedje@gmail.com>2020-10-05 13:39:33 +0200
commitd1c07260c0b67098a1b778262c76e6f31c5a5240 (patch)
tree6b78bd83ec83c85fab1e3bf289d52c8de456eca3 /src
parent335fa2d118718b4dba539294a8ef6c96c5bbf09e (diff)
Move align out of BoxLayout 🍫
Diffstat (limited to 'src')
-rw-r--r--src/layout/line.rs33
-rw-r--r--src/layout/mod.rs10
-rw-r--r--src/layout/stack.rs31
-rw-r--r--src/layout/tree.rs42
-rw-r--r--src/library/boxed.rs3
-rw-r--r--src/shaping.rs37
6 files changed, 71 insertions, 85 deletions
diff --git a/src/layout/line.rs b/src/layout/line.rs
index baef9fb0..19ec053d 100644
--- a/src/layout/line.rs
+++ b/src/layout/line.rs
@@ -23,14 +23,10 @@ pub struct LineLayouter {
/// The context for line layouting.
#[derive(Debug, Clone)]
pub struct LineContext {
- /// The spaces to layout into.
- pub spaces: Vec<LayoutSpace>,
/// The initial layouting system, which can be updated through `set_sys`.
pub sys: LayoutSystem,
- /// The alignment of the _resulting_ layout. This does not effect the line
- /// layouting itself, but rather how the finished layout will be positioned
- /// in a parent layout.
- pub align: LayoutAlign,
+ /// The spaces to layout into.
+ pub spaces: Vec<LayoutSpace>,
/// Whether to spill over into copies of the last space or finish layouting
/// when the last space is used up.
pub repeat: bool,
@@ -45,7 +41,6 @@ impl LineLayouter {
stack: StackLayouter::new(StackContext {
spaces: ctx.spaces.clone(),
sys: ctx.sys,
- align: ctx.align,
repeat: ctx.repeat,
}),
ctx,
@@ -54,26 +49,26 @@ impl LineLayouter {
}
/// Add a layout.
- pub fn add(&mut self, layout: BoxLayout) {
+ pub fn add(&mut self, layout: BoxLayout, align: LayoutAlign) {
let sys = self.ctx.sys;
- if let Some(align) = self.run.align {
- if layout.align.secondary != align.secondary {
+ if let Some(prev) = self.run.align {
+ if align.secondary != prev.secondary {
// TODO: Issue warning for non-fitting alignment in
// non-repeating context.
- let fitting = self.stack.is_fitting_alignment(layout.align);
+ let fitting = self.stack.is_fitting_alignment(align);
if !fitting && self.ctx.repeat {
self.finish_space(true);
} else {
self.finish_line();
}
- } else if layout.align.primary < align.primary {
+ } else if align.primary < prev.primary {
self.finish_line();
- } else if layout.align.primary > align.primary {
+ } else if align.primary > prev.primary {
let mut rest_run = LineRun::new();
let usable = self.stack.usable().primary(sys);
- rest_run.usable = Some(match layout.align.primary {
+ rest_run.usable = Some(match align.primary {
GenAlign::Start => unreachable!("start > x"),
GenAlign::Center => usable - 2.0 * self.run.size.width,
GenAlign::End => usable - self.run.size.width,
@@ -105,7 +100,7 @@ impl LineLayouter {
}
}
- self.run.align = Some(layout.align);
+ self.run.align = Some(align);
self.run.layouts.push((self.run.size.width, layout));
self.run.size.width += size.width;
@@ -211,10 +206,8 @@ impl LineLayouter {
/// Finish the active line and start a new one.
pub fn finish_line(&mut self) {
- let mut layout = BoxLayout::new(
- self.run.size.specialized(self.ctx.sys),
- self.run.align.unwrap_or_default(),
- );
+ let mut layout = BoxLayout::new(self.run.size.specialized(self.ctx.sys));
+ let align = self.run.align.unwrap_or_default();
let layouts = std::mem::take(&mut self.run.layouts);
for (offset, child) in layouts {
@@ -227,7 +220,7 @@ impl LineLayouter {
layout.push_layout(pos, child);
}
- self.stack.add(layout);
+ self.stack.add(layout, align);
self.run = LineRun::new();
self.stack.add_spacing(self.ctx.line_spacing, SpacingKind::LINE);
diff --git a/src/layout/mod.rs b/src/layout/mod.rs
index 52f7e0e6..7803c747 100644
--- a/src/layout/mod.rs
+++ b/src/layout/mod.rs
@@ -54,16 +54,14 @@ pub async fn layout(
pub struct BoxLayout {
/// The size of the box.
pub size: Size,
- /// How to align this box in a parent container.
- pub align: LayoutAlign,
/// The elements composing this layout.
pub elements: Vec<(Point, LayoutElement)>,
}
impl BoxLayout {
- /// Create an new empty collection.
- pub fn new(size: Size, align: LayoutAlign) -> Self {
- Self { size, align, elements: vec![] }
+ /// Create a new empty collection.
+ pub fn new(size: Size) -> Self {
+ Self { size, elements: vec![] }
}
/// Add an element at a position.
@@ -161,7 +159,7 @@ pub enum Command {
LayoutSyntaxTree(SynTree),
/// Add a finished layout.
- Add(BoxLayout),
+ Add(BoxLayout, LayoutAlign),
/// Add spacing of the given kind along the primary or secondary axis. The
/// kind defines how the spacing interacts with surrounding spacing.
AddSpacing(f64, SpacingKind, GenAxis),
diff --git a/src/layout/stack.rs b/src/layout/stack.rs
index dadc40b9..04c78da5 100644
--- a/src/layout/stack.rs
+++ b/src/layout/stack.rs
@@ -34,14 +34,10 @@ pub struct StackLayouter {
/// The context for stack layouting.
#[derive(Debug, Clone)]
pub struct StackContext {
- /// The spaces to layout into.
- pub spaces: Vec<LayoutSpace>,
/// The initial layouting system, which can be updated through `set_sys`.
pub sys: LayoutSystem,
- /// The alignment of the _resulting_ layout. This does not effect the line
- /// layouting itself, but rather how the finished layout will be positioned
- /// in a parent layout.
- pub align: LayoutAlign,
+ /// The spaces to layout into.
+ pub spaces: Vec<LayoutSpace>,
/// Whether to spill over into copies of the last space or finish layouting
/// when the last space is used up.
pub repeat: bool,
@@ -59,11 +55,11 @@ impl StackLayouter {
}
/// Add a layout to the stack.
- pub fn add(&mut self, layout: BoxLayout) {
+ pub fn add(&mut self, layout: BoxLayout, align: LayoutAlign) {
// If the alignment cannot be fitted in this space, finish it.
// TODO: Issue warning for non-fitting alignment in non-repeating
// context.
- if !self.update_rulers(layout.align) && self.ctx.repeat {
+ if !self.update_rulers(align) && self.ctx.repeat {
self.finish_space(true);
}
@@ -84,7 +80,7 @@ impl StackLayouter {
// Add the box to the vector and remember that spacings are allowed
// again.
- self.space.layouts.push((self.ctx.sys, layout));
+ self.space.layouts.push((self.ctx.sys, align, layout));
self.space.last_spacing = LastSpacing::None;
}
@@ -100,10 +96,8 @@ impl StackLayouter {
self.update_metrics(size);
self.space.layouts.push((
self.ctx.sys,
- BoxLayout::new(
- size.specialized(self.ctx.sys),
- LayoutAlign::default(),
- ),
+ LayoutAlign::default(),
+ BoxLayout::new(size.specialized(self.ctx.sys)),
));
self.space.last_spacing = LastSpacing::Hard;
@@ -279,7 +273,7 @@ impl StackLayouter {
y1: start.y + self.space.size.height,
};
- for (sys, layout) in &self.space.layouts {
+ for (sys, _, layout) in &self.space.layouts {
// First, we store the bounds calculated so far (which were reduced
// by the predecessors of this layout) as the initial bounding box
// of this layout.
@@ -303,7 +297,7 @@ impl StackLayouter {
let mut rotation = SpecAxis::Vertical;
for (bound, entry) in bounds.iter_mut().zip(&self.space.layouts).rev() {
- let (sys, layout) = entry;
+ let (sys, _, layout) = entry;
// When the axes are rotated, the maximal primary size (`extent.x`)
// dictates how much secondary extent the whole run had. This value
@@ -331,12 +325,11 @@ impl StackLayouter {
// Step 4: Align each layout in its bounding box and collect everything
// into a single finished layout.
- let mut layout = BoxLayout::new(size, self.ctx.align);
+ let mut layout = BoxLayout::new(size);
let layouts = std::mem::take(&mut self.space.layouts);
- for ((sys, child), bound) in layouts.into_iter().zip(bounds) {
+ for ((sys, align, child), bound) in layouts.into_iter().zip(bounds) {
let size = child.size.specialized(sys);
- let align = child.align;
// The space in which this layout is aligned is given by the
// distances between the borders of its bounding box.
@@ -373,7 +366,7 @@ struct Space {
/// Whether to include a layout for this space even if it would be empty.
hard: bool,
/// The so-far accumulated layouts.
- layouts: Vec<(LayoutSystem, BoxLayout)>,
+ layouts: Vec<(LayoutSystem, LayoutAlign, BoxLayout)>,
/// The specialized size of this space.
size: Size,
/// The specialized remaining space.
diff --git a/src/layout/tree.rs b/src/layout/tree.rs
index 4e15fb12..fde7833e 100644
--- a/src/layout/tree.rs
+++ b/src/layout/tree.rs
@@ -1,5 +1,7 @@
//! Layouting of syntax trees.
+use fontdock::FontStyle;
+
use super::*;
use crate::eval::Eval;
use crate::shaping;
@@ -25,7 +27,6 @@ impl<'a> TreeLayouter<'a> {
let layouter = LineLayouter::new(LineContext {
spaces: ctx.constraints.spaces.clone(),
sys: ctx.state.sys,
- align: ctx.state.align,
repeat: ctx.constraints.repeat,
line_spacing: ctx.state.text.line_spacing(),
});
@@ -99,16 +100,31 @@ impl<'a> TreeLayouter<'a> {
}
async fn layout_text(&mut self, text: &str) {
- self.layouter.add(
- shaping::shape(
- text,
- self.ctx.state.sys.primary,
- self.ctx.state.align,
- &self.ctx.state.text,
- &mut self.ctx.loader.borrow_mut(),
- )
- .await,
- );
+ let mut variant = self.ctx.state.text.variant;
+
+ if self.ctx.state.text.strong {
+ variant.weight = variant.weight.thicken(300);
+ }
+
+ if self.ctx.state.text.emph {
+ variant.style = match variant.style {
+ FontStyle::Normal => FontStyle::Italic,
+ FontStyle::Italic => FontStyle::Normal,
+ FontStyle::Oblique => FontStyle::Normal,
+ }
+ }
+
+ let boxed = shaping::shape(
+ text,
+ self.ctx.state.sys.primary,
+ self.ctx.state.text.font_size(),
+ variant,
+ &self.ctx.state.text.fallback,
+ &mut self.ctx.loader.borrow_mut(),
+ )
+ .await;
+
+ self.layouter.add(boxed, self.ctx.state.align);
}
async fn layout_heading(&mut self, heading: &NodeHeading) {
@@ -160,9 +176,7 @@ impl<'a> TreeLayouter<'a> {
};
let val = expr.v.eval(self.ctx).await;
-
let commands = val.span_with(expr.span).into_commands();
-
for command in commands {
self.execute_command(command, expr.span).await;
}
@@ -173,7 +187,7 @@ impl<'a> TreeLayouter<'a> {
match command {
LayoutSyntaxTree(tree) => self.layout_tree(&tree).await,
- Add(layout) => self.layouter.add(layout),
+ Add(layout, align) => self.layouter.add(layout, align),
AddSpacing(space, kind, axis) => match axis {
GenAxis::Primary => self.layouter.add_primary_spacing(space, kind),
GenAxis::Secondary => self.layouter.add_secondary_spacing(space, kind),
diff --git a/src/library/boxed.rs b/src/library/boxed.rs
index 085176e0..caeb206e 100644
--- a/src/library/boxed.rs
+++ b/src/library/boxed.rs
@@ -12,6 +12,7 @@ pub async fn boxed(mut args: Args, ctx: &mut LayoutContext) -> Value {
let height = args.get::<_, Linear>(ctx, "height");
args.done(ctx);
+ let align = ctx.state.align;
let constraints = &mut ctx.constraints;
constraints.base = constraints.spaces[0].size;
constraints.spaces.truncate(1);
@@ -34,5 +35,5 @@ pub async fn boxed(mut args: Args, ctx: &mut LayoutContext) -> Value {
let layouted = layout_tree(&body, ctx).await;
let layout = layouted.into_iter().next().unwrap();
- Value::Commands(vec![Add(layout)])
+ Value::Commands(vec![Add(layout, align)])
}
diff --git a/src/shaping.rs b/src/shaping.rs
index f56fa444..7c60e0d2 100644
--- a/src/shaping.rs
+++ b/src/shaping.rs
@@ -6,23 +6,23 @@
use std::fmt::{self, Debug, Formatter};
-use fontdock::{FaceId, FaceQuery, FallbackTree, FontStyle, FontVariant};
+use fontdock::{FaceId, FaceQuery, FallbackTree, FontVariant};
use ttf_parser::GlyphId;
-use crate::eval::TextState;
use crate::font::FontLoader;
use crate::geom::{Point, Size};
-use crate::layout::{BoxLayout, Dir, LayoutAlign, LayoutElement};
+use crate::layout::{BoxLayout, Dir, LayoutElement};
/// Shape text into a box containing shaped runs.
pub async fn shape(
text: &str,
dir: Dir,
- align: LayoutAlign,
- state: &TextState,
+ size: f64,
+ variant: FontVariant,
+ fallback: &FallbackTree,
loader: &mut FontLoader,
) -> BoxLayout {
- Shaper::new(text, dir, align, state, loader).shape().await
+ Shaper::new(text, dir, size, variant, fallback, loader).shape().await
}
/// A shaped run of text.
@@ -86,32 +86,19 @@ impl<'a> Shaper<'a> {
fn new(
text: &'a str,
dir: Dir,
- align: LayoutAlign,
- state: &'a TextState,
+ size: f64,
+ variant: FontVariant,
+ fallback: &'a FallbackTree,
loader: &'a mut FontLoader,
) -> Self {
- let mut variant = state.variant;
-
- if state.strong {
- variant.weight = variant.weight.thicken(300);
- }
-
- if state.emph {
- variant.style = match variant.style {
- FontStyle::Normal => FontStyle::Italic,
- FontStyle::Italic => FontStyle::Normal,
- FontStyle::Oblique => FontStyle::Normal,
- }
- }
-
Self {
text,
dir,
variant,
- fallback: &state.fallback,
+ fallback,
loader,
- shaped: Shaped::new(FaceId::MAX, state.font_size()),
- layout: BoxLayout::new(Size::new(0.0, state.font_size()), align),
+ shaped: Shaped::new(FaceId::MAX, size),
+ layout: BoxLayout::new(Size::new(0.0, size)),
offset: 0.0,
}
}