Compare commits

...

1 Commits

Author SHA1 Message Date
Brandon Thomas 01f4937dac Layering: the render-based rotated-field test moves from forms to engine
forms (L3) gained a dev-dependency on render (L3) with #516, which
`xtask layers` refuses, so main CI failed. The one test that renders a
rotated field now lives in engine's tests, which may depend on both;
the parity evidence points there.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 14:08:46 -04:00
5 changed files with 49 additions and 36 deletions

1
Cargo.lock generated
View File

@ -3642,7 +3642,6 @@ dependencies = [
"pdfcraft-cos", "pdfcraft-cos",
"pdfcraft-fonts", "pdfcraft-fonts",
"pdfcraft-model", "pdfcraft-model",
"pdfcraft-render",
"thiserror 2.0.21", "thiserror 2.0.21",
] ]

View File

@ -2205,3 +2205,51 @@ fn comments_without_appearances_are_drawn_but_not_saved() {
assert!(reopened.get(r).as_dict().is_some_and(|d| !d.contains(b"AP")), "{r:?} is saved without /AP"); assert!(reopened.get(r).as_dict().is_some_and(|d| !d.contains(b"AP")), "{r:?} is saved without /AP");
} }
} }
/// Forms (L3) may not depend on render (L3), so this check of what a rotated field's appearance
/// draws lives here, where both are available.
#[test]
fn a_rotated_form_field_draws_along_the_vertical_edge() {
use pdfcraft_cos::{Document, Object, SaveOptions, write_incremental};
use pdfcraft_forms::{FieldProps, FieldValue, NewField, add_field, set_props, set_value};
use pdfcraft_render::{PageRenderer, RenderConfig, RenderRequest, RequestKind};
let mut doc = Document::new_empty();
let pages = doc.get(doc.root().unwrap()).as_dict().unwrap().reference(b"Pages").unwrap();
let mut p = pdfcraft_cos::Dict::new();
p.set(b"Type".to_vec(), Object::name("Page"));
p.set(b"Parent".to_vec(), Object::Ref(pages));
p.set(b"MediaBox".to_vec(), Object::Array(vec![0.into(), 0.into(), 600.into(), 800.into()]));
let r = doc.add(p);
doc.update_dict(pages, |d| {
d.set(b"Kids".to_vec(), Object::Array(vec![Object::Ref(r)]));
d.set(b"Count".to_vec(), Object::Int(1));
})
.unwrap();
add_field(&mut doc, 0, [10.0, 40.0, 90.0, 60.0], &NewField::Text { multiline: false }, Some("wide")).unwrap();
set_value(&mut doc, "wide", &FieldValue::Text("MMMMMM".into())).unwrap();
set_props(&mut doc, "wide", &FieldProps { font_size: Some(12.0), ..FieldProps::default() }).unwrap();
let span = |doc: &Document| -> (u32, u32) {
let bytes = write_incremental(doc, &SaveOptions::default()).unwrap();
let mut r = PageRenderer::new(Arc::new(bytes), RenderConfig::default());
let p = r.render(RenderRequest { page: 0, kind: RequestKind::Pixels, tile: None, scale: 2.0, tag: 0 });
assert!(p.error.is_none(), "{:?}", p.error);
let (mut x0, mut y0, mut x1, mut y1) = (u32::MAX, u32::MAX, 0, 0);
let mut ink = false;
for y in 0..p.height {
for x in 0..p.width {
let i = ((y * p.width + x) * 4) as usize;
if p.rgba[i] < 200 {
ink = true;
(x0, y0, x1, y1) = (x0.min(x), y0.min(y), x1.max(x), y1.max(y));
}
}
}
assert!(ink, "the field drew no text");
(x1 - x0, y1 - y0)
};
let (wide, tall) = span(&doc);
assert!(wide > tall, "upright text is a horizontal run: {wide}x{tall}");
set_props(&mut doc, "wide", &FieldProps { rotation: Some((0, 90)), ..FieldProps::default() }).unwrap();
let (wide, tall) = span(&doc);
assert!(tall > wide, "rotated text is a vertical run: {wide}x{tall}");
}

View File

