Decode a soft mask that isn't averaged down within its image's decode

Patch 82 sent every soft mask through the decoded-image cache, so a mask that patch 91 keeps failed inside its image's entry got a second entry and counted as another decode. Only a mask averaged down needs an entry of its own; any other decodes as it did before patch 82.
This commit is contained in:
bflatastic committed 2026-11-09 09:05:11 +07:00
1 parent 9e6854869b
commit b21ee3a710
2 files changed
+7 -4

No files matched your search

+3 -3
View File
@@ -8948,9 +8948,9 @@ fn decoded_images_serve_every_size_they_are_drawn_at() {
(cache.decoded_image_decodes() - masks, masks)
};
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");
// The image decodes once for each of the five sizes, its JPX soft mask within it: only a mask
// averaged down (hayro-interpret patch 82) has a cache entry of its own.
assert_eq!(decodes("B"), (5, 0), "an image with a JPX soft mask decodes for the size it is drawn at");
}
/// A soft mask far larger than where its image is drawn is averaged down to that size and cached
+4 -1
View File
@@ -678,8 +678,11 @@ impl<'a> ImageXObject<'a> {
&& (u64::from(self.width) > u64::from(tw) * SOFT_MASK_SHRINK_FACTOR
|| u64::from(self.height) > u64::from(th) * SOFT_MASK_SHRINK_FACTOR)
});
// Decoded within the image's own decode, as before: the image's cache entry holds it as
// its alpha, and patch (91) keeps that entry when the mask fails, so a second entry for
// the mask would only count it twice.
let Some((tw, th)) = shrink_to else {
return self.decoded_mask(target_dimension);
return decode_mask(self, target_dimension);
};
// Averaged down to the drawn size rounded up to a power of two (`size_bucket`), so draws a
// pixel apart share one mask and the renderer filters the rest, and only on the sides that