Ungroup keeps the translucency an unmatched Q doesn't restore

A Q with no q before it restores nothing; the renderer ignores it. The check for translucency at
the Do took it as restoring the opaque default, so a transparency group drawn after /H gs Q was
inlined although it is drawn translucent.
This commit is contained in:
bflatastic committed 2026-11-08 22:31:14 +07:00
1 parent 7169b0d6ad
commit 233bc6c932
2 files changed
+4 -1

No files matched your search

+2
View File
@@ -5041,6 +5041,8 @@ fn ungroup_refuses_what_would_draw_differently() {
ungroup(&[("Group", group(&[]))], fill, "/H gs /One gs", half()).unwrap();
// The translucency ends with its q … Q scope.
ungroup(&[("Group", group(&[]))], fill, "q /H gs Q", half()).unwrap();
// A Q with no q to restore is ignored, as the renderer ignores it: the translucency stays.
refused(ungroup(&[("Group", group(&[]))], fill, "/H gs Q", half()), "translucent");
// Without a group, translucency at the Do applies to each part just as it would inline.
ungroup(&[], fill, "/H gs", half()).unwrap();
ungroup(&[("Group", group(&[]))], fill, "", None).unwrap();
+2 -1
View File
@@ -691,7 +691,8 @@ pub(crate) fn translucent_at(doc: &Document, resources: &Dict, ops: &[Op], at: u
for op in ops.iter().take(at) {
match op.op.as_slice() {
b"q" => stack.push(now),
b"Q" => now = stack.pop().unwrap_or([false; 4]),
// A Q with nothing to restore is ignored, as renderers ignore it.
b"Q" => now = stack.pop().unwrap_or(now),
b"gs" => {
let Ok(Some((_, i))) = resource_operand(op) else { continue };
let Some(gs) = op.name(i).and_then(|n| states.get(n)).map(|g| doc.resolve(g)).and_then(|g| g.as_dict().cloned()) else {