fix(algo): normalize nonpositive filter tile sizes (#7554)

This commit is contained in:
JGF
2026-10-18 16:57:08 -04:00
committed by GitHub
parent d77a989ef4
commit b48a916b13
2 changed files with 24 additions and 0 deletions
+3
View File
@@ -972,6 +972,7 @@ fn auto_tile(params: &FilterParams, bounds: Rect) -> i32 {
}
/// [`apply`] / [`apply_in`] with an explicit tile size (tests use it to check tile independence).
/// Nonpositive tile sizes are treated as one pixel.
pub fn apply_tiled(
surface: &Surface,
params: &FilterParams,
@@ -1014,6 +1015,8 @@ fn apply_tiled_with_impl(
ctl: &photocraft_raster::Interrupt,
prepare_fast_paths: bool,
) -> Option<Surface> {
// Every dispatch path needs a positive step, including Motion Blur's fallback.
let tile = tile.max(1);
if ctl.cancelled() {
return None;
}
+21
View File
@@ -90,6 +90,27 @@ fn radial_blur_quality_defaults_for_older_serialized_parameters() {
assert_eq!(decoded, FilterParams::RadialBlur { amount: 20.0, method: RadialMethod::Spin, quality: RadialQuality::Good, center_x: 0.5, center_y: 0.5 });
}
#[test]
fn nonpositive_tile_sizes_match_one_pixel_tiles() {
let area = Rect::new(0, 0, 4, 3);
for depth in [SampleType::U8, SampleType::U16, SampleType::F32] {
let source = pattern(depth, area);
for params in all_filters().into_iter().chain([FilterParams::ShapeBlur { radius: 3.0, shape: BlurShape::Star }]) {
let expected = apply_tiled(&source, &params, area, area, None, 1, Some(area));
for tile in [0, -64, i32::MIN] {
let actual = apply_tiled(&source, &params, area, area, None, tile, Some(area));
assert_eq!(actual.read_region(area), expected.read_region(area), "{}: {depth:?}, tile={tile}", params.label());
let cancellable = apply_tiled_with(&source, &params, area, area, None, tile, Some(area), &photocraft_raster::Interrupt::NONE)
.expect("a nonpositive tile size is normalized, not rejected");
assert_eq!(cancellable.read_region(area), expected.read_region(area), "{}: {depth:?}, tile={tile}", params.label());
let cancelled = photocraft_raster::Interrupt::cancel_only(&|| true);
assert!(apply_tiled_with(&source, &params, area, area, None, tile, Some(area), &cancelled).is_none());
}
}
assert_eq!(source.read_region(area), pattern(depth, area).read_region(area));
}
}
#[test]
fn every_filter_is_tile_independent() {
let s = pattern(SampleType::U8, R);