Place: justified RTF paragraphs marked right to left end their last line on the right

File › Place set every justified paragraph (`\qj`) of an RTF file as
Justify with last line aligned left, so a right-to-left paragraph
(`\rtlpar`) ended its last line on the left. Such a paragraph now
places as Justify with last line aligned right, in either order of the
two control words. `\qj` in a left-to-right paragraph still places as
Justify with last line aligned left, and `\ql`, `\qr`, `\qc` and `\qd`
keep their alignments in both directions.
This commit is contained in:
dotCooCoo
2026-10-18 12:34:30 +07:00
committed by bflatastic
parent b27b5b80ea
commit 5df664d1a7
+19 -1
View File
@@ -14,6 +14,8 @@
//! superscript and subscript, baseline shift (`\up`, `\dn`) and the color table's color (`\cf`).
//! - Paragraph formatting, reset by `\pard`: alignment (`\ql`, `\qc`, `\qr`, `\qj`, `\qd`), left,
//! right and first-line indents, space before and after, and direction (`\rtlpar`, `\ltrpar`).
//! `\ql` and `\qr` are the left and right edges in either direction, and a justified (`\qj`)
//! paragraph marked right to left (`\rtlpar`) ends its last line on the right.
//!
//! Other control words are skipped, and so are hidden text (`\v`) and the groups of destinations
//! that are not the document's text: every `\*` destination, the style sheet, document
@@ -608,7 +610,11 @@ impl Reader {
.paras
.iter()
.map(|p| ParaStyle {
justify: p.justify,
// `\qj` in an `\rtlpar` paragraph justifies it with its last line on the right.
justify: match p.justify {
Justify::JustifyLeft if p.rtl == Some(true) => Justify::JustifyRight,
j => j,
},
left_indent: twips(p.left),
right_indent: twips(p.right),
first_line_indent: twips(p.first),
@@ -682,6 +688,18 @@ mod tests {
assert_eq!(s.paras.last().map(|p| p.left_indent), Some(20.0));
}
#[test]
fn justified_right_to_left_paragraphs_end_their_last_line_on_the_right() {
let s = read(concat!(
r"{\rtf1\pard\rtlpar\qj a\par\pard\qj\rtlpar b\par\pard\qj c\par\pard\rtlpar\ltrpar\qj d\par",
r"\pard\rtlpar\ql e\par\pard\rtlpar\qr f\par\pard\rtlpar\qc g\par\pard\rtlpar\qd h}"
));
let justify: Vec<Justify> = s.paras.iter().map(|p| p.justify).collect();
use Justify::*;
assert_eq!(justify, [JustifyRight, JustifyRight, JustifyLeft, JustifyLeft, Left, Right, Center, JustifyAll]);
assert_eq!(s.paras.first().and_then(|p| p.direction), Some(ParaDirection::RightToLeft));
}
#[test]
fn deep_nesting_and_stray_braces_end_cleanly() {
let deep = format!("{{\\rtf1 {}x{}}}", "{".repeat(5000), "}".repeat(5000));