mirror of
https://github.com/storytold/wordcraft.git
synced 2026-10-27 03:47:09 -06:00
Fonts: a Bidi theme slot names the theme's complex-script font (#1619)
w:asciiTheme="minorBidi" (and majorBidi, and w:cstheme) read as the theme's Latin font, so a template's titles came out in Calibri where Word draws Arial. Measured in Word: the slot names the theme's a:cs font, and an empty a:cs names nothing, so the font inherited from the style applies. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
Brandon Thomas
parent
74a279d5f2
commit
63ed4daab2
@@ -726,6 +726,9 @@ impl Reader<'_> {
|
||||
if let Some(f) = face("a:minorFont") {
|
||||
self.doc.settings.minor_font = f;
|
||||
}
|
||||
let cs = |n: &str| fs.child(n).and_then(|f| f.child("a:cs")).and_then(|c| c.attr("typeface")).unwrap_or_default().to_string();
|
||||
self.pc.major_cs = cs("a:majorFont");
|
||||
self.pc.minor_cs = cs("a:minorFont");
|
||||
}
|
||||
self.pc.major_font = self.doc.settings.major_font.clone();
|
||||
self.pc.minor_font = self.doc.settings.minor_font.clone();
|
||||
|
||||
@@ -43,6 +43,9 @@ use crate::xml::El;
|
||||
pub struct PropCtx {
|
||||
pub major_font: String,
|
||||
pub minor_font: String,
|
||||
/// The theme's complex-script fonts (`a:cs`), which the `…Bidi` theme slots name.
|
||||
pub major_cs: String,
|
||||
pub minor_cs: String,
|
||||
/// The theme's colour scheme (dk1, lt1, dk2, lt2, accent1..6, hlink, folHlink); empty when the
|
||||
/// package has none, and then `w:themeColor` falls back to the fixed colour.
|
||||
pub theme_colors: Vec<Rgb>,
|
||||
@@ -82,7 +85,10 @@ impl PropCtx {
|
||||
}
|
||||
|
||||
fn theme_font(&self, t: &str) -> Option<String> {
|
||||
let f = if t.starts_with("major") { &self.major_font } else { &self.minor_font };
|
||||
let (latin, cs) = if t.starts_with("major") { (&self.major_font, &self.major_cs) } else { (&self.minor_font, &self.minor_cs) };
|
||||
// Measured in Word: `minorBidi`/`majorBidi` name the complex-script font, and an empty one
|
||||
// names nothing, so the font beside it or the inherited one applies.
|
||||
let f = if t.ends_with("Bidi") { cs } else { latin };
|
||||
(!f.is_empty()).then(|| f.clone())
|
||||
}
|
||||
|
||||
|
||||
@@ -2567,6 +2567,23 @@ fn text_frames_read_and_round_trip() {
|
||||
assert!(q.iter().any(|x| x.props.drop_cap == Some(2) && x.props.frame.is_none()));
|
||||
}
|
||||
|
||||
/// Measured in Word: `w:asciiTheme="minorBidi"` names the theme's complex-script font (`a:cs`);
|
||||
/// when that is empty it names nothing, and the run keeps the font it inherits.
|
||||
#[test]
|
||||
fn bidi_theme_slots_name_the_complex_script_font() {
|
||||
let font = |cs: &str| {
|
||||
let theme = format!(
|
||||
r#"<?xml version="1.0" encoding="UTF-8" standalone="yes"?><a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="T"><a:themeElements><a:fontScheme name="F"><a:majorFont><a:latin typeface="Cambria"/><a:ea typeface=""/><a:cs typeface="{cs}"/></a:majorFont><a:minorFont><a:latin typeface="Calibri"/><a:ea typeface=""/><a:cs typeface="{cs}"/></a:minorFont></a:fontScheme></a:themeElements></a:theme>"#
|
||||
);
|
||||
let rels = [("rId9", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme", "theme/theme1.xml")];
|
||||
let body = r#"<w:p><w:r><w:rPr><w:rFonts w:asciiTheme="minorBidi" w:hAnsiTheme="minorBidi"/></w:rPr><w:t>x</w:t></w:r></w:p>"#;
|
||||
let d = wordcraft_docx::read(&docx(body, &rels, &[("word/theme/theme1.xml", &theme)])).unwrap();
|
||||
paras(&d)[0].runs[0].props.font.clone()
|
||||
};
|
||||
assert_eq!(font(""), None);
|
||||
assert_eq!(font("Times New Roman").as_deref(), Some("Times New Roman"));
|
||||
}
|
||||
|
||||
/// The font table's family classes: Word draws a missing roman font in a serif face.
|
||||
#[test]
|
||||
fn roman_fonts_are_read_from_the_font_table() {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# File-format parity with Microsoft Word
|
||||
|
||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-14 · **Change:** trivial (missing roman fonts drawn in Cambria; previously trivial: legacy DOC DIB conversion honours the BLIP byte limit; related #1334 and #1554; previously trivial: right triangles keep their right angle; previously trivial: section `w:vAlign` "both" round-trips as Justified, #1320; previously trivial: Word's text watermark written back to DOCX headers, #1290; previously trivial: VML preset shapes drawn, #1377; previously trivial: VML text boxes keep their internal margins, fit to their text and vertical alignment; hidden drawings not shown; previously trivial: equations as MathML in HTML export, copy and paste, #816; previously trivial: symbol-font text exported as Unicode, #776; previously trivial: text-box margins, Resize shape to fit text and freeforms in groups, #743; previously trivial: formatted paste from the system clipboard's HTML and RTF, #687; previously trivial: independent complex-script formatting inheritance and round-trip regression tests; previously trivial: import/export fixes for TXT, RTF, ODT, HTML and LaTeX, #433–#440; previously major: first version; every format Word reads or writes, measured from the readers and writers on origin/main) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4, plus Word for Windows' extra formats
|
||||
> **Last reviewed:** 2026-10-11 · **Last updated:** 2026-10-14 · **Change:** trivial (Bidi theme font slots; previously trivial: missing roman fonts drawn in Cambria; previously trivial: legacy DOC DIB conversion honours the BLIP byte limit; related #1334 and #1554; previously trivial: right triangles keep their right angle; previously trivial: section `w:vAlign` "both" round-trips as Justified, #1320; previously trivial: Word's text watermark written back to DOCX headers, #1290; previously trivial: VML preset shapes drawn, #1377; previously trivial: VML text boxes keep their internal margins, fit to their text and vertical alignment; hidden drawings not shown; previously trivial: equations as MathML in HTML export, copy and paste, #816; previously trivial: symbol-font text exported as Unicode, #776; previously trivial: text-box margins, Resize shape to fit text and freeforms in groups, #743; previously trivial: formatted paste from the system clipboard's HTML and RTF, #687; previously trivial: independent complex-script formatting inheritance and round-trip regression tests; previously trivial: import/export fixes for TXT, RTF, ODT, HTML and LaTeX, #433–#440; previously major: first version; every format Word reads or writes, measured from the readers and writers on origin/main) · **Target:** Microsoft Word (Microsoft 365) for Mac 16.113.4, plus Word for Windows' extra formats
|
||||
|
||||
Every format Word opens or saves, what WordCraft does with it, and how it's tested. Fidelity is the
|
||||
share of a typical real-world file's content and formatting that survives (read: shows correctly;
|
||||
@@ -195,6 +195,7 @@ attributes inside stories and style or list definitions; a regenerated theme. Te
|
||||
|
||||
| Date | Change | Summary |
|
||||
|---|---|---|
|
||||
| 2026-10-14 | trivial | `minorBidi`/`majorBidi` theme fonts name the theme's complex-script font (`a:cs`); an empty one names nothing, so the inherited font applies, as measured in Word |
|
||||
| 2026-10-14 | trivial | A missing font the font table classes as roman is drawn in Cambria, as measured in Word (Calibri for the other classes, as before) |
|
||||
| 2026-10-14 | minor | Legacy DOC DIB helper honours the supplied byte limit for its BMP header/copy, decoder and PNG output, with a bounded BMP fallback. Generated 1-pixel regression only; resource-exhaustion consequences unmeasured, fidelity/readiness estimates unchanged. Related: #1334 and #1554 |
|
||||
| 2026-10-14 | trivial | Right triangles (`rtTriangle`) keep their right angle at the bottom left instead of becoming isosceles triangles, and save back as `rtTriangle` |
|
||||
|
||||
Reference in New Issue
Block a user