mirror of
https://github.com/typst/typst
synced 2025-05-19 11:35:27 +08:00
Fixed par layouter directions 🗜
This commit is contained in:
parent
309b8f20a8
commit
88da325c7d
@ -1,4 +1,5 @@
|
|||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
use std::mem;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::exec::FontProps;
|
use crate::exec::FontProps;
|
||||||
@ -77,39 +78,35 @@ impl From<ParNode> for AnyNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct ParLayouter {
|
struct ParLayouter {
|
||||||
dirs: Gen<Dir>,
|
dir: Dir,
|
||||||
main: SpecAxis,
|
|
||||||
cross: SpecAxis,
|
|
||||||
line_spacing: Length,
|
line_spacing: Length,
|
||||||
areas: Areas,
|
areas: Areas,
|
||||||
finished: Vec<Frame>,
|
finished: Vec<Frame>,
|
||||||
stack: Vec<(Length, Frame, Align)>,
|
stack: Vec<(Length, Frame, Align)>,
|
||||||
stack_size: Gen<Length>,
|
stack_size: Size,
|
||||||
line: Vec<(Length, Frame, Align)>,
|
line: Vec<(Length, Frame, Align)>,
|
||||||
line_size: Gen<Length>,
|
line_size: Size,
|
||||||
line_ruler: Align,
|
line_ruler: Align,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ParLayouter {
|
impl ParLayouter {
|
||||||
fn new(dir: Dir, line_spacing: Length, areas: Areas) -> Self {
|
fn new(dir: Dir, line_spacing: Length, areas: Areas) -> Self {
|
||||||
Self {
|
Self {
|
||||||
dirs: Gen::new(Dir::TTB, dir),
|
dir,
|
||||||
main: SpecAxis::Vertical,
|
|
||||||
cross: SpecAxis::Horizontal,
|
|
||||||
line_spacing,
|
line_spacing,
|
||||||
areas,
|
areas,
|
||||||
finished: vec![],
|
finished: vec![],
|
||||||
stack: vec![],
|
stack: vec![],
|
||||||
stack_size: Gen::ZERO,
|
stack_size: Size::ZERO,
|
||||||
line: vec![],
|
line: vec![],
|
||||||
line_size: Gen::ZERO,
|
line_size: Size::ZERO,
|
||||||
line_ruler: Align::Start,
|
line_ruler: Align::Start,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_spacing(&mut self, amount: Length) {
|
fn push_spacing(&mut self, amount: Length) {
|
||||||
let cross_max = self.areas.current.get(self.cross);
|
let max = self.areas.current.width;
|
||||||
self.line_size.cross = (self.line_size.cross + amount).min(cross_max);
|
self.line_size.width = (self.line_size.width + amount).min(max);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn push_text(&mut self, ctx: &mut LayoutContext, node: &TextNode, align: Align) {
|
fn push_text(&mut self, ctx: &mut LayoutContext, node: &TextNode, align: Align) {
|
||||||
@ -192,98 +189,80 @@ impl ParLayouter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A line can contain frames with different alignments. They exact
|
// A line can contain frames with different alignments. Their exact
|
||||||
// positions are calculated later depending on the alignments.
|
// positions are calculated later depending on the alignments.
|
||||||
let size = frame.size.switch(self.main);
|
let size = frame.size;
|
||||||
self.line.push((self.line_size.cross, frame, align));
|
self.line.push((self.line_size.width, frame, align));
|
||||||
self.line_size.cross += size.cross;
|
self.line_size.width += size.width;
|
||||||
self.line_size.main = self.line_size.main.max(size.main);
|
self.line_size.height = self.line_size.height.max(size.height);
|
||||||
self.line_ruler = align;
|
self.line_ruler = align;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn usable(&self) -> Size {
|
fn usable(&self) -> Size {
|
||||||
// Space occupied by previous lines is already removed from
|
// Space occupied by previous lines is already removed from
|
||||||
// `areas.current`, but the cross-extent of the current line needs to be
|
// `areas.current`, but the width of the current line needs to be
|
||||||
// subtracted to make sure the frame fits.
|
// subtracted to make sure the frame fits.
|
||||||
let mut usable = self.areas.current;
|
let mut usable = self.areas.current;
|
||||||
*usable.get_mut(self.cross) -= self.line_size.cross;
|
usable.width -= self.line_size.width;
|
||||||
usable
|
usable
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_line(&mut self) {
|
fn finish_line(&mut self) {
|
||||||
let full_size = {
|
let full_size = {
|
||||||
let expand = self.areas.expand.get(self.cross);
|
let expand = self.areas.expand.horizontal;
|
||||||
let full = self.areas.full.get(self.cross);
|
let full = self.areas.full.width;
|
||||||
Gen::new(
|
Size::new(
|
||||||
self.line_size.main,
|
expand.resolve(self.line_size.width, full),
|
||||||
expand.resolve(self.line_size.cross, full),
|
self.line_size.height,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut output = Frame::new(full_size.switch(self.main).to_size());
|
let mut output = Frame::new(full_size);
|
||||||
|
for (before, frame, align) in mem::take(&mut self.line) {
|
||||||
for (before, frame, align) in std::mem::take(&mut self.line) {
|
// Align along the x axis.
|
||||||
let child_cross_size = frame.size.get(self.cross);
|
let x = align.resolve(if self.dir.is_positive() {
|
||||||
|
before .. full_size.width - self.line_size.width + before
|
||||||
// Position along the cross axis.
|
|
||||||
let cross = align.resolve(if self.dirs.cross.is_positive() {
|
|
||||||
let after_with_self = self.line_size.cross - before;
|
|
||||||
before .. full_size.cross - after_with_self
|
|
||||||
} else {
|
} else {
|
||||||
let before_with_self = before + child_cross_size;
|
let before_with_self = before + frame.size.width;
|
||||||
let after = self.line_size.cross - (before + child_cross_size);
|
full_size.width - before_with_self
|
||||||
full_size.cross - before_with_self .. after
|
.. self.line_size.width - before_with_self
|
||||||
});
|
});
|
||||||
|
|
||||||
let pos = Gen::new(Length::ZERO, cross).switch(self.main).to_point();
|
let pos = Point::new(x, Length::ZERO);
|
||||||
output.push_frame(pos, frame);
|
output.push_frame(pos, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add line spacing, but only between lines.
|
// Add line spacing, but only between lines, not after the last line.
|
||||||
if !self.stack.is_empty() {
|
if !self.stack.is_empty() {
|
||||||
self.stack_size.main += self.line_spacing;
|
self.stack_size.height += self.line_spacing;
|
||||||
*self.areas.current.get_mut(self.main) -= self.line_spacing;
|
self.areas.current.height -= self.line_spacing;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update metrics of paragraph and reset for line.
|
self.stack.push((self.stack_size.height, output, self.line_ruler));
|
||||||
self.stack.push((self.stack_size.main, output, self.line_ruler));
|
self.stack_size.height += full_size.height;
|
||||||
self.stack_size.main += full_size.main;
|
self.stack_size.width = self.stack_size.width.max(full_size.width);
|
||||||
self.stack_size.cross = self.stack_size.cross.max(full_size.cross);
|
self.areas.current.height -= full_size.height;
|
||||||
*self.areas.current.get_mut(self.main) -= full_size.main;
|
self.line_size = Size::ZERO;
|
||||||
self.line_size = Gen::ZERO;
|
|
||||||
self.line_ruler = Align::Start;
|
self.line_ruler = Align::Start;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_area(&mut self) {
|
fn finish_area(&mut self) {
|
||||||
let full_size = self.stack_size;
|
let mut output = Frame::new(self.stack_size);
|
||||||
let mut output = Frame::new(full_size.switch(self.main).to_size());
|
for (before, line, align) in mem::take(&mut self.stack) {
|
||||||
|
// Align along the x axis.
|
||||||
for (before, line, cross_align) in std::mem::take(&mut self.stack) {
|
let x = align.resolve(if self.dir.is_positive() {
|
||||||
let child_size = line.size.switch(self.main);
|
Length::ZERO .. self.stack_size.width - line.size.width
|
||||||
|
|
||||||
// Position along the main axis.
|
|
||||||
let main = if self.dirs.main.is_positive() {
|
|
||||||
before
|
|
||||||
} else {
|
} else {
|
||||||
full_size.main - (before + child_size.main)
|
self.stack_size.width - line.size.width .. Length::ZERO
|
||||||
};
|
|
||||||
|
|
||||||
// Align along the cross axis.
|
|
||||||
let cross = cross_align.resolve(if self.dirs.cross.is_positive() {
|
|
||||||
Length::ZERO .. full_size.cross - child_size.cross
|
|
||||||
} else {
|
|
||||||
full_size.cross - child_size.cross .. Length::ZERO
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let pos = Gen::new(main, cross).switch(self.main).to_point();
|
let pos = Point::new(x, before);
|
||||||
output.push_frame(pos, line);
|
output.push_frame(pos, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.finished.push(output);
|
self.finished.push(output);
|
||||||
self.areas.next();
|
self.areas.next();
|
||||||
|
self.stack_size = Size::ZERO;
|
||||||
// Reset metrics for the whole paragraph.
|
|
||||||
self.stack_size = Gen::ZERO;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish(mut self) -> Vec<Frame> {
|
fn finish(mut self) -> Vec<Frame> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user