diff --git a/crates/docx/src/read/props.rs b/crates/docx/src/read/props.rs
index d6d97914e..0ba0132a5 100644
--- a/crates/docx/src/read/props.rs
+++ b/crates/docx/src/read/props.rs
@@ -42,7 +42,19 @@ impl PropCtx {
.filter(|f| !f.is_empty())
.map(str::to_string)
.or_else(|| k.attr("w:asciiTheme").or_else(|| k.attr("w:hAnsiTheme")).and_then(|t| self.theme_font(t)))
- .or_else(|| k.attr("w:cs").or_else(|| k.attr("w:eastAsia")).filter(|f| !f.is_empty()).map(str::to_string));
+ .or_else(|| {
+ // `w:eastAsia` and `w:cs` name fonts for other scripts; they stand in for the
+ // Latin font only when the run is hinted as that script. Otherwise the Latin
+ // font is inherited (a Normal style with only `w:eastAsia`/`w:cs` keeps the
+ // `docDefaults` font, as in Word).
+ match k.attr("w:hint") {
+ Some("eastAsia") => k.attr("w:eastAsia"),
+ Some("cs") => k.attr("w:cs"),
+ _ => None,
+ }
+ .filter(|f| !f.is_empty())
+ .map(str::to_string)
+ });
}
"w:b" => c.bold = Some(on_off(k)),
"w:i" => c.italic = Some(on_off(k)),
diff --git a/crates/docx/tests/fixtures.rs b/crates/docx/tests/fixtures.rs
index 7f1d99b7f..d91d6a8b5 100644
--- a/crates/docx/tests/fixtures.rs
+++ b/crates/docx/tests/fixtures.rs
@@ -389,6 +389,25 @@ fn header_self_reference_and_escaping_targets() {
wordcraft_docx::read(&out).unwrap();
}
+#[test]
+fn style_rfonts_without_ascii_inherits_doc_defaults_font() {
+ // Issue #93: Normal names only East Asian / complex-script fonts, so Latin text keeps the
+ // docDefaults font. A run hinted as East Asian still uses its East Asian font.
+ let styles = format!(
+ r#"
+
+
+"#
+ );
+ let body = r#"Plain漢字"#;
+ let d = wordcraft_docx::read(&docx(body, &[("rId1", "styles", "styles.xml")], &[("word/styles.xml", &styles)])).unwrap();
+ assert_eq!(d.styles.get("Normal").unwrap().chr.font, None);
+ let ps = paras(&d);
+ let font = |p: &Paragraph| d.styles.resolve_char(p.props.style.as_deref(), &p.runs[0].props).font;
+ assert_eq!(font(ps[0]), "Calibri");
+ assert_eq!(font(ps[1]), "SimSun");
+}
+
#[test]
fn bare_break_directly_in_paragraph() {
let body = r#"FirstSecondThird"#;