diff --git a/crates/xfa/src/tests.rs b/crates/xfa/src/tests.rs index 7da9321059..498cdf8fb3 100644 --- a/crates/xfa/src/tests.rs +++ b/crates/xfa/src/tests.rs @@ -3364,6 +3364,62 @@ fn a_caption_is_measured_in_the_font_and_paragraph_it_is_drawn_in() { assert!((left_next.y - left.y - (line + 4.0)).abs() < 0.01, "a one-line caption beside the box adds no height: {}", left_next.y - left.y); } +/// The room a caption with no font and no reserve takes is worked out in its field's font, +/// resolved before the room is: beside the box, the caption text's width; above it, one line. +/// A 24pt field's caption takes four times the room of a 6pt one's, and neither takes the +/// room of the 10pt Courier default. +#[test] +fn a_caption_without_a_font_or_a_reserve_takes_room_in_its_fields_font() { + // A 5in field at x=1in in 24pt or 6pt Arial, its caption naming no font and no reserve. + let field = |size: f64, placement: &str| { + let items = positioned(&format!( + r#"Name:"# + )); + let rect = items.iter().find_map(|i| if let Item::Widget(w) = i { Some(w.rect) } else { None }).expect("the field"); + let cap = items.iter().find_map(|i| if let Item::Text(s) = i { Some((s.x, s.face.family, s.face.size)) } else { None }).expect("the caption"); + (rect, cap) + }; + let helvetica = |size: f64| text::Face { + family: crate::text::Family::Helvetica, + bold: false, + italic: false, + size, + color: [0.0; 3], + underline: false, + h_scale: 1.0, + }; + let courier_room = text::Face { family: crate::text::Family::Courier, ..helvetica(10.0) }.width("Name:") + 2.0; + let mut rooms = Vec::new(); + for size in [24.0, 6.0] { + let (rect, (cap_x, family, cap_size)) = field(size, "left"); + // The box starts after the caption's room: its text's width in the field's font, plus 2pt. + let room = rect.x - cap_x; + let expected = helvetica(size).width("Name:") + 2.0; + assert!((room - expected).abs() < 0.05, "{size}pt: the caption takes {room}pt, not {expected}pt"); + assert!((room - courier_room).abs() > 1.0, "{size}pt: not the default's {courier_room}pt"); + // And it is drawn in that font, whole, in the room it was given. + assert_eq!((family, cap_size), (crate::text::Family::Helvetica, size), "drawn in the field's font"); + rooms.push(room - 2.0); + // Above the box, the caption takes one line of the field's font. + // (The field's top is the box's, 0.5in down the page.) + let (top, _) = field(size, "top"); + let above = top.y - 36.0; + assert!((above - text::line_height(size)).abs() < 0.05, "{size}pt: the top caption takes {above}pt"); + } + assert!((rooms[0] / rooms[1] - 4.0).abs() < 0.01, "24pt against 6pt: {rooms:?}"); +} + +/// A caption font that names only a size takes the rest, its weight, style and family, from +/// its field's font (XFA 3.3, "Formatting Text That Appears as Fixed or Variable Content", p. 43). +#[test] +fn a_caption_font_naming_only_a_size_takes_the_fields_weight_style_and_family() { + let items = positioned( + r#"Name:"#, + ); + let face = items.iter().find_map(|i| if let Item::Text(s) = i { Some(s.face.clone()) } else { None }).expect("the caption"); + assert_eq!((face.family, face.bold, face.italic, face.size), (crate::text::Family::Times, true, true, 12.0)); +} + /// A signature box the file already holds a signature for shows that signature, the file's own /// objects, and is locked; the other box stays unsigned. #[test]