fix(organize): normalize rotations before adding so large quarter turns cannot overflow (#1512)

* Contributors: credit webdevtodayjason as Jason Brashear

* fix(organize): normalize rotations before adding so large quarter turns cannot overflow
This commit is contained in:
Jason Brashear authored and GitHub committed 2026-10-13 00:05:50 -04:00
1 parent 801a2f1488
commit a9745dd22d
3 files changed
+19 -2

No files matched your search

+3
View File
@@ -126,3 +126,6 @@ sync_github_name = true
real_name = "Jeremy Yao"
display_name = "Jeremy Yao"
sync_github_name = false
[people.webdevtodayjason]
display_name = "Jason Brashear"
+2 -2
View File
@@ -158,11 +158,11 @@ pub fn rotate_pages(doc: &mut Document, indices: &[usize], degrees: i64) -> Resu
}
let all = walk(doc)?;
check(indices, all.len())?;
let delta = (degrees / 90) * 90;
let delta = degrees.rem_euclid(360);
for &i in indices {
let (page, inherited) = &all[i];
let current = doc.get(*page).as_dict().and_then(|d| d.int(b"Rotate")).or_else(|| inherited.int(b"Rotate")).unwrap_or(0);
let new = (current + delta).rem_euclid(360);
let new = (current.rem_euclid(360) + delta).rem_euclid(360);
doc.update_dict(*page, |d| d.set(b"Rotate".to_vec(), Object::Int(new)))?;
}
Ok(())
+14
View File
@@ -28,6 +28,20 @@ fn rotate_rejects_angles_that_are_not_multiples_of_90() {
assert_eq!(page_rotation(&doc, 0).unwrap(), 0);
}
#[test]
fn rotate_handles_large_quarter_turns() {
let large = i64::MAX - i64::MAX % 90;
for (current, degrees, expected) in [(90, large, 90), (-90, -large, 270), (large, 90, 90), (-large, -90, 270), (180, large - 90, 90)] {
for inherited in [false, true] {
let mut doc = open(fixture());
let target = if inherited { pages_root(&doc).unwrap() } else { pages(&doc).unwrap()[0].obj };
doc.update_dict(target, |d| d.set(b"Rotate".to_vec(), Object::Int(current))).unwrap();
rotate_pages(&mut doc, &[0], degrees).unwrap();
assert_eq!(page_rotation(&doc, 0).unwrap(), expected);
}
}
}
/// A 3-page document with a nested page tree. MediaBox and Rotate are inherited from the root,
/// Resources from an intermediate node; each page's content says which page it is.
fn fixture() -> Vec<u8> {