From e69fa2a91f789c201bc8d6f446b44d1b97d67a79 Mon Sep 17 00:00:00 2001 From: William Salmon Date: Mon, 1 Nov 2021 20:49:56 +0000 Subject: [PATCH] Catch edge cases were the image widget would request inf sized layout --- druid/src/widget/image.rs | 43 +++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-) diff --git a/druid/src/widget/image.rs b/druid/src/widget/image.rs index 9d86fd9ea..78eaffc80 100644 --- a/druid/src/widget/image.rs +++ b/druid/src/widget/image.rs @@ -197,12 +197,34 @@ impl Widget for Image { ) -> Size { bc.debug_check("Image"); - // If either the width or height is constrained calculate a value so that the image fits - // in the size exactly. If it is unconstrained by both width and height then use the fill - // strategy to determine the size. + // Let the fill strat determine the size of the widget as a function of the bc.max() + // and the original image size. But catch cases were they would return INFINITY + // and try to make a sensible area as a function of the fill strat. let max = bc.max(); let image_size = self.image_size(); - let affine = self.fill.affine_to_fill(max, image_size).as_coeffs(); + let mut max_width = bc.max().width; + let mut max_height = bc.max().height; + let mut fill_strat = self.fill; + if max_width == f64::INFINITY && max_height == f64::INFINITY { + // If we are in a scroll box for width and height then fall back to + // original image size + max_height = image_size.height; + max_width = image_size.width; + } else if max_width == f64::INFINITY || max_height == f64::INFINITY { + // If we are in a scroll box for width or heigh but not both + // then give self.fill a box the size of the scroll box and let it decide how to + // fill it. Unless that would result in requesting INFINITY in which case fall back + // to contain. + fill_strat = match fill_strat { + FillStrat::FitWidth if max_width == f64::INFINITY => FillStrat::Contain, + FillStrat::FitHeight if max_height == f64::INFINITY => FillStrat::Contain, + FillStrat::Cover | FillStrat::Fill => FillStrat::Contain, + _ => fill_strat, + } + } + let affine = fill_strat + .affine_to_fill(Size::new(max_width, max_height), image_size) + .as_coeffs(); // The first and forth elements of the affine are the x and y scale factor. // So just multiply them by the original size to get the ideal area based on `self.fill`. let mut width = affine[0] * image_size.width; @@ -211,6 +233,7 @@ impl Widget for Image { // would be over scaled to keep AR fixed then we just clip back to the `bc.max()` width = width.min(max.width); height = height.min(max.height); + let size = Size::new(width, height); trace!("Computed size: {}", size); size @@ -437,8 +460,10 @@ mod tests { 2, ); - let image_widget = - Scroll::new(Container::new(Image::new(image_data).fill_mode(FillStrat::Fill)).with_id(id_1)).vertical(); + let image_widget = Scroll::new( + Container::new(Image::new(image_data).fill_mode(FillStrat::Fill)).with_id(id_1), + ) + .vertical(); Harness::create_simple(true, image_widget, |harness| { harness.send_initial_events(); @@ -465,8 +490,10 @@ mod tests { 2, ); - let image_widget = - Scroll::new(Container::new(Image::new(image_data).fill_mode(FillStrat::Fill)).with_id(id_1)).horizontal(); + let image_widget = Scroll::new( + Container::new(Image::new(image_data).fill_mode(FillStrat::Fill)).with_id(id_1), + ) + .horizontal(); Harness::create_simple(true, image_widget, |harness| { harness.send_initial_events();