From 251917f685a8f252548620fe619ebc0c85b7f162 Mon Sep 17 00:00:00 2001 From: Marco Arnulfo <103679419+marcoarnulfo@users.noreply.github.com> Date: Tue, 13 Oct 2026 06:47:16 +0200 Subject: [PATCH] fix(ui): the accessibility check keeps a saved page range inside the document (#1300) (#1437) With the options dialog turned off, run_accessibility_check used the range saved on an earlier, longer document as it was: a page past the end selected no page, and the page rules came out Passed without looking at anything. The range is now clamped to the active document's pages, as the dialog already does. a_saved_page_range_past_the_document_still_checks_its_pages fails before the change with Passed for Tagged content. --- crates/ui-egui/src/a11y_ui.rs | 6 +++++- crates/ui-egui/tests/accessibility.rs | 20 ++++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/crates/ui-egui/src/a11y_ui.rs b/crates/ui-egui/src/a11y_ui.rs index 70d14d0d..67683beb 100644 --- a/crates/ui-egui/src/a11y_ui.rs +++ b/crates/ui-egui/src/a11y_ui.rs @@ -357,7 +357,11 @@ impl PdfCraftApp { let Some((_, id)) = self.active_ids() else { return }; let Some(doc) = self.session.get(id) else { return }; let o = &self.a11y_options; - let options = Options { rules: o.rules.clone(), pages: (!o.all_pages).then(|| (o.from.max(1) - 1..o.to.max(o.from)).collect()) }; + // The range was picked on whatever document had the options dialog last; with the dialog + // turned off it reaches here unchecked, and a page past the end would select nothing. + let to = o.to.clamp(1, doc.info.pages.len().max(1)); + let from = o.from.clamp(1, to); + let options = Options { rules: o.rules.clone(), pages: (!o.all_pages).then(|| (from - 1..to).collect()) }; let Some(report) = doc.accessibility_check(&options) else { self.notify_tr("This document can't be checked: it couldn't be read for editing"); return; diff --git a/crates/ui-egui/tests/accessibility.rs b/crates/ui-egui/tests/accessibility.rs index b050dd07..d4ea6a60 100644 --- a/crates/ui-egui/tests/accessibility.rs +++ b/crates/ui-egui/tests/accessibility.rs @@ -171,6 +171,26 @@ fn checker_summary_does_not_hide_manual_review() { h.get_by_label("No issues found"); } +#[test] +fn a_saved_page_range_past_the_document_still_checks_its_pages() { + // A range picked on a longer document survives into this one-page document when the options + // dialog is turned off. Unclamped, it selected no page, and the page rules came out Passed + // without having looked at the untagged text (#1300). + let mut h = Harness::builder().with_size(egui::vec2(1400.0, 900.0)).build_eframe(move |_cc| { + let mut app = PdfCraftApp::new(); + app.set_option("language", "en").unwrap(); + app.open_bytes("notes.pdf", None, FIXTURE.to_vec()).unwrap(); + app + }); + h.run_steps(3); + let o = &mut h.state_mut().a11y_options; + (o.show_dialog, o.all_pages, o.from, o.to) = (false, false, 2, 2); + assert!(h.state_mut().execute("a11y.check")); + h.run_steps(2); + assert_eq!(status(&h, Rule::TaggedContent), Status::Failed); + assert_eq!(h.state().a11y.options.as_ref().and_then(|o| o.pages.clone()), Some(vec![0])); +} + /// Two tagged figures: an image without alternate text and a bar (role-mapped Photo) with. const FIGURES: &[u8] = b"%PDF-1.7 1 0 obj << /Type /Catalog /Pages 2 0 R /MarkInfo << /Marked true >> /StructTreeRoot 5 0 R >> endobj