Implement ObjectFit::ScaleDown for images (#10063)

While working towards fixes for the image viewer, @mikayla-maki and I
discovered that we didn't have `object-fit: scale-down` implemented.
This doesn't _fully_ solve the image issues as there is some issue where
only the bounds width is updating on layout change that I haven't fully
chased down.

Co-Authored-By: @mikayla-maki 

Release Notes:

- N/A

---------

Co-authored-by: Mikayla Maki <mikayla@zed.dev>
This commit is contained in:
Kyle Kelley 2024-04-06 15:20:30 -07:00 committed by GitHub
parent c64c2758c0
commit c7961b9054
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 102 additions and 58 deletions

View file

@ -99,6 +99,8 @@ pub enum ObjectFit {
Contain,
/// The image will be scaled to cover the bounds of the element.
Cover,
/// The image will be scaled down to fit within the bounds of the element.
ScaleDown,
/// The image will maintain its original size.
None,
}
@ -114,7 +116,7 @@ impl ObjectFit {
let image_ratio = image_size.width / image_size.height;
let bounds_ratio = bounds.size.width / bounds.size.height;
match self {
let result_bounds = match self {
ObjectFit::Fill => bounds,
ObjectFit::Contain => {
let new_size = if bounds_ratio > image_ratio {
@ -137,6 +139,42 @@ impl ObjectFit {
size: new_size,
}
}
ObjectFit::ScaleDown => {
// Check if the image is larger than the bounds in either dimension.
if image_size.width > bounds.size.width || image_size.height > bounds.size.height {
// If the image is larger, use the same logic as Contain to scale it down.
let new_size = if bounds_ratio > image_ratio {
size(
image_size.width * (bounds.size.height / image_size.height),
bounds.size.height,
)
} else {
size(
bounds.size.width,
image_size.height * (bounds.size.width / image_size.width),
)
};
Bounds {
origin: point(
bounds.origin.x + (bounds.size.width - new_size.width) / 2.0,
bounds.origin.y + (bounds.size.height - new_size.height) / 2.0,
),
size: new_size,
}
} else {
// If the image is smaller than or equal to the container, display it at its original size,
// centered within the container.
let original_size = size(image_size.width, image_size.height);
Bounds {
origin: point(
bounds.origin.x + (bounds.size.width - original_size.width) / 2.0,
bounds.origin.y + (bounds.size.height - original_size.height) / 2.0,
),
size: original_size,
}
}
}
ObjectFit::Cover => {
let new_size = if bounds_ratio > image_ratio {
size(
@ -162,7 +200,9 @@ impl ObjectFit {
origin: bounds.origin,
size: image_size,
},
}
};
result_bounds
}
}