ladybird/Libraries/LibWeb/Layout/ImageBox.cpp
Jonathan Gamble ec50525675 LibWeb/Layout: Don't inject natural size in prepare_for_replaced_layout
Instead, compute them on demand. This affects ReplacedBox and its
subclasses.

This commit is centered around a new Box::auto_content_box_size
method. It returns a SizeWithAspectRatio representing the natural
size of a replaced element, or the size derived from attributes
for text input and textarea. These values are used when the
corresponding axis is auto or indefinite.

Although introducing this API choke-point for sizing replaced and
replaced-like elements was the main goal, it's notable that layout
becomes more robust in the face of dynamic changes due to reduced
potential for stale size values (at the cost of extra calculations
and allocations).
2026-02-02 14:36:49 +00:00

77 lines
2.1 KiB
C++

/*
* Copyright (c) 2018-2022, Andreas Kling <andreas@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibWeb/HTML/BrowsingContext.h>
#include <LibWeb/HTML/DecodedImageData.h>
#include <LibWeb/Layout/ImageBox.h>
#include <LibWeb/Layout/ImageProvider.h>
#include <LibWeb/Painting/ImagePaintable.h>
#include <LibWeb/Platform/FontPlugin.h>
namespace Web::Layout {
GC_DEFINE_ALLOCATOR(ImageBox);
ImageBox::ImageBox(DOM::Document& document, GC::Ptr<DOM::Element> element, GC::Ref<CSS::ComputedProperties> style, ImageProvider const& image_provider)
: ReplacedBox(document, element, move(style))
, m_image_provider(image_provider)
{
}
ImageBox::~ImageBox() = default;
void ImageBox::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
m_image_provider.image_provider_visit_edges(visitor);
}
CSS::SizeWithAspectRatio ImageBox::natural_size() const
{
if (m_image_provider.is_image_available()) {
return {
.width = m_image_provider.intrinsic_width(),
.height = m_image_provider.intrinsic_height(),
.aspect_ratio = m_image_provider.intrinsic_aspect_ratio()
};
}
String alt;
if (auto element = dom_node())
alt = element->get_attribute_value(HTML::AttributeNames::alt);
if (alt.is_empty())
return { 0, 0, {} };
auto font = Platform::FontPlugin::the().default_font(12);
CSSPixels alt_text_width = m_cached_alt_text_width.ensure([&] {
return CSSPixels::nearest_value_for(font->width(Utf16String::from_utf8(alt)));
});
auto width = alt_text_width + 16;
auto height = CSSPixels::nearest_value_for(font->pixel_size()) + 16;
Optional<CSSPixelFraction> aspect_ratio;
if (height > 0)
aspect_ratio = CSSPixelFraction(width, height);
return { width, height, aspect_ratio };
}
void ImageBox::dom_node_did_update_alt_text(Badge<ImageProvider>)
{
m_cached_alt_text_width = {};
}
bool ImageBox::renders_as_alt_text() const
{
return !m_image_provider.is_image_available();
}
GC::Ptr<Painting::Paintable> ImageBox::create_paintable() const
{
return Painting::ImagePaintable::create(*this);
}
}