mirror of
https://github.com/storytold/designcraft.git
synced 2026-10-24 10:16:59 -06:00
Merge pull request #1561 from Hamza0101/fix/rtl-first-line-indent
A right-to-left paragraph's first-line indent is at its right edge (#1448)
This commit is contained in:
@@ -1676,10 +1676,16 @@ fn compose_with_db(doc: &Document, story: &Story, frames: &[FrameSpec], opts: &C
|
|||||||
}
|
}
|
||||||
// A drop cap sits at the start-side indent; the first-line indent doesn't move it.
|
// A drop cap sits at the start-side indent; the first-line indent doesn't move it.
|
||||||
let beside = drop_cap.as_ref().filter(|dc| line_no < dc.lines && col_first_line == 0).map(DropCap::indent);
|
let beside = drop_cap.as_ref().filter(|dc| line_no < dc.lines && col_first_line == 0).map(DropCap::indent);
|
||||||
|
let first_line = if line_no == 0 { pp.first_line_indent } else { 0.0 };
|
||||||
let (ind_l, ind_r) = match beside {
|
let (ind_l, ind_r) = match beside {
|
||||||
Some(w) if rtl => (pp.left_indent, pp.right_indent + w),
|
Some(w) if rtl => (pp.left_indent, pp.right_indent + w),
|
||||||
Some(w) => (pp.left_indent + w, pp.right_indent),
|
Some(w) => (pp.left_indent + w, pp.right_indent),
|
||||||
None => (pp.left_indent + if line_no == 0 { pp.first_line_indent } else { 0.0 }, pp.right_indent),
|
// The first-line indent is at the paragraph's start side, which is the right
|
||||||
|
// one in a right-to-left paragraph: applied on the left it moved the line the
|
||||||
|
// wrong way, out of the frame for the hanging indent a numbered list uses
|
||||||
|
// (#1448).
|
||||||
|
None if rtl => (pp.left_indent, pp.right_indent + first_line),
|
||||||
|
None => (pp.left_indent + first_line, pp.right_indent),
|
||||||
};
|
};
|
||||||
let lx0 = x0 + ind_l;
|
let lx0 = x0 + ind_l;
|
||||||
let lx1 = x1 - ind_r;
|
let lx1 = x1 - ind_r;
|
||||||
|
|||||||
@@ -7323,3 +7323,45 @@ fn parent_page_frames_know_which_side_of_the_spine_they_are_on() {
|
|||||||
assert!(frame_specs(&d, left_story)[0].left_page);
|
assert!(frame_specs(&d, left_story)[0].left_page);
|
||||||
assert!(!frame_specs(&d, right_story)[0].left_page);
|
assert!(!frame_specs(&d, right_story)[0].left_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A right-to-left paragraph's first-line indent belongs at its start side, the right. Applied on
|
||||||
|
/// the left it moved the first line the wrong way — out of the frame for the hanging indent a
|
||||||
|
/// numbered list uses (right indent 10 mm, first line −10 mm), while the wrapped lines sat where
|
||||||
|
/// the first line should have been (#1448).
|
||||||
|
#[test]
|
||||||
|
fn an_rtl_first_line_indent_is_at_the_right_edge() {
|
||||||
|
const MM: f64 = 72.0 / 25.4;
|
||||||
|
// Latin text in a right-to-left paragraph: the direction is the paragraph's, and it is the
|
||||||
|
// placement that is being measured, so no Arabic font has to be present.
|
||||||
|
let text = LOREM;
|
||||||
|
let rect = Rect::new(0.0, 0.0, 200.0, 300.0);
|
||||||
|
let para = |dir, align, first, left, right| ParaAttrs {
|
||||||
|
direction: Some(dir),
|
||||||
|
align: Some(align),
|
||||||
|
first_line_indent: Some(first),
|
||||||
|
left_indent: Some(left),
|
||||||
|
right_indent: Some(right),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
// The hanging indent of a numbered list, right to left.
|
||||||
|
let (d, sid, _) = doc_with(text, rect, para(designcraft_doc::TextDirection::RightToLeft, Align::Right, -10.0 * MM, 0.0, 10.0 * MM));
|
||||||
|
let cs = compose_story(&d, sid, &ComposeOptions::default());
|
||||||
|
let lines = all_lines(&cs);
|
||||||
|
assert!(lines.len() >= 2, "the text wraps: {}", lines.len());
|
||||||
|
let right_edge = |l: &Line| l.glyphs.iter().filter(|g| g.visible).map(|g| g.x + g.adv).fold(f64::MIN, f64::max);
|
||||||
|
let left_edge = |l: &Line| l.glyphs.iter().filter(|g| g.visible).map(|g| g.x).fold(f64::MAX, f64::min);
|
||||||
|
// The first line reaches the frame's right edge; the wrapped lines stop 10 mm short of it.
|
||||||
|
assert!((right_edge(lines[0]) - rect.x1).abs() < 1.0, "first line at the edge: {}", right_edge(lines[0]));
|
||||||
|
assert!((right_edge(lines[1]) - (rect.x1 - 10.0 * MM)).abs() < 1.0, "wrapped line indented: {}", right_edge(lines[1]));
|
||||||
|
// And nothing leaves the frame on the left, which is where the first line used to go.
|
||||||
|
for (i, l) in lines.iter().enumerate() {
|
||||||
|
assert!(left_edge(l) >= rect.x0 - 0.01, "line {i} starts inside the frame: {}", left_edge(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
// The same paragraph left to right is unchanged: the first line hangs on the left.
|
||||||
|
let (d, sid, _) = doc_with(text, rect, para(designcraft_doc::TextDirection::LeftToRight, Align::Left, -10.0 * MM, 10.0 * MM, 0.0));
|
||||||
|
let cs = compose_story(&d, sid, &ComposeOptions::default());
|
||||||
|
let lines = all_lines(&cs);
|
||||||
|
assert!((left_edge(lines[0]) - rect.x0).abs() < 1.0, "left to right, first line at the edge: {}", left_edge(lines[0]));
|
||||||
|
assert!((left_edge(lines[1]) - (rect.x0 + 10.0 * MM)).abs() < 1.0, "left to right, wrapped line indented: {}", left_edge(lines[1]));
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user