LibWeb: Use dimension image source for images

Fixes tiny images on Wikipedia
This commit is contained in:
Chase Knowlden 2026-02-11 20:41:13 -05:00 committed by Sam Atkins
parent 31cbe2061a
commit b8f31179b2
5 changed files with 83 additions and 14 deletions

View file

@ -78,6 +78,7 @@
#include <LibWeb/DOM/ShadowRoot.h>
#include <LibWeb/HTML/HTMLBRElement.h>
#include <LibWeb/HTML/HTMLHtmlElement.h>
#include <LibWeb/HTML/HTMLImageElement.h>
#include <LibWeb/HTML/HTMLSlotElement.h>
#include <LibWeb/HTML/Parser/HTMLParser.h>
#include <LibWeb/Layout/Node.h>
@ -1274,8 +1275,11 @@ GC::Ref<CascadedProperties> StyleComputer::compute_cascaded_values(DOM::Abstract
auto& element = abstract_element.element();
element.apply_presentational_hints(cascaded_properties);
if (element.supports_dimension_attributes()) {
apply_dimension_attribute(cascaded_properties, element, HTML::AttributeNames::width, CSS::PropertyID::Width);
apply_dimension_attribute(cascaded_properties, element, HTML::AttributeNames::height, CSS::PropertyID::Height);
auto const& dimension_source = is<HTML::HTMLImageElement>(element)
? static_cast<HTML::HTMLImageElement const&>(element).dimension_attribute_source()
: element;
apply_dimension_attribute(cascaded_properties, dimension_source, HTML::AttributeNames::width, CSS::PropertyID::Width);
apply_dimension_attribute(cascaded_properties, dimension_source, HTML::AttributeNames::height, CSS::PropertyID::Height);
}
// SVG presentation attributes are parsed as CSS values, so we need to handle potential custom properties here.

View file

@ -102,9 +102,26 @@ void HTMLImageElement::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_current_request);
visitor.visit(m_pending_request);
visitor.visit(m_document_observer);
visitor.visit(m_dimension_attribute_source);
visit_lazy_loading_element(visitor);
}
// https://html.spec.whatwg.org/multipage/embedded-content.html#concept-img-dimension-attribute-source
DOM::Element const& HTMLImageElement::dimension_attribute_source() const
{
if (m_dimension_attribute_source)
return *m_dimension_attribute_source;
return *this;
}
void HTMLImageElement::set_dimension_attribute_source(DOM::Element const* source)
{
if (m_dimension_attribute_source.ptr() != source) {
m_dimension_attribute_source = source;
set_needs_style_update(true);
}
}
bool HTMLImageElement::is_presentational_hint(FlyString const& name) const
{
if (Base::is_presentational_hint(name))
@ -1290,25 +1307,22 @@ static void update_the_source_set(DOM::Element& element)
// 8. If child has a type attribute, and its value is an unknown or unsupported MIME type, continue to the next child.
if (child->has_attribute(HTML::AttributeNames::type)) {
auto mime_type = child->get_attribute_value(HTML::AttributeNames::type);
if (is<HTMLImageElement>(element)) {
if (!is_supported_image_type(mime_type))
continue;
}
// FIXME: Implement this step for link elements
if (!is_supported_image_type(mime_type))
continue;
}
// FIXME: 9. If child has width or height attributes, set el's dimension attribute source to child.
// Otherwise, set el's dimension attribute source to el.
// 9. If child has width or height attributes, set el's dimension attribute source to child.
// Otherwise, set el's dimension attribute source to el.
if (child->has_attribute(HTML::AttributeNames::width) || child->has_attribute(HTML::AttributeNames::height))
img->set_dimension_attribute_source(child);
else
img->set_dimension_attribute_source(nullptr);
// 10. Normalize the source densities of source set.
source_set.normalize_source_densities(element);
// 11. Set el's source set to source set.
if (auto* image_element = as_if<HTMLImageElement>(element))
image_element->set_source_set(move(source_set));
else if (is<HTMLLinkElement>(element))
TODO();
img->set_source_set(move(source_set));
// 12. Return.
return;

View file

@ -92,6 +92,10 @@ public:
void set_source_set(SourceSet);
// https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element:dimension-attribute-source
DOM::Element const& dimension_attribute_source() const;
void set_dimension_attribute_source(DOM::Element const*);
ImageRequest& current_request() { return *m_current_request; }
ImageRequest const& current_request() const { return *m_current_request; }
@ -168,6 +172,10 @@ private:
CSSPixelSize m_last_seen_viewport_size;
// https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element:dimension-attribute-source
// Each img element has a dimension attribute source, which must initially be the img element itself.
GC::Ptr<DOM::Element const> m_dimension_attribute_source;
u64 m_update_the_image_data_count { 0 };
};

View file

@ -0,0 +1,2 @@
with source dimensions: 200x100
without source dimensions: 50x50

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<script src="../include.js"></script>
<script>
asyncTest((done) => {
const picture = document.createElement("picture");
const source = document.createElement("source");
source.media = "(min-width: 1px)";
source.srcset = "../../../Assets/120.png";
source.width = 200;
source.height = 100;
const img = document.createElement("img");
img.src = "../../../Assets/120.png";
img.width = 25;
img.height = 25;
picture.appendChild(source);
picture.appendChild(img);
document.body.appendChild(picture);
img.onload = function() {
println("with source dimensions: " + img.clientWidth + "x" + img.clientHeight);
picture.remove();
// Test without source dimensions (should use img dimensions)
const picture2 = document.createElement("picture");
const source2 = document.createElement("source");
source2.media = "(min-width: 1px)";
source2.srcset = "../../../Assets/120.png";
const img2 = document.createElement("img");
img2.src = "../../../Assets/120.png";
img2.width = 50;
img2.height = 50;
picture2.appendChild(source2);
picture2.appendChild(img2);
document.body.appendChild(picture2);
img2.onload = function() {
println("without source dimensions: " + img2.clientWidth + "x" + img2.clientHeight);
picture2.remove();
done();
};
};
});
</script>