fix(render): key soft masks by inherited context (#716)

Co-authored-by: Brandon Thomas <[email protected]>
This commit is contained in:
cyfung1031andBrandon Thomas authored and GitHub committed 2026-10-10 06:11:45 -04:00
1 parent 72b3b6171a
commit a211e334a0
2 files changed
+68 -3

No files matched your search

+41
View File
@@ -1986,6 +1986,47 @@ trailer << /Root 1 0 R >>
assert_ne!(second_pixel, [255, 255, 255, 255]);
}
#[test]
fn shared_soft_mask_uses_each_inherited_resource_context() {
let page_body = "/A Do /B Do";
let form_a = "/GS gs 1 0 0 rg 0 0 40 40 re f";
let form_b = "/GS gs 0 0 1 rg 60 0 40 40 re f";
let mask_body = "/FILL Do";
let white = "1 g 0 0 100 100 re f";
let black = "0 g 0 0 100 100 re f";
let pdf = format!(
"%PDF-1.7\n\
1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj\n\
2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 /MediaBox [0 0 100 100] >> endobj\n\
3 0 obj << /Type /Page /Parent 2 0 R /Resources << /XObject << /A 4 0 R /B 5 0 R >> >> /Contents 6 0 R >> endobj\n\
4 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 100 100] /Resources << /ExtGState << /GS 8 0 R >> /XObject << /FILL 9 0 R >> >> /Length {} >> stream\n{form_a}\nendstream endobj\n\
5 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 100 100] /Resources << /ExtGState << /GS 8 0 R >> /XObject << /FILL 10 0 R >> >> /Length {} >> stream\n{form_b}\nendstream endobj\n\
6 0 obj << /Length {} >> stream\n{page_body}\nendstream endobj\n\
8 0 obj << /Type /ExtGState /SMask 11 0 R >> endobj\n\
9 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 100 100] /Length {} >> stream\n{white}\nendstream endobj\n\
10 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 100 100] /Length {} >> stream\n{black}\nendstream endobj\n\
11 0 obj << /Type /Mask /S /Luminosity /G 12 0 R >> endobj\n\
12 0 obj << /Type /XObject /Subtype /Form /BBox [0 0 100 100] /Group << /S /Transparency /CS /DeviceGray >> /Length {} >> stream\n{mask_body}\nendstream endobj\n\
trailer << /Root 1 0 R >>\n%%EOF",
form_a.len(),
form_b.len(),
page_body.len(),
white.len(),
black.len(),
mask_body.len()
)
.into_bytes();
let mut renderer = PageRenderer::new(Arc::new(pdf), RenderConfig::default());
let page = renderer.render(RenderRequest { page: 0, scale: 1.0, ..Default::default() });
assert!(page.error.is_none(), "{:?}", page.error);
let pixel = |x: u32, y: u32| {
let offset = ((y * page.width + x) * 4) as usize;
[page.rgba[offset], page.rgba[offset + 1], page.rgba[offset + 2], page.rgba[offset + 3]]
};
assert_eq!(pixel(20, 80), [255, 0, 0, 255], "the white inherited mask makes form A visible");
assert_eq!(pixel(80, 80), [255, 255, 255, 255], "the black inherited mask must not reuse form A's cached pixels");
}
#[test]
fn renders_a_blue_rectangle() {
let pool = RenderPool::new(Arc::new(ONE_PAGE.to_vec()), 1, RenderConfig::default());