mirror of
https://github.com/storytold/vectorcraft.git
synced 2026-11-08 21:10:40 +00:00
.ai import: type keeps Standard Vertical Roman Alignment from its editing data
The modern type reader read key 35 of a character style only for Tate-chu-yoko (3). A run whose key 35 is 1 (Standard), in the run, its character style or the document's defaults, now opens with Standard Vertical Roman Alignment on, so its half-width characters stand upright in vertical type. Horizontal type keeps the mark with no change to its layout. A value of 2 (rotated), 3, any other value and no key at all leave it off, VectorCraft's default. - ate.rs: Style reads the flag and passes it to CharStyle, with a unit test over defaults, character styles, run overrides and bad values. - tests_native.rs: a vertical and a horizontal story with Standard, rotated and unset runs; the test of values the reader ignores also checks the flag. - import_fuzz.rs: the vertical fixture also checks the flag. - docs/file-format-parity.md: one line on the mapping.
This commit is contained in:
@@ -3100,11 +3100,17 @@ fn the_vertical_fixture_reads_as_vertical_type() {
|
||||
l.doc.walk(|n| {
|
||||
if let vectorcraft_doc::NodeKind::Text(t) = &n.kind {
|
||||
let tcy: Vec<&str> = t.runs.iter().filter(|r| r.style.tate_chu_yoko).map(|r| r.text.as_str()).collect();
|
||||
found.push((t.plain_text(), t.vertical, tcy.join("|")));
|
||||
let roman: Vec<&str> = t.runs.iter().filter(|r| r.style.standard_vertical_roman).map(|r| r.text.as_str()).collect();
|
||||
found.push((t.plain_text(), t.vertical, tcy.join("|"), roman.join("|")));
|
||||
}
|
||||
});
|
||||
let want = [("Day 12\nnext", true, "12"), ("Vertical area type wraps", true, ""), ("On a path", true, "On a path")];
|
||||
assert_eq!(found, want.map(|(a, b, c)| (a.to_string(), b, c.to_string())), "{:?}", l.warnings);
|
||||
// Key 35 at 1 in the defaults: Standard Vertical Roman Alignment, except where a run has 3 or 2.
|
||||
let want = [
|
||||
("Day 12\nnext", true, "12", "Day "),
|
||||
("Vertical area type wraps", true, "", "Vertical area type wraps"),
|
||||
("On a path", true, "On a path", ""),
|
||||
];
|
||||
assert_eq!(found, want.map(|(a, b, c, d)| (a.to_string(), b, c.to_string(), d.to_string())), "{:?}", l.warnings);
|
||||
}
|
||||
|
||||
/// The text objects of [`frames_document_text`]: story 0 in its two frames, story 1 in its one (a
|
||||
|
||||
@@ -424,6 +424,9 @@ struct Style {
|
||||
caps: u8,
|
||||
/// Key 35 at 3: Tate-chu-yoko, the characters set across the column as one block.
|
||||
tate_chu_yoko: bool,
|
||||
/// Key 35 at 1 (Standard): Standard Vertical Roman Alignment, half-width characters upright in
|
||||
/// a column. Any other value, or no key in the run, its character style or the defaults, is off.
|
||||
standard_vertical_roman: bool,
|
||||
}
|
||||
|
||||
/// The text document of an editing copy.
|
||||
@@ -664,6 +667,7 @@ impl Texts {
|
||||
stroke_width: num("63").filter(|v| *v >= 0.0 && *v < 1e4).unwrap_or(1.0),
|
||||
caps: num("12").filter(|v| *v == 1.0 || *v == 2.0).map_or(0, |v| v as u8),
|
||||
tate_chu_yoko: num("35") == Some(3.0),
|
||||
standard_vertical_roman: num("35") == Some(1.0),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1206,6 +1210,7 @@ fn char_style(s: &Style, scale: f64, leading: Option<f64>) -> CharStyle {
|
||||
// At the default Small Caps size of Document Setup: the file's own isn't read.
|
||||
small_caps: (s.caps == 1).then(|| vectorcraft_doc::DocSetup::default().small_caps_size),
|
||||
tate_chu_yoko: s.tate_chu_yoko,
|
||||
standard_vertical_roman: s.standard_vertical_roman,
|
||||
..CharStyle::default()
|
||||
}
|
||||
}
|
||||
@@ -1328,6 +1333,35 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
/// Key 35 of a character style at 1 (Standard) is Standard Vertical Roman Alignment, from the
|
||||
/// run, its character style or the document's defaults; at 2 (rotated), 3 (Tate-chu-yoko), a
|
||||
/// value that isn't one of those numbers, or with no key anywhere it is off.
|
||||
#[test]
|
||||
fn baseline_direction_one_is_standard_vertical_roman_alignment() {
|
||||
let texts = |defaults: &[u8]| Texts {
|
||||
stories: vec![],
|
||||
fonts: vec![],
|
||||
defaults: read(defaults).unwrap(),
|
||||
para_defaults: Val::Dict(BTreeMap::new()),
|
||||
char_sheets: vec![read(b"/0 ([Normal Character Style]) /6 << >>").unwrap(), read(b"/0 (Rotated) /6 << /35 2 >>").unwrap()],
|
||||
para_sheets: vec![],
|
||||
frames: vec![],
|
||||
};
|
||||
let roman = |defaults: &[u8], run: &[u8]| texts(defaults).style(Some(&read(run).unwrap())).standard_vertical_roman;
|
||||
assert!(roman(b"/35 1", b"/6 << >>"), "the document's defaults");
|
||||
assert!(roman(b"/35 2", b"/6 << /35 1 >>"), "the run's own");
|
||||
assert!(!roman(b"/35 1", b"/6 << /35 2 >>"), "the run's own rotated");
|
||||
assert!(!roman(b"/35 1", b"/5 1 /6 << >>"), "its character style's");
|
||||
assert!(roman(b"/35 2", b"/5 1 /6 << /35 1 >>"), "the run's own wins over its style");
|
||||
assert!(!roman(b"/0 0", b"/6 << >>"), "no key: off");
|
||||
for other in
|
||||
[&b"/6 << /35 3 >>"[..], b"/6 << /35 1.5 >>", b"/6 << /35 (1) >>", b"/6 << /35 -1 >>", b"/6 << /35 true >>", b"/6 << /35 [ 1 ] >>"]
|
||||
{
|
||||
assert!(!roman(b"/0 0", other), "{}", String::from_utf8_lossy(other));
|
||||
}
|
||||
assert!(texts(b"/35 3").style(None).tate_chu_yoko && !texts(b"/35 3").style(None).standard_vertical_roman);
|
||||
}
|
||||
|
||||
/// A right-to-left paragraph is laid out right to left even when it has no right-to-left
|
||||
/// letters (a dimension's label " 120.5 mm " reads "mm 120.5"); a left-to-right one, or one
|
||||
/// that doesn't say, goes by its letters.
|
||||
@@ -1597,6 +1631,7 @@ mod tests {
|
||||
stroke_width: 1.0,
|
||||
caps: 0,
|
||||
tate_chu_yoko: false,
|
||||
standard_vertical_roman: false,
|
||||
},
|
||||
)],
|
||||
path_spacing: 0.0,
|
||||
|
||||
@@ -2828,6 +2828,32 @@ fn a_tate_chu_yoko_run_is_marked() {
|
||||
assert_eq!(marked, [("§".to_string(), false), ("12".to_string(), true), ("§".to_string(), false)]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_standard_baseline_run_keeps_standard_vertical_roman_alignment() {
|
||||
// Three runs over "ab12": "ab" with key 35 at 1 (Standard), "1" at 2 (rotated), "2" without it.
|
||||
// Horizontal type keeps the mark too.
|
||||
for vertical in [true, false] {
|
||||
let doc = text_document(&[("ab12\r", 0, (8200.0, 8180.0), (0.0, 0.0), 0.0)]);
|
||||
let doc = if vertical { vertical_text_document(&doc, 0.0) } else { doc };
|
||||
let run = |n: u32, own: &str| {
|
||||
format!(
|
||||
"<< /0 << /0 << /0 () /5 0 /6 << /0 0 /1 14.0 {own}/53 << /99 /CAITextPaint /0 << /0 2 /1 [ 1.0 0.0 1.0 0.0 0.0 ] >> >> >> >> >> /1 {n} >>"
|
||||
)
|
||||
};
|
||||
let one = run(5, "");
|
||||
assert!(doc.contains(&one));
|
||||
let doc = doc.replacen(&one, &format!("{} {} {}", run(2, "/35 1 "), run(1, "/35 2 "), run(2, "")), 1);
|
||||
let art = native_with_text(&(layer("Back", true, &square(10, 10)) + &layer("Spare", false, &text_object(0))), &doc);
|
||||
let r = import(&eps(&page_square(10, 10), &art)).unwrap();
|
||||
let texts = text_of(&r.document.layers[1]);
|
||||
assert_eq!(texts.len(), 1, "{:?}", r.warnings);
|
||||
assert_eq!(texts[0].vertical, vertical);
|
||||
let marked: Vec<(String, bool, bool)> =
|
||||
texts[0].runs.iter().map(|r| (r.text.clone(), r.style.standard_vertical_roman, r.style.tate_chu_yoko)).collect();
|
||||
assert_eq!(marked, [("ab".to_string(), true, false), ("1".to_string(), false, false), ("2".to_string(), false, false)], "{vertical}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn orientation_and_tate_chu_yoko_values_it_cant_use_are_ignored() {
|
||||
for bad in ["(2)", "2.5", "1e300", "-2", "1", "true", "[ 2 ]"] {
|
||||
@@ -2840,6 +2866,8 @@ fn orientation_and_tate_chu_yoko_values_it_cant_use_are_ignored() {
|
||||
assert_eq!(texts.len(), 1, "{bad}: {:?}", r.warnings);
|
||||
assert!(!texts[0].vertical, "{bad}");
|
||||
assert!(texts[0].runs.iter().all(|r| !r.style.tate_chu_yoko), "{bad}");
|
||||
// Key 35 at 1 is Standard Vertical Roman Alignment; the other values leave it off.
|
||||
assert!(texts[0].runs.iter().all(|r| r.style.standard_vertical_roman == (bad == "1")), "{bad}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user