Add dimension source attribute to HTMLImageElement (#38152)

HTMLImageElement was missing the dimension source attribute, as step 9
from
[here](https://html.spec.whatwg.org/multipage/images.html#updating-the-source-set)
wasn't implemented. This meant that for an element like this:
```html
<picture>
  <source media="(min-width: 1000px)"
    srcset=""
    width="84" height="29">
  <img
    src=""
    width="25" height="25" alt="Wikimedia Foundation" lang="en" loading="lazy">
</picture>
```

The `width` and `height` attributes of the source tag were being
ignored. This broke stuff like these icons on the main page of
Wikipedia.

**Original:**
<img width="2252" height="229" alt="image"
src="https://github.com/user-attachments/assets/fa3fdd9d-5f91-43d4-bc9d-784b0a836d44"
/>


**Fixed:**
<img width="2252" height="229" alt="image"
src="https://github.com/user-attachments/assets/6f4ca4ae-e764-4394-ac31-9a92bbb456ab"
/>


Testing: If there isn't an existing test that covers this I'll make one,
waiting for the github runner to tell me whether this is covered and
then I'll amend the PR

---------

Signed-off-by: Leo Ring <leoring03@gmail.com>
Signed-off-by: Xiaocheng Hu <hu.xiaocheng@huawei.com>
Signed-off-by: Xiaocheng Hu <xiaochengh.work@gmail.com>
Co-authored-by: Xiaocheng Hu <hu.xiaocheng@huawei.com>
Co-authored-by: Xiaocheng Hu <xiaochengh.work@gmail.com>
This commit is contained in:
leo030303 2025-07-24 14:40:44 +01:00 committed by GitHub
parent be38bd4636
commit 5592061474
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 36 additions and 15 deletions

View file

@ -162,6 +162,9 @@ pub(crate) struct HTMLImageElement {
form_owner: MutNullableDom<HTMLFormElement>,
generation: Cell<u32>,
source_set: DomRefCell<SourceSet>,
/// <https://html.spec.whatwg.org/multipage/#concept-img-dimension-attribute-source>
/// Always non-null after construction.
dimension_attribute_source: MutNullableDom<Element>,
last_selected_source: DomRefCell<Option<USVString>>,
#[ignore_malloc_size_of = "promises are hard"]
image_decode_promises: DomRefCell<Vec<Rc<Promise>>>,
@ -737,9 +740,20 @@ impl HTMLImageElement {
}
// Step 4.9
self.normalise_source_densities(&mut source_set, width);
if element
.get_attribute(&ns!(), &local_name!("width"))
.is_some() ||
element
.get_attribute(&ns!(), &local_name!("height"))
.is_some()
{
self.dimension_attribute_source.set(Some(element));
}
// Step 4.10
self.normalise_source_densities(&mut source_set, width);
// Step 4.11
*self.source_set.borrow_mut() = source_set;
return;
}
@ -1348,6 +1362,7 @@ impl HTMLImageElement {
form_owner: Default::default(),
generation: Default::default(),
source_set: DomRefCell::new(SourceSet::new()),
dimension_attribute_source: Default::default(),
last_selected_source: DomRefCell::new(None),
image_decode_promises: DomRefCell::new(vec![]),
line_number: creator.return_line_number(),
@ -1363,14 +1378,18 @@ impl HTMLImageElement {
creator: ElementCreator,
can_gc: CanGc,
) -> DomRoot<HTMLImageElement> {
Node::reflect_node_with_proto(
let image_element = Node::reflect_node_with_proto(
Box::new(HTMLImageElement::new_inherited(
local_name, prefix, document, creator,
)),
document,
proto,
can_gc,
)
);
image_element
.dimension_attribute_source
.set(Some(image_element.upcast()));
image_element
}
pub(crate) fn areas(&self) -> Option<Vec<DomRoot<HTMLAreaElement>>> {
@ -1487,6 +1506,16 @@ impl<'dom> LayoutDom<'dom, HTMLImageElement> {
fn current_request(self) -> &'dom ImageRequest {
unsafe { self.unsafe_get().current_request.borrow_for_layout() }
}
#[allow(unsafe_code)]
fn dimension_attribute_source(self) -> LayoutDom<'dom, Element> {
unsafe {
self.unsafe_get()
.dimension_attribute_source
.get_inner_as_layout()
.expect("dimension attribute source should be always non-null")
}
}
}
impl LayoutHTMLImageElementHelpers for LayoutDom<'_, HTMLImageElement> {
@ -1504,18 +1533,16 @@ impl LayoutHTMLImageElementHelpers for LayoutDom<'_, HTMLImageElement> {
}
fn get_width(self) -> LengthOrPercentageOrAuto {
self.upcast::<Element>()
self.dimension_attribute_source()
.get_attr_for_layout(&ns!(), &local_name!("width"))
.map(AttrValue::as_dimension)
.cloned()
.map(|x| *AttrValue::from_dimension(x.to_string()).as_dimension())
.unwrap_or(LengthOrPercentageOrAuto::Auto)
}
fn get_height(self) -> LengthOrPercentageOrAuto {
self.upcast::<Element>()
self.dimension_attribute_source()
.get_attr_for_layout(&ns!(), &local_name!("height"))
.map(AttrValue::as_dimension)
.cloned()
.map(|x| *AttrValue::from_dimension(x.to_string()).as_dimension())
.unwrap_or(LengthOrPercentageOrAuto::Auto)
}
}