M2: two Indexed resources are cached apart, and a stroke colour in a recovered Indexed space is reported (ISO 32000-2 8.6.6.3)

Mutation pass on patch (60):
- keying the resource colour-space cache with one key for every space
  survived the earlier tests, which used one Indexed resource a page:
  raster::tests::indexed_lookup_cache::two_indexed_resources_are_cached_apart
  kills it;
- the ColorFallback report for a recovered space set with CS had no
  test (only cs was tested): a stroke case in
  a_fill_or_stroke_colour_in_a_short_table_is_padded_and_reported fails
  with that report removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCfwzyRXj4VfQAVVdv
This commit is contained in:
mtlcl410andClaude Opus 5.5 committed 2026-11-02 02:08:46 +08:00
1 parent 3275f853c3
commit 6179cf795d
2 files changed
+18 -2

No files matched your search

@@ -61,3 +61,15 @@ fn inline_images_naming_one_indexed_resource_read_its_lookup_once() {
let short = page(20, 7, b"\xFF\x00\x00\x00\xFF\x00"); let short = page(20, 7, b"\xFF\x00\x00\x00\xFF\x00");
assert_eq!(lookup_reads(short), [1, 1], "a short table: read once, then cached"); assert_eq!(lookup_reads(short), [1, 1], "a short table: read once, then cached");
} }
/// Two Indexed resources whose arrays differ (`/P` names object 5, `/Q` object 6) are two
/// spaces: each is built, and its table read, once, and neither stands in for the other.
#[test]
fn two_indexed_resources_are_cached_apart() {
let image = |name: &str| format!("q 20 0 0 20 0 0 cm BI /W 2 /H 1 /BPC 8 /CS /{name} /F /AHx ID 0001> EI Q");
let content = [image("P"), image("Q"), image("P"), image("Q")].join("\n");
let resources = "<< /ColorSpace << /P [/Indexed /DeviceRGB 1 5 0 R] /Q [/Indexed /DeviceRGB 1 6 0 R] >> >>";
let (red_green, blue_white): (&[u8], &[u8]) = (b"\xFF\x00\x00\x00\xFF\x00", b"\x00\x00\xFF\xFF\xFF\xFF");
let pdf = image_cache_pdf(&content, resources, &[("<< /Length 6 >>", red_green), ("<< /Length 6 >>", blue_white)]);
assert_eq!(lookup_reads(pdf), [2, 2], "each table read once");
}
+6 -2
View File
@@ -299,10 +299,10 @@ fn an_unreadable_base_keeps_its_fallback() {
} }
} }
/// A fill colour set in such a space (`cs`, `sc`) draws through the same recovered table, and /// A fill or stroke colour set in such a space (`cs`, `sc`, `CS`, `SC`) draws through the same recovered table, and
/// the recovery is reported as `ColourFallback`, as the upstream DeviceGray fallback was. /// the recovery is reported as `ColourFallback`, as the upstream DeviceGray fallback was.
#[test] #[test]
fn a_fill_colour_in_a_short_table_is_padded_and_reported() { fn a_fill_or_stroke_colour_in_a_short_table_is_padded_and_reported() {
let fill = |index: u8| format!("/P cs {index} sc 0 0 200 200 re f"); let fill = |index: u8| format!("/P cs {index} sc 0 0 200 200 re f");
let short = format!("[/Indexed /DeviceRGB 7 <{}>]", entries(2)); let short = format!("[/Indexed /DeviceRGB 7 <{}>]", entries(2));
let page = render(pdf(&short, &fill(1), &[])); let page = render(pdf(&short, &fill(1), &[]));
@@ -310,6 +310,10 @@ fn a_fill_colour_in_a_short_table_is_padded_and_reported() {
assert_eq!(page.warnings, vec![RenderWarning::ColourFallback]); assert_eq!(page.warnings, vec![RenderWarning::ColourFallback]);
let page = render(pdf(&short, &fill(5), &[])); let page = render(pdf(&short, &fill(5), &[]));
assert_eq!(columns(&page)[0], BLACK, "entry 5 is padding"); assert_eq!(columns(&page)[0], BLACK, "entry 5 is padding");
// A stroke colour (`CS`, `SC`) the same way.
let page = render(pdf(&short, "/P CS 1 SC 20 w 0 100 m 200 100 l S", &[]));
assert_eq!(columns(&page)[0], COLOURS[1], "the stroke is green");
assert_eq!(page.warnings, vec![RenderWarning::ColourFallback]);
let page = render(pdf(&format!("[/Indexed /DeviceRGB 7 <{TABLE}>]"), &fill(1), &[])); let page = render(pdf(&format!("[/Indexed /DeviceRGB 7 <{TABLE}>]"), &fill(1), &[]));
assert_eq!(columns(&page)[0], COLOURS[1]); assert_eq!(columns(&page)[0], COLOURS[1]);
assert!(page.warnings.is_empty(), "{:?}", page.warnings); assert!(page.warnings.is_empty(), "{:?}", page.warnings);