M5: unify annotation flag parsing (#698)

This commit is contained in:
cyfung1031 2026-10-10 19:04:03 +09:00 committed by GitHub
parent 0695fd6f16
commit e2b71e3e82
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 22 additions and 4 deletions

View File

@ -741,6 +741,10 @@ pub fn is_fill_sign(doc: &Document, d: &Dict) -> bool {
subtype == b"Ink" && text_value(doc, d, b"Subj").as_deref() == Some("Signature")
}
fn annotation_flags(doc: &Document, d: &Dict) -> i64 {
d.get(b"F").and_then(|f| doc.resolve(f).as_int()).unwrap_or(0)
}
/// Whether any page has a Fill & Sign annotation that flatten would bake in (not hidden).
pub fn has_visible_fill_sign(doc: &Document) -> bool {
let Ok(pages) = page_refs(doc) else { return false };
@ -748,7 +752,7 @@ pub fn has_visible_fill_sign(doc: &Document) -> bool {
for entry in annots(doc, page) {
let obj = doc.resolve(&entry);
let Some(d) = obj.as_dict() else { continue };
let flags = d.get(b"F").and_then(|f| doc.resolve(f).as_int()).unwrap_or(0);
let flags = annotation_flags(doc, d);
if flags & (FLAG_HIDDEN | FLAG_NO_VIEW) != 0 {
continue;
}
@ -1504,7 +1508,7 @@ fn reply(
}
fn flags(doc: &Document, r: ObjRef) -> i64 {
doc.get(r).as_dict().and_then(|d| d.get(b"F").and_then(|f| doc.resolve(f).as_f64())).unwrap_or(0.0) as i64
doc.get(r).as_dict().map(|d| annotation_flags(doc, d)).unwrap_or(0)
}
/// Refuse to change a locked comment (Acrobat: Properties ▸ Locked).
@ -1848,7 +1852,7 @@ pub fn summaries(doc: &Document) -> Vec<Summary> {
color,
state: text_value(doc, d, b"State"),
quads,
locked: d.get(b"F").and_then(|f| doc.resolve(f).as_int()).unwrap_or(0) & FLAG_LOCKED != 0,
locked: annotation_flags(doc, d) & FLAG_LOCKED != 0,
intent: d.get(b"IT").and_then(|o| doc.resolve(o).as_name().map(|n| String::from_utf8_lossy(n).into_owned())),
});
}
@ -1934,7 +1938,7 @@ pub fn props(doc: &Document, page: usize, index: usize) -> Option<Props> {
icon: (subtype == "Text").then(|| d.name(b"Name").and_then(|n| NoteIcon::from_name(&String::from_utf8_lossy(n))).unwrap_or(NoteIcon::Note)),
modified: text_value(doc, d, b"M"),
restylable: appearance::build(d).is_some(),
locked: d.get(b"F").and_then(|f| doc.resolve(f).as_int()).unwrap_or(0) & FLAG_LOCKED != 0,
locked: annotation_flags(doc, d) & FLAG_LOCKED != 0,
subtype,
endings: line_endings_of(d),
})

View File

@ -374,6 +374,20 @@ fn editing_a_callout_refits_the_box_and_keeps_the_leader() {
assert_eq!(ap_content(&doc, d).matches(" Tj").count(), appearance::wrap(long, 12.0, 200.0 - 2.0 * 4.0).len(), "nothing is clipped");
}
#[test]
fn real_annotation_flags_do_not_lock_comments() {
let mut doc = fixture();
let page = page_refs(&doc).unwrap()[0];
let mut entries = annots(&doc, page);
let Object::Dict(annotation) = &mut entries[0] else { panic!("fixture annotation is inline") };
annotation.set(b"F".to_vec(), Object::Real(128.5));
set_annots(&mut doc, page, entries).unwrap();
assert!(!summaries(&doc)[0].locked, "a non-integer /F is outside the annotation flag domain");
assert!(!props(&doc, 0, 0).unwrap().locked);
assert!(set_info(&mut doc, 0, 0, Some("Ada"), None, None, &meta("")).is_ok());
}
#[test]
fn a_locked_text_box_still_refits_its_text() {
let mut doc = fixture();