layout: Scale images in image_set by their specified resolution (#36374)

This PR makes it so the `resolution` factor in `image-set` also affects
the image size.
For instance, in the example below:

```css
background-image: image-set("./small.png" 1x, "./large.png" 2x);
```

if `large.png` is used, an image which is 32x32 will be rendered as
16x16. This is specified
in <https://drafts.csswg.org/css-images-4/#image-set-notation>.

Testing:
 - `css/css-images/image-set/image-set-resolution-002.html`

---------

Signed-off-by: tobinio <Tobias.frischmann1@gmail.com>
Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
Co-authored-by: Josh Matthews <josh@joshmatthews.net>
This commit is contained in:
ToBinio 2025-04-07 15:54:29 +02:00 committed by GitHub
parent 3e249c9bc4
commit 4f41354349
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 30 additions and 14 deletions

View file

@ -5,6 +5,7 @@
use std::sync::Arc; use std::sync::Arc;
use base::id::PipelineId; use base::id::PipelineId;
use euclid::Size2D;
use fnv::FnvHashMap; use fnv::FnvHashMap;
use fonts::FontContext; use fonts::FontContext;
use fxhash::FxHashMap; use fxhash::FxHashMap;
@ -148,8 +149,7 @@ impl LayoutContext<'_> {
Some(ImageOrMetadataAvailable::ImageAvailable { image, .. }) => { Some(ImageOrMetadataAvailable::ImageAvailable { image, .. }) => {
self.handle_animated_image(node, image.clone()); self.handle_animated_image(node, image.clone());
let image_info = WebRenderImageInfo { let image_info = WebRenderImageInfo {
width: image.width, size: Size2D::new(image.width, image.height),
height: image.height,
key: image.id, key: image.id,
}; };
if image_info.key.is_none() { if image_info.key.is_none() {
@ -188,10 +188,29 @@ impl LayoutContext<'_> {
)?; )?;
Some(ResolvedImage::Image(webrender_info)) Some(ResolvedImage::Image(webrender_info))
}, },
Image::ImageSet(image_set) => image_set Image::ImageSet(image_set) => {
.items image_set
.get(image_set.selected_index) .items
.and_then(|image| self.resolve_image(node, &image.image)), .get(image_set.selected_index)
.and_then(|image| {
self.resolve_image(node, &image.image)
.map(|info| match info {
ResolvedImage::Image(mut image_info) => {
// From <https://drafts.csswg.org/css-images-4/#image-set-notation>:
// > A <resolution> (optional). This is used to help the UA decide
// > which <image-set-option> to choose. If the image reference is
// > for a raster image, it also specifies the images natural
// > resolution, overriding any other source of data that might
// > supply a natural resolution.
image_info.size = (image_info.size.to_f32() /
image.resolution.dppx())
.to_u32();
ResolvedImage::Image(image_info)
},
_ => info,
})
})
},
} }
} }
} }

View file

@ -61,8 +61,7 @@ pub use stacking_context::*;
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct WebRenderImageInfo { pub struct WebRenderImageInfo {
pub width: u32, pub size: Size2D<u32, UnknownUnit>,
pub height: u32,
pub key: Option<wr::ImageKey>, pub key: Option<wr::ImageKey>,
} }
@ -817,8 +816,8 @@ impl<'a> BuilderForBoxFragment<'a> {
// FIXME: https://drafts.csswg.org/css-images-4/#the-image-resolution // FIXME: https://drafts.csswg.org/css-images-4/#the-image-resolution
let dppx = 1.0; let dppx = 1.0;
let intrinsic = NaturalSizes::from_width_and_height( let intrinsic = NaturalSizes::from_width_and_height(
image_info.width as f32 / dppx, image_info.size.width as f32 / dppx,
image_info.height as f32 / dppx, image_info.size.height as f32 / dppx,
); );
let Some(image_key) = image_info.key else { let Some(image_key) = image_info.key else {
continue; continue;
@ -1007,8 +1006,8 @@ impl<'a> BuilderForBoxFragment<'a> {
return false; return false;
}; };
width = image_info.width as f32; width = image_info.size.width as f32;
height = image_info.height as f32; height = image_info.size.height as f32;
NinePatchBorderSource::Image(key, ImageRendering::Auto) NinePatchBorderSource::Image(key, ImageRendering::Auto)
}, },
Some(ResolvedImage::Gradient(gradient)) => { Some(ResolvedImage::Gradient(gradient)) => {

View file

@ -1,2 +0,0 @@
[image-set-resolution-002.html]
expected: FAIL