@ -17,4 +17,3 @@ thiserror = { workspace = true }
[dev-dependencies] [dev-dependencies]
hayro-syntax = { workspace = true } hayro-syntax = { workspace = true }
pdfcraft-render = { workspace = true }

View File

@ -1062,36 +1062,3 @@ fn a_rotation_refused_as_too_small_changes_nothing_else() {
assert_eq!(f.tooltip, None, "the tooltip was written before the rotation was refused"); assert_eq!(f.tooltip, None, "the tooltip was written before the rotation was refused");
assert_eq!(f.widgets[0].rotation, 0); assert_eq!(f.widgets[0].rotation, 0);
} }
#[test]
fn a_rotated_field_draws_along_the_vertical_edge() {
use pdfcraft_render::{PageRenderer, RenderConfig, RenderRequest, RequestKind};
let mut doc = one_page();
add_field(&mut doc, 0, [10.0, 40.0, 90.0, 60.0], &NewField::Text { multiline: false }, Some("wide")).unwrap();
set_value(&mut doc, "wide", &FieldValue::Text("MMMMMM".into())).unwrap();
set_props(&mut doc, "wide", &FieldProps { font_size: Some(12.0), ..FieldProps::default() }).unwrap();
let span = |doc: &Document| -> (u32, u32) {
let bytes = write_incremental(doc, &SaveOptions::default()).unwrap();
let mut r = PageRenderer::new(Arc::new(bytes), RenderConfig::default());
let p = r.render(RenderRequest { page: 0, kind: RequestKind::Pixels, tile: None, scale: 2.0, tag: 0 });
assert!(p.error.is_none(), "{:?}", p.error);
let (mut x0, mut y0, mut x1, mut y1) = (u32::MAX, u32::MAX, 0, 0);
let mut ink = false;
for y in 0..p.height {
for x in 0..p.width {
let i = ((y * p.width + x) * 4) as usize;
if p.rgba[i] < 200 {
ink = true;
(x0, y0, x1, y1) = (x0.min(x), y0.min(y), x1.max(x), y1.max(y));
}
}
}
assert!(ink, "the field drew no text");
(x1 - x0, y1 - y0)
};
let (wide, tall) = span(&doc);
assert!(wide > tall, "upright text is a horizontal run: {wide}x{tall}");
set_props(&mut doc, "wide", &FieldProps { rotation: Some((0, 90)), ..FieldProps::default() }).unwrap();
let (wide, tall) = span(&doc);
assert!(tall > wide, "rotated text is a vertical run: {wide}x{tall}");
}

View File

@ -4398,7 +4398,7 @@ milestone = "M6"
status = "partial" status = "partial"
commands = ["form.fields"] commands = ["form.fields"]
tools = ["form_fill", "form_set_props"] tools = ["form_fill", "form_set_props"]
evidence = ["crates/forms/src/tests.rs::text_fields_get_new_appearances", "crates/forms/src/tests.rs::choices_accept_exports_or_display_text", "crates/forms/src/tests.rs::rotated_fields_draw_in_their_quadrant", "crates/forms/src/tests.rs::a_rotated_field_draws_along_the_vertical_edge", "crates/automation/tests/automation.rs::rotating_a_field_through_tools", "crates/ui-egui/tests/prepare.rs::position_tab_rotates_a_field"] evidence = ["crates/forms/src/tests.rs::text_fields_get_new_appearances", "crates/forms/src/tests.rs::choices_accept_exports_or_display_text", "crates/forms/src/tests.rs::rotated_fields_draw_in_their_quadrant", "crates/engine/src/tests.rs::a_rotated_form_field_draws_along_the_vertical_edge", "crates/automation/tests/automation.rs::rotating_a_field_through_tools", "crates/ui-egui/tests/prepare.rs::position_tab_rotates_a_field"]
notes = "auto-size, comb, multiline, password, quadding, /MK colours and /MK /R rotation (0, 90, 180, 270); approximate Helvetica metrics" notes = "auto-size, comb, multiline, password, quadding, /MK colours and /MK /R rotation (0, 90, 180, 270); approximate Helvetica metrics"
[[feature]] [[feature]]