Fix multi-page paragraph bugs 🐞

This commit is contained in:
Laurenz 2021-04-03 20:53:18 +02:00
parent d74c9378b8
commit 9014e83478
2 changed files with 45 additions and 49 deletions

View File

@ -128,10 +128,12 @@ impl<'a> ParLayout<'a> {
}); });
} }
ParChild::Any(ref node, align) => { ParChild::Any(ref node, align) => {
for frame in node.layout(ctx, areas) { let frames = node.layout(ctx, areas);
assert_eq!(frames.len(), 1);
let frame = frames.into_iter().next().unwrap();
items.push(ParItem::Frame(frame, align)); items.push(ParItem::Frame(frame, align));
ranges.push(range.clone()); ranges.push(range);
}
} }
} }
} }
@ -145,39 +147,38 @@ impl<'a> ParLayout<'a> {
let mut last = None; let mut last = None;
let mut stack = LineStack::new(par.line_spacing, areas); let mut stack = LineStack::new(par.line_spacing, areas);
// TODO: Provide line break opportunities on alignment changes.
let mut iter = LineBreakIterator::new(self.bidi.text).peekable();
// Find suitable line breaks. // Find suitable line breaks.
while let Some(&(end, mandatory)) = iter.peek() { // TODO: Provide line break opportunities on alignment changes.
assert!(start <= end); for (end, mandatory) in LineBreakIterator::new(self.bidi.text) {
let mut line = LineLayout::new(&self, start .. end, ctx);
let mut size = line.measure().0;
let line = LineLayout::new(&self, start .. end, ctx); if !stack.areas.current.fits(size) {
let size = line.measure().0; if let Some((last_line, last_end)) = last.take() {
stack.push(last_line);
start = last_end;
line = LineLayout::new(&self, start .. end, ctx);
size = line.measure().0;
}
}
// Find out whether the line fits. if !stack.areas.current.height.fits(size.height)
if stack.fits(size) { && !stack.areas.in_full_last()
if mandatory { {
stack.finish_area();
}
if mandatory || !stack.areas.current.width.fits(size.width) {
stack.push(line); stack.push(line);
start = end; start = end;
last = None; last = None;
if end == self.bidi.text.len() {
if mandatory && end == self.bidi.text.len() {
stack.push(LineLayout::new(&self, end .. end, ctx)); stack.push(LineLayout::new(&self, end .. end, ctx));
} }
} else { } else {
last = Some((line, end)); last = Some((line, end));
} }
} else if let Some((line, end)) = last.take() {
stack.push(line);
stack.prepare(size.height);
start = end;
continue;
} else {
stack.push(line);
start = end;
}
iter.next();
} }
if let Some((line, _)) = last { if let Some((line, _)) = last {
@ -433,27 +434,16 @@ impl<'a> LineStack<'a> {
} }
} }
fn fits(&self, size: Size) -> bool {
self.areas.current.fits(size)
}
fn prepare(&mut self, height: Length) {
if !self.areas.current.height.fits(height) && !self.areas.in_full_last() {
self.finish_area();
}
}
fn push(&mut self, line: LineLayout<'a>) { fn push(&mut self, line: LineLayout<'a>) {
let size = line.measure().0; let size = line.measure().0;
if !self.lines.is_empty() {
self.size.height += self.line_spacing;
self.areas.current.height -= self.line_spacing;
}
self.size.width = self.size.width.max(size.width); self.size.width = self.size.width.max(size.width);
self.size.height += size.height; self.size.height += size.height;
self.areas.current.height -= size.height; if !self.lines.is_empty() {
self.size.height += self.line_spacing;
}
self.areas.current.height -= size.height + self.line_spacing;
self.lines.push(line); self.lines.push(line);
} }

View File

@ -28,7 +28,13 @@ impl Layout for StackNode {
match *child { match *child {
StackChild::Spacing(amount) => layouter.push_spacing(amount), StackChild::Spacing(amount) => layouter.push_spacing(amount),
StackChild::Any(ref node, aligns) => { StackChild::Any(ref node, aligns) => {
for frame in node.layout(ctx, &layouter.areas) { let mut frames = node.layout(ctx, &layouter.areas).into_iter();
if let Some(frame) = frames.next() {
layouter.push_frame(frame, aligns);
}
for frame in frames {
layouter.finish_area();
layouter.push_frame(frame, aligns); layouter.push_frame(frame, aligns);
} }
} }