From 5f757262f92007dd9484f010174ecf96b1cc9f2b Mon Sep 17 00:00:00 2001 From: mtlcl410 <2368091+mtlcl410@users.noreply.github.com> Date: Sat, 24 Oct 2026 16:49:25 +0800 Subject: [PATCH] M2: print previews don't apply the View auto state; doc_info layer_order end-to-end test A print preview (a request carrying the print tag, with or without the canvas's scale and grayscale bits) rendered with the document's on-screen settings, so a layer the View auto state turns off was hidden in the preview but printed. Printing is not the View event (ISO 32000-2 8.11.4.4), so the preview now leaves the auto state off like the print. Also add a tool-level test of doc_info's layer_order rows for a /Order with a group, a labelled nested array and an unlisted group (1-based layer index, name, label and depth). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC --- crates/automation/tests/it/automation.rs | 30 ++++++++++++++++++++++++ crates/render/src/raster.rs | 2 ++ crates/render/src/raster/tests.rs | 14 +++++++++++ parity/acrobat-features.toml | 2 +- 4 files changed, 47 insertions(+), 1 deletion(-) diff --git a/crates/automation/tests/it/automation.rs b/crates/automation/tests/it/automation.rs index c066a97a6e..8d7834c245 100644 --- a/crates/automation/tests/it/automation.rs +++ b/crates/automation/tests/it/automation.rs @@ -8186,6 +8186,36 @@ fn doc_info_describes_set_layer_links() { assert_eq!(info["layer_order"], json!([])); } +/// `doc_info`'s `layer_order` follows the default configuration's /Order (ISO 32000-2 Table 99): +/// a group by its 1-based position in `layers` and its name, a nested array one level deeper, +/// a label that starts one, and a group /Order does not list left out. +#[test] +fn doc_info_lists_the_layer_order_tree() { + let dir = workdir("layer-order"); + let pdf = pdf_of(&[ + "<< /Type /Catalog /Pages 2 0 R /OCProperties << /OCGs [4 0 R 5 0 R 6 0 R 7 0 R] /D << /Order [6 0 R [(Inks) 4 0 R [5 0 R]]] >> >> >>", + "<< /Type /Pages /Kids [3 0 R] /Count 1 >>", + "<< /Type /Page /Parent 2 0 R /MediaBox [0 0 200 200] >>", + "<< /Type /OCG /Name (Red) >>", + "<< /Type /OCG /Name (Green) >>", + "<< /Type /OCG /Name (Blue) >>", + "<< /Type /OCG /Name (Unlisted) >>", + ]); + std::fs::write(dir.join("order.pdf"), pdf).unwrap(); + let mut a = auto(&dir); + let doc = ok(&mut a, "doc_open", json!({ "path": "order.pdf" }))["doc"].as_u64().unwrap(); + let info = ok(&mut a, "doc_info", json!({ "doc": doc })); + assert_eq!( + info["layer_order"], + json!([ + { "depth": 0, "layer": 3, "name": "Blue" }, + { "depth": 0, "label": "Inks" }, + { "depth": 1, "layer": 1, "name": "Red" }, + { "depth": 2, "layer": 2, "name": "Green" }, + ]) + ); +} + mod close_argument_tests { use super::*; use std::sync::atomic::{AtomicU64, Ordering}; diff --git a/crates/render/src/raster.rs b/crates/render/src/raster.rs index 16bd1ad178..b4c31f50da 100644 --- a/crates/render/src/raster.rs +++ b/crates/render/src/raster.rs @@ -440,6 +440,8 @@ fn render_page<'a>( // Previews render at low detail (tiny images are skipped); finals always draw all. let mut preview_settings = settings.clone(); preview_settings.preview = req.preview; + // A print preview shows what prints, and printing is not the View event. + preview_settings.view_auto_state &= req.tag & PRINT_TAG == 0; render_into(page, cache, &preview_settings, &rs, pixels.bytes_mut()); Ok((w.into(), h.into(), pixels, None)) })); diff --git a/crates/render/src/raster/tests.rs b/crates/render/src/raster/tests.rs index a82d60138e..c9ecd5e292 100644 --- a/crates/render/src/raster/tests.rs +++ b/crates/render/src/raster/tests.rs @@ -2370,6 +2370,20 @@ fn layer_toggles_and_print_renders_are_not_the_view_auto_state() { assert!(!auto_state_red(pdf, RenderConfig::default()), "on screen: hidden"); } +/// A print preview ([`PRINT_TAG`], with or without the canvas's scale and grayscale bits) +/// shows what prints, so the View auto state is not applied to it either. +#[test] +fn print_previews_are_not_the_view_auto_state() { + let pdf = Arc::new(auto_state_pdf(VIEW_OFF, &format!("<< {AS_VIEW} >>"), "")); + let mut r = PageRenderer::new(pdf, RenderConfig::default()); + for tag in [PRINT_TAG, PRINT_TAG | 1 << 59 | 7] { + let p = r.render(RenderRequest { page: 0, kind: RequestKind::Pixels, tile: None, scale: 0.5, tag, ..Default::default() }); + assert_eq!(p.rgba.get(..4), Some(&[255, 0, 0, 255][..]), "tag {tag:#x}: printed state"); + } + let p = r.render(RenderRequest { page: 0, kind: RequestKind::Pixels, tile: None, scale: 0.5, tag: 7, ..Default::default() }); + assert_ne!(p.rgba.get(..4), Some(&[255, 0, 0, 255][..]), "on screen: hidden"); +} + /// Malformed auto state is ignored without a panic, and the walk is bounded. #[test] fn malformed_view_auto_state_is_ignored() { diff --git a/parity/acrobat-features.toml b/parity/acrobat-features.toml index 67f133765f..c79ea9f515 100644 --- a/parity/acrobat-features.toml +++ b/parity/acrobat-features.toml @@ -1335,7 +1335,7 @@ status = "shipped" commands = [] tools = ["doc_info", "layer_set"] evidence = ["crates/render/src/raster/tests.rs::layer_override_hides_content", "crates/engine/src/tests.rs::layer_choices_survive_edits", "crates/automation/tests/it/automation.rs::layers_and_hidden_comments_change_what_page_render_draws", "crates/render/src/raster/tests.rs::the_view_auto_state_sets_a_groups_state_on_screen", "crates/render/src/raster/tests.rs::layer_toggles_and_print_renders_are_not_the_view_auto_state", "crates/render/src/raster/tests.rs::malformed_view_auto_state_is_ignored", "crates/render/src/inspect/tests.rs::the_layers_panel_presents_the_order_tree", "crates/ui-egui/tests/it/layer_actions.rs::the_layers_panel_shows_the_order_tree"] -notes = "layer_set shows or hides a layer by name (every group with that name, as CAD exporters repeat names) or by position, and page_render draws with the document's layer visibility. Still missing: Reset to initial visibility (view.layers-reset), layer properties, and /OC on annotations (#2176). The default configuration's auto state for the View event (/AS, ISO 32000-2 8.11.4.4) sets the groups it manages from their /Usage /View /ViewState as the document opens, on screen and in the panel, and toggles still override it; renders for printing don't apply it. Not yet: the /Zoom, /User and /Language categories, and the Print event's auto state when printing. The panel presents the default configuration's /Order (ISO 32000-2 Table 99) as a tree: a nested array one level deeper, a leading text string as a label that can't be toggled. Groups /Order leaves out aren't listed but still draw in their state, and a document without /Order lists none, the default Table 99 gives; doc_info reports the rows as layer_order. Not yet: /ListMode /VisiblePages." +notes = "layer_set shows or hides a layer by name (every group with that name, as CAD exporters repeat names) or by position, and page_render draws with the document's layer visibility. Still missing: Reset to initial visibility (view.layers-reset), layer properties, and /OC on annotations (#2176). The default configuration's auto state for the View event (/AS, ISO 32000-2 8.11.4.4) sets the groups it manages from their /Usage /View /ViewState as the document opens, on screen and in the panel, and toggles still override it; renders for printing and print previews don't apply it. Not yet: the /Zoom, /User and /Language categories, and the Print event's auto state when printing. The panel presents the default configuration's /Order (ISO 32000-2 Table 99) as a tree: a nested array one level deeper, a leading text string as a label that can't be toggled. Groups /Order leaves out aren't listed but still draw in their state, and a document without /Order lists none, the default Table 99 gives; doc_info reports the rows as layer_order. Not yet: /ListMode /VisiblePages." [[feature]] id = "view.layers-reset"