mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-15 08:45:25 +00:00
Type: a tab to a default or left stop reads none of the text after it
tab_advance read the text after a tab up to the next tab for every stop, though only right, center and decimal stops align it. The first tab of a long paragraph read the paragraph to its end, even on a line that stops reading a bounded number of breaks past its overflow. It now reads that text only when it reaches a stop that aligns it.
This commit is contained in:
@@ -214,18 +214,30 @@ pub(super) fn tab_advance<'t, 'g>(
|
||||
) -> (f64, &'t str) {
|
||||
use vectorcraft_doc::TabAlign;
|
||||
let rel = x - origin;
|
||||
let seg: Vec<&SGlyph> = rest.into_iter().take_while(|g| g.ch != '\t' && g.ch != '\u{2028}').collect();
|
||||
let width: f64 = seg.iter().map(|g| g.adv).sum();
|
||||
let target = |pos: f64, align: TabAlign, on: char| match align {
|
||||
TabAlign::Left => pos,
|
||||
TabAlign::Right => pos - width,
|
||||
TabAlign::Center => pos - width / 2.0,
|
||||
TabAlign::Decimal => pos - seg.iter().take_while(|g| g.ch != on).map(|g| g.adv).sum::<f64>(),
|
||||
};
|
||||
let explicit = tabs.iter().find_map(|t| {
|
||||
let at = target(t.position, t.align, t.align_on);
|
||||
(at > rel + 1e-6).then_some((at, t.leader.as_str()))
|
||||
});
|
||||
// The text after the tab is read only when a right, center or decimal stop is reached, since
|
||||
// only those align it. A tab to a default or left stop reads none of it.
|
||||
let mut rest = Some(rest);
|
||||
let mut seg: Vec<&SGlyph> = Vec::new();
|
||||
let mut width = 0.0;
|
||||
let mut explicit = None;
|
||||
for t in tabs {
|
||||
if t.align != TabAlign::Left
|
||||
&& let Some(r) = rest.take()
|
||||
{
|
||||
seg = r.into_iter().take_while(|g| g.ch != '\t' && g.ch != '\u{2028}').collect();
|
||||
width = seg.iter().map(|g| g.adv).sum();
|
||||
}
|
||||
let at = match t.align {
|
||||
TabAlign::Left => t.position,
|
||||
TabAlign::Right => t.position - width,
|
||||
TabAlign::Center => t.position - width / 2.0,
|
||||
TabAlign::Decimal => t.position - seg.iter().take_while(|g| g.ch != t.align_on).map(|g| g.adv).sum::<f64>(),
|
||||
};
|
||||
if at > rel + 1e-6 {
|
||||
explicit = Some((at, t.leader.as_str()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
let (at, leader) = explicit.unwrap_or_else(|| {
|
||||
let last = tabs.iter().map(|t| t.position).fold(0.0, f64::max).max(0.0);
|
||||
let base = rel.max(last);
|
||||
|
||||
@@ -745,6 +745,24 @@ fn a_tabbed_line_stepping_back_ends_at_a_final_soft_hyphen_without_a_hyphen() {
|
||||
assert_eq!(ended, (len, false));
|
||||
}
|
||||
|
||||
/// A tab to a default or left stop does not read the text after it, which only right, center and
|
||||
/// decimal stops align: the first tab of a long paragraph does not read the paragraph to its end.
|
||||
#[test]
|
||||
fn a_tab_to_a_default_or_left_stop_reads_no_text_after_it() {
|
||||
use vectorcraft_doc::{TabAlign, TabStop};
|
||||
let (_, glyphs) = stepping_back_tabbed_line(2000);
|
||||
let read = std::cell::Cell::new(0usize);
|
||||
let rest = || glyphs[2..].iter().inspect(|_| read.set(read.get() + 1));
|
||||
let left = [TabStop { position: 100.0, align: TabAlign::Left, leader: String::new(), align_on: '.' }];
|
||||
assert_eq!(tab_advance(&[], 0.0, 1.0, rest()).0, 35.0);
|
||||
assert_eq!(tab_advance(&left, 0.0, 1.0, rest()).0, 99.0);
|
||||
assert_eq!(read.get(), 0, "read {} glyphs after the tab", read.get());
|
||||
// A right stop reads up to the next tab and aligns that text on the stop.
|
||||
let right = [TabStop { position: 100.0, align: TabAlign::Right, leader: String::new(), align_on: '.' }];
|
||||
let short = synthetic_glyphs(&[(0, 1, 2.0, 'b'), (1, 1, 3.0, 'b'), (2, 1, 0.0, '\t'), (3, 1, 7.0, 'b')]);
|
||||
assert_eq!(tab_advance(&right, 0.0, 1.0, short.iter()).0, 94.0);
|
||||
}
|
||||
|
||||
/// A long tabbed line with a glyph that steps back ends at the latest break that fits as drawn, even
|
||||
/// where a later break than one that does not fit fits again.
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user