diff --git a/crates/docx/tests/it/bidi.rs b/crates/docx/tests/it/bidi.rs
index 6dae963aa..bea7e2131 100644
--- a/crates/docx/tests/it/bidi.rs
+++ b/crates/docx/tests/it/bidi.rs
@@ -290,3 +290,40 @@ fn thai_text_takes_the_complex_script_formatting_only_in_a_complex_script_run()
assert_eq!(drawn, [("Angsana New".to_string(), 22.0), ("Tahoma".to_string(), 11.0), ("Angsana New".to_string(), 22.0)], "{when}");
}
}
+
+/// Measured in Word for Windows: Thai text as a field's result follows the same rule as ordinary
+/// text, also when the reader keeps the field as one object with its result.
+#[test]
+fn a_fields_thai_result_takes_the_complex_script_formatting_only_in_a_complex_script_run() {
+ let styles = r#"
+"#;
+ let field = |rpr: &str| {
+ let r = |inner: &str| format!("{rpr}{inner}");
+ format!(
+ "{}{}{}{}{}",
+ r(r#""#),
+ r(r#" QUOTE "x" "#),
+ r(r#""#),
+ r("ทดสอบ"),
+ r(r#""#)
+ )
+ };
+ let drawn = |d: &Document| {
+ let p = paras(d)[0];
+ let at = p.text.find(craft_wordmodel::para::OBJ).expect("the field is one object");
+ let run = p.runs.iter().scan(0, |end, r| {
+ let start = *end;
+ *end += r.len;
+ Some((start, r))
+ });
+ let (_, run) = run.into_iter().find(|(start, r)| *start <= at && at < start + r.len).unwrap();
+ let rc = d.styles.resolve_char(p.props.style.as_deref(), &run.props);
+ if rc.uses_complex('ท') { (rc.font_cs.clone(), rc.size_cs) } else { (rc.font.clone(), rc.size) }
+ };
+ for (what, rpr, want) in [("nothing", "", ("Angsana New", 10.0)), ("w:cs", "", ("Tahoma", 20.0))] {
+ let d = craft_docx::read(&docx_with_styles(&field(rpr), styles)).unwrap();
+ assert_eq!(drawn(&d), (want.0.to_string(), want.1), "a run with {what}: read");
+ let again = craft_docx::read(&craft_docx::write(&d).unwrap()).unwrap();
+ assert_eq!(drawn(&again), (want.0.to_string(), want.1), "a run with {what}: after a save");
+ }
+}
diff --git a/crates/wordmodel/src/styles.rs b/crates/wordmodel/src/styles.rs
index 81d8cd272..1d725efa2 100644
--- a/crates/wordmodel/src/styles.rs
+++ b/crates/wordmodel/src/styles.rs
@@ -841,11 +841,25 @@ impl StyleSheet {
/// right to left.
pub fn mark_runs_as_word_draws_them(&self, para: &mut crate::para::Paragraph, table: Option<&CharProps>) {
use crate::bidi::{is_complex_script, is_rtl_script};
- let style = para.props.style.as_deref();
- let mut at = 0;
- for run in &mut para.runs {
- let text = para.text.get(at..at + run.len).unwrap_or("");
+ use crate::para::{InlineObject, OBJ};
+ // What each run draws: its text, a field kept as one object standing for its result
+ // (drawn in the run's formatting, and measured in Word to follow the same rule).
+ let mut drawn = Vec::with_capacity(para.runs.len());
+ let (mut at, mut objects) = (0, para.objects.iter());
+ for run in ¶.runs {
+ let mut text = String::new();
+ for c in para.text.get(at..at + run.len).unwrap_or("").chars() {
+ if c != OBJ {
+ text.push(c);
+ } else if let Some(InlineObject::Field { result, code: false, .. }) = objects.next() {
+ text.push_str(result);
+ }
+ }
at += run.len;
+ drawn.push(text);
+ }
+ let style = para.props.style.as_deref();
+ for (run, text) in para.runs.iter_mut().zip(&drawn) {
if text.is_empty() || text.chars().any(is_rtl_script) {
continue;
}