mirror of
https://github.com/storytold/pdfcraft.git
synced 2026-11-12 00:46:57 -06:00
M2: the soft-mask tests count image and mask decodes apart and check a truncated mask's size
decoded_images_serve_every_size_they_are_drawn_at asserts image and mask decodes separately, through a new InterpreterCache::decoded_mask_decodes (hayro-interpret patch 82), so a wrong split behind the same total fails. The truncated-stream case of an_averaged_down_soft_mask_follows_its_samples_and_its_drawn_size asserts the exact mask handed over: 32 x 10 (the decoded rows), all opaque. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
327fddec5b
commit
30164b6973
@@ -8187,13 +8187,14 @@ fn decoded_images_serve_every_size_they_are_drawn_at() {
|
||||
let mut device = Draws::default();
|
||||
interpret_page(page, &mut ctx, &mut device);
|
||||
assert_eq!(device.0, 5, "every draw of /{name} was handed its pixels");
|
||||
cache.decoded_image_decodes()
|
||||
// (image decodes, mask decodes)
|
||||
let masks = cache.decoded_mask_decodes();
|
||||
(cache.decoded_image_decodes() - masks, masks)
|
||||
};
|
||||
assert_eq!(decodes("A"), 1, "a Flate image decodes the same at every size");
|
||||
// The image and its JPX soft mask each decode once for each of the five sizes: the mask goes
|
||||
// through the cache too since hayro-interpret patch 82, so its decodes are counted with the
|
||||
// image's.
|
||||
assert_eq!(decodes("B"), 10, "a JPX soft mask decodes for the size it is drawn at");
|
||||
assert_eq!(decodes("A"), (1, 0), "a Flate image decodes the same at every size");
|
||||
// The image and its JPX soft mask each decode once for each of the five sizes (the mask goes
|
||||
// through the cache too since hayro-interpret patch 82).
|
||||
assert_eq!(decodes("B"), (5, 5), "an image with a JPX soft mask, and the mask, decode for the size they are drawn at");
|
||||
}
|
||||
|
||||
/// A soft mask far larger than where its image is drawn is averaged down to that size and cached
|
||||
@@ -8356,7 +8357,8 @@ fn an_averaged_down_soft_mask_follows_its_samples_and_its_drawn_size() {
|
||||
let (handed, _) = soft_masks_handed(7, 1, &[0, 0, 0, 255, 0, 0, 0], &[(3, 1)]);
|
||||
assert_eq!(handed, vec![(4, 1, vec![0, 0, 127, 0])], "centres, not left edges");
|
||||
let (handed, _) = soft_masks_handed(100, 100, &[255; 100 * 10], &[(20, 20)]);
|
||||
assert!(!handed.is_empty() && handed.iter().all(|(_, _, data)| data.iter().all(|&a| a == 255)), "no uncovered rows: {handed:?}");
|
||||
// 32 wide (20 rounded up to a power of two), and 10 rows, the ones decoded, not 32: all opaque.
|
||||
assert_eq!(handed, vec![(32, 10, vec![255; 32 * 10])], "no uncovered rows");
|
||||
let sizes = |draws: &[(u32, u32)]| -> Vec<(u32, u32)> {
|
||||
soft_masks_handed(100, 100, &[255; 100 * 100], draws).0.iter().map(|(w, h, _)| (*w, *h)).collect()
|
||||
};
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+14
@@ -119,6 +119,8 @@ struct DecodedImageCacheInner {
|
||||
bytes: usize,
|
||||
/// PdfCraft patch (32): how many keyed decodes ran (cache misses).
|
||||
decodes: usize,
|
||||
/// PdfCraft patch (82): how many of `decodes` were of masks (keys with `mask_output`).
|
||||
mask_decodes: usize,
|
||||
}
|
||||
|
||||
impl DecodedImageCache {
|
||||
@@ -135,6 +137,15 @@ impl DecodedImageCache {
|
||||
self.inner.lock().map(|locked| locked.decodes).unwrap_or(0)
|
||||
}
|
||||
|
||||
/// PdfCraft patch (82): how many of [`Self::decodes`] were of soft masks and `/Mask` images,
|
||||
/// for tests. 0 when the lock is poisoned.
|
||||
pub(crate) fn mask_decodes(&self) -> usize {
|
||||
self.inner
|
||||
.lock()
|
||||
.map(|locked| locked.mask_decodes)
|
||||
.unwrap_or(0)
|
||||
}
|
||||
|
||||
/// The same cache, for a preview (`true`) or a final render.
|
||||
pub(crate) fn for_render(&self, preview: bool) -> Self {
|
||||
Self {
|
||||
@@ -172,6 +183,9 @@ impl DecodedImageCache {
|
||||
return val;
|
||||
};
|
||||
locked.decodes = locked.decodes.saturating_add(1);
|
||||
if key.mask_output {
|
||||
locked.mask_decodes = locked.mask_decodes.saturating_add(1);
|
||||
}
|
||||
// Another thread may have decoded it meanwhile: keep the first copy.
|
||||
if let Some(existing) = locked.map.get(&key)
|
||||
&& let Some(existing) = existing.as_ref().and_then(|val| val.downcast_ref::<T>())
|
||||
|
||||
+6
@@ -147,6 +147,12 @@ impl<'a> InterpreterCache<'a> {
|
||||
self.decoded_cache.decodes()
|
||||
}
|
||||
|
||||
/// PdfCraft patch (82): how many of [`Self::decoded_image_decodes`] were of soft masks and
|
||||
/// `/Mask` images, for diagnostics and tests.
|
||||
pub fn decoded_mask_decodes(&self) -> usize {
|
||||
self.decoded_cache.mask_decodes()
|
||||
}
|
||||
|
||||
/// PdfCraft patch (48): how many `/ICCBased` profiles were read through this cache, for
|
||||
/// diagnostics and tests. A profile used again, by the same stream object or by a copy with
|
||||
/// the same dictionary and bytes, is read once.
|
||||
|
||||
Reference in New Issue
Block a user