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