diff --git a/crates/automation/src/tools.rs b/crates/automation/src/tools.rs index 4fff59c07d..259993233d 100644 --- a/crates/automation/src/tools.rs +++ b/crates/automation/src/tools.rs @@ -527,7 +527,7 @@ pub fn tools() -> Vec { t( "doc_print", "Print", - "Print with Acrobat's Print dialog options, or save the print-ready PDF. pages: a range such as \"1-3, 6, 9-\" (page labels allowed; default all); subset odd/even; reverse. layout: fit (default), actual, shrink, custom (scale %), multiple (per_sheet 2/4/6/9/16, order, border, auto_rotate; cut-stack order arranges single-sided sheets for cutting into piles and stacking left to right, top to bottom, keeping sheet order within each pile; duplex must be off), booklet (booklet_subset both/front/back, binding left/right), poster (scale %, overlap pt, cut_marks). orientation auto/portrait/landscape; comments_forms document / document-and-markups (default) / document-and-stamps / form-fields-only; paper Letter/Legal/Tabloid, ARCH A/B/C/D/E1/E, ANSI C/D/E, A0/A1/A2/A3/A4/A5/A6, or US #10 Envelope (short names or full preset labels); use layout actual for 100% in the print-ready PDF; printer drivers may still substitute paper or scale. Then path (save) or printer (a name or \"default\") with copies, collate, duplex off/long-edge/short-edge, grayscale, and options (driver options from printer_options, CUPS).", + "Print with Acrobat's Print dialog options, or save the print-ready PDF. pages: a range such as \"1-3, 6, 9-\" (page labels allowed; default all); subset odd/even (by page number, as Acrobat counts them: pages 2, 7-10 with even prints 2, 8 and 10, not every second page of the range); reverse. layout: fit (default), actual, shrink, custom (scale %), multiple (per_sheet 2/4/6/9/16, order, border, auto_rotate; cut-stack order arranges single-sided sheets for cutting into piles and stacking left to right, top to bottom, keeping sheet order within each pile; duplex must be off), booklet (booklet_subset both/front/back, binding left/right), poster (scale %, overlap pt, cut_marks). orientation auto/portrait/landscape; comments_forms document / document-and-markups (default) / document-and-stamps / form-fields-only; paper Letter/Legal/Tabloid, ARCH A/B/C/D/E1/E, ANSI C/D/E, A0/A1/A2/A3/A4/A5/A6, or US #10 Envelope (short names or full preset labels); use layout actual for 100% in the print-ready PDF; printer drivers may still substitute paper or scale. Then path (save) or printer (a name or \"default\") with copies, collate, duplex off/long-edge/short-edge, grayscale, and options (driver options from printer_options, CUPS).", ) .with(schema( json!({ diff --git a/crates/automation/tests/it/automation.rs b/crates/automation/tests/it/automation.rs index 778deaaec4..d652f77f3c 100644 --- a/crates/automation/tests/it/automation.rs +++ b/crates/automation/tests/it/automation.rs @@ -6422,7 +6422,9 @@ fn cut_stack_printing_through_tools() { &mut a, "doc_print", json!({ - "doc": doc, "pages": "2-10", "subset": "odd", "reverse": true, + // Even pages by page number (#3984): 2, 4, 6, 8 and 10 (counting places in the range, + // "even" would have been 3, 5, 7 and 9). + "doc": doc, "pages": "2-10", "subset": "even", "reverse": true, "layout": "multiple", "order": "cut-stack", "per_sheet": 2, "auto_rotate": false, "orientation": "landscape", "path": "range.pdf" }), diff --git a/crates/print/src/range.rs b/crates/print/src/range.rs index 075261945b..d03f31a3ca 100644 --- a/crates/print/src/range.rs +++ b/crates/print/src/range.rs @@ -45,8 +45,8 @@ fn hyphenated_label_range(part: &str, count: usize, labels: &[String]) -> Option } /// The pages to print (0-based, in print order). `range` is `None` for all pages; it may list -/// numbers and labels with `-` ranges (open-ended allowed: `5-`, `-3`). The subset counts the -/// selected pages (the first selected is "odd"), as Acrobat does. +/// numbers and labels with `-` ranges (open-ended allowed: `5-`, `-3`). The subset keeps the odd or +/// even pages of those chosen, by page number (see [`narrow`]). pub fn select_pages(count: usize, range: Option<&str>, labels: &[String], subset: Subset, reverse: bool) -> Result, PrintError> { let mut pages = Vec::new(); match range.map(str::trim).filter(|r| !r.is_empty()) { @@ -95,12 +95,17 @@ pub fn select_listed(count: usize, pages: &[usize], subset: Subset, reverse: boo narrow(pages.to_vec(), subset, reverse) } -/// Odd or even positions of the chosen pages, then the print order. +/// The odd or even pages of those chosen, by page number (the first page of the document is 1, +/// odd; `pages` are 0-based), then the print order. Acrobat counts the same way (#3984): "if you +/// set the range to 2, 7–10 and choose Even Pages Only, only pages 2, 8, and 10 print" (Adobe +/// Acrobat DC Help, last updated 11/28/2019, Options in the Print dialog box, p. 515; the same +/// example in Using Adobe Acrobat 9 Pro, p. 413). Counting places in the range instead printed +/// 7 and 9 there, and a range starting on an even page started its "even" pages on an odd one. fn narrow(pages: Vec, subset: Subset, reverse: bool) -> Result, PrintError> { let mut out: Vec = match subset { Subset::All => pages, - Subset::Odd => pages.into_iter().step_by(2).collect(), - Subset::Even => pages.into_iter().skip(1).step_by(2).collect(), + Subset::Odd => pages.into_iter().filter(|p| p % 2 == 0).collect(), + Subset::Even => pages.into_iter().filter(|p| p % 2 == 1).collect(), }; if reverse { out.reverse(); diff --git a/crates/print/src/tests.rs b/crates/print/src/tests.rs index fabe19a130..84ab248c78 100644 --- a/crates/print/src/tests.rs +++ b/crates/print/src/tests.rs @@ -71,8 +71,10 @@ fn page_selection() { assert_eq!(select_pages(1, None, &[], Subset::Even, false), Err(PrintError::NoPages)); // An explicit list (selected thumbnails): positions, never labels, in the order given. assert_eq!(select_listed(5, &[1, 3], Subset::All, false).unwrap(), [1, 3]); - assert_eq!(select_listed(5, &[0, 2, 4], Subset::Even, false).unwrap(), [2]); - assert_eq!(select_listed(5, &[0, 2, 4], Subset::Odd, true).unwrap(), [4, 0]); + // Picked pages keep their page numbers: pages 1, 3 and 5 are all odd. + assert_eq!(select_listed(5, &[0, 2, 4], Subset::Even, false), Err(PrintError::NoPages)); + assert_eq!(select_listed(5, &[0, 2, 4], Subset::Odd, true).unwrap(), [4, 2, 0]); + assert_eq!(select_listed(5, &[1, 2, 3], Subset::Even, false).unwrap(), [1, 3]); assert_eq!(select_listed(5, &[1, 5], Subset::All, false), Err(PrintError::OutOfRange(6, 5))); assert!(matches!(select_listed(0, &[usize::MAX], Subset::All, false), Err(PrintError::OutOfRange(_, 0)))); assert_eq!(select_listed(5, &[], Subset::All, false), Err(PrintError::NoPages)); @@ -940,3 +942,22 @@ fn text_direction_reads_on_past_a_refused_form() { text_direction(&doc, content, &res, Matrix::IDENTITY, 0, &mut score, &mut DecodeBudget::new(1 << 20, 0)); assert_eq!(score, 1); } + +/// #3984: odd and even are page numbers, as Acrobat counts them, not places in the range. +#[test] +fn odd_and_even_pages_are_page_numbers_not_places_in_the_range() { + let even = |range: &str| select_pages(12, Some(range), &[], Subset::Even, false).unwrap(); + let odd = |range: &str| select_pages(12, Some(range), &[], Subset::Odd, false).unwrap(); + // Adobe Acrobat DC Help (11/28/2019), Options in the Print dialog box, p. 515: "if you set the + // range to 2, 7–10 and choose Even Pages Only, only pages 2, 8, and 10 print". + assert_eq!(even("2, 7-10"), [1, 7, 9]); + // The report: 4–11 and 3–11 both print pages 4, 6, 8 and 10 as Even pages only. + assert_eq!(even("4-11"), [3, 5, 7, 9]); + assert_eq!(even("3-11"), [3, 5, 7, 9]); + assert_eq!(odd("4-11"), [4, 6, 8, 10]); + // Typed order is kept, and Reverse turns it round. + assert_eq!(even("10, 3, 4"), [9, 3]); + assert_eq!(select_pages(12, Some("10, 3, 4"), &[], Subset::Even, true).unwrap(), [3, 9]); + // A range with no page of the kind prints nothing. + assert_eq!(select_pages(12, Some("3, 5"), &[], Subset::Even, false), Err(PrintError::NoPages)); +} diff --git a/parity/acrobat-features.toml b/parity/acrobat-features.toml index 973e0cc697..fb1f2e0e2e 100644 --- a/parity/acrobat-features.toml +++ b/parity/acrobat-features.toml @@ -8013,8 +8013,8 @@ milestone = "M10" status = "shipped" commands = ["print.dialog"] tools = ["doc_print"] -evidence = ["crates/print/src/tests.rs::page_selection"] -notes = "" +evidence = ["crates/print/src/tests.rs::page_selection", "crates/print/src/tests.rs::odd_and_even_pages_are_page_numbers_not_places_in_the_range", "crates/automation/tests/it/automation.rs::cut_stack_printing_through_tools"] +notes = "Odd and even are page numbers, as Acrobat counts them (Adobe Acrobat DC Help, 11/28/2019, Options in the Print dialog box, p. 515: a range of 2, 7–10 with Even Pages Only prints pages 2, 8 and 10), for a typed range, picked thumbnails and the current page; Reverse turns the chosen pages round (#3984). Not yet: with page labels, odd and even still count page numbers (a document whose front matter is numbered i, ii, iii… keeps label 2 among the odd pages when it is page 5); the Acrobat help consulted doesn't say how Acrobat counts there, and the other Print-dialog behaviours #3984 mentions are open." [[feature]] id = "print.scaling"