summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLaurenz <laurmaedje@gmail.com>2021-03-29 11:41:28 +0200
committerLaurenz <laurmaedje@gmail.com>2021-03-30 14:31:39 +0200
commit652986fd58db96036c31e397cc8651135845d06e (patch)
tree9d5dac3fa36cfb7b4d26ef9715e788b31e94bc4d /src
parent88da325c7df6efa84059961e705df35afd15c2f9 (diff)
Fix double leading 🐞
Diffstat (limited to 'src')
-rw-r--r--src/layout/par.rs83
1 files changed, 48 insertions, 35 deletions
diff --git a/src/layout/par.rs b/src/layout/par.rs
index cbd74248..902ffafa 100644
--- a/src/layout/par.rs
+++ b/src/layout/par.rs
@@ -1,6 +1,8 @@
use std::fmt::{self, Debug, Formatter};
use std::mem;
+use xi_unicode::LineBreakIterator;
+
use super::*;
use crate::exec::FontProps;
@@ -87,6 +89,7 @@ struct ParLayouter {
line: Vec<(Length, Frame, Align)>,
line_size: Size,
line_ruler: Align,
+ hard: bool,
}
impl ParLayouter {
@@ -101,6 +104,7 @@ impl ParLayouter {
line: vec![],
line_size: Size::ZERO,
line_ruler: Align::Start,
+ hard: true,
}
}
@@ -110,45 +114,50 @@ impl ParLayouter {
}
fn push_text(&mut self, ctx: &mut LayoutContext, node: &TextNode, align: Align) {
- // Text shaped up to the previous line break opportunity that can fit
- // the current line.
- let mut last = None;
-
// Position in the text at which the current line starts.
let mut start = 0;
- let iter = xi_unicode::LineBreakIterator::new(&node.text);
- for (pos, mandatory) in iter {
- while start != pos {
- let part = &node.text[start .. pos].trim_end();
- let frame = shape(part, &mut ctx.env.fonts, &node.props);
-
- if self.usable().fits(frame.size) {
- if mandatory {
- // We have to break here.
- self.push_frame(frame, align);
- self.finish_line();
- start = pos;
- last = None;
- } else {
- // Still fits into the line.
- last = Some((frame, pos));
- }
- } else {
- // Doesn't fit into the line. If `last` was `None`, the single
- // unbreakable piece of text didn't fit, but we can't break it
- // up further, so we just have to push it.
- let (frame, pos) = last.take().unwrap_or((frame, pos));
+ // The current line attempt: Text shaped up to the previous line break
+ // opportunity.
+ let mut last = None;
+
+ let mut iter = LineBreakIterator::new(&node.text).peekable();
+ while let Some(&(pos, mandatory)) = iter.peek() {
+ let part = &node.text[start .. pos].trim_end();
+ let frame = shape(part, &mut ctx.env.fonts, &node.props);
+
+ if self.usable().fits(frame.size) {
+ // Still fits into the line.
+ if mandatory {
+ // We have to break here.
self.push_frame(frame, align);
- self.finish_line();
+ self.finish_line(true);
start = pos;
- continue;
+ last = None;
+ } else {
+ last = Some((frame, pos));
}
-
- break;
+ } else if let Some((frame, pos)) = last.take() {
+ // The line start..pos doesn't fit. So we write the line up to
+ // the last position and retry writing just the single piece
+ // behind it.
+ self.push_frame(frame, align);
+ self.finish_line(false);
+ start = pos;
+ continue;
+ } else {
+ // Since last is `None`, we are at the first piece behind a line
+ // break and it still doesn't fit. Since we can't break it up
+ // further, so we just have to push it.
+ self.push_frame(frame, align);
+ self.finish_line(false);
+ start = pos;
}
+
+ iter.next();
}
+ // Leftovers.
if let Some((frame, _)) = last {
self.push_frame(frame, align);
}
@@ -168,12 +177,12 @@ impl ParLayouter {
// | Second |
// +----------------------------+
if self.line_ruler > align {
- self.finish_line();
+ self.finish_line(false);
}
// Find out whether the area still has enough space for this frame.
- if !self.usable().fits(frame.size) {
- self.finish_line();
+ if !self.usable().fits(frame.size) && self.line_size.width > Length::ZERO {
+ self.finish_line(false);
// Here, we can directly check whether the frame fits into
// `areas.current` since we just called `finish_line`.
@@ -207,7 +216,11 @@ impl ParLayouter {
usable
}
- fn finish_line(&mut self) {
+ fn finish_line(&mut self, hard: bool) {
+ if !mem::replace(&mut self.hard, hard) && self.line.is_empty() {
+ return;
+ }
+
let full_size = {
let expand = self.areas.expand.horizontal;
let full = self.areas.full.width;
@@ -266,7 +279,7 @@ impl ParLayouter {
}
fn finish(mut self) -> Vec<Frame> {
- self.finish_line();
+ self.finish_line(false);
self.finish_area();
self.finished
}