LibWeb/CSS: Remove the "Auto" type from Length

This has always been a bit of a hack. Initially it made sense as a lot
of properties that accept a length also accept `auto`, but while
convenient, that leads to problems: It's easy to forget to check if a
length is `auto`, and places that don't accept it end up with an
invalid state lurking in the type system, which makes things unclear.
This commit is contained in:
Sam Atkins 2025-09-01 14:03:25 +01:00
commit 930ee495e7
Notes: github-actions[bot] 2025-09-04 12:32:29 +00:00
10 changed files with 8 additions and 66 deletions

View file

@ -321,8 +321,6 @@ WebIDL::ExceptionOr<void> CSSStyleProperties::set_property(PropertyID property_i
static NonnullRefPtr<StyleValue const> style_value_for_length_percentage(LengthPercentage const& length_percentage)
{
if (length_percentage.is_auto())
return KeywordStyleValue::create(Keyword::Auto);
if (length_percentage.is_percentage())
return PercentageStyleValue::create(length_percentage.percentage());
if (length_percentage.is_length())

View file

@ -209,12 +209,8 @@ Size ComputedProperties::size_value(PropertyID id) const
if (value.is_percentage())
return Size::make_percentage(value.as_percentage().percentage());
if (value.is_length()) {
auto length = value.as_length().length();
if (length.is_auto())
return Size::make_auto();
return Size::make_length(length);
}
if (value.is_length())
return Size::make_length(value.as_length().length());
// FIXME: Support `anchor-size(..)`
if (value.is_anchor_size())
@ -378,11 +374,8 @@ CSSPixels ComputedProperties::compute_line_height(CSSPixelRect const& viewport_r
if (line_height.is_keyword() && line_height.to_keyword() == Keyword::Normal)
return CSSPixels { round_to<i32>(font_metrics.font_size * normal_line_height_scale) };
if (line_height.is_length()) {
auto line_height_length = line_height.as_length().length();
if (!line_height_length.is_auto())
return line_height_length.to_px(viewport_rect, font_metrics, root_font_metrics);
}
if (line_height.is_length())
return line_height.as_length().length().to_px(viewport_rect, font_metrics, root_font_metrics);
if (line_height.is_number())
return Length(line_height.as_number().number(), Length::Type::Em).to_px(viewport_rect, font_metrics, root_font_metrics);

View file

@ -96,9 +96,7 @@ bool GridSize::is_intrinsic(Layout::AvailableSize const& available_size) const
bool GridSize::is_definite() const
{
return m_value.visit(
[](Size const& size) {
return (size.is_length() && !size.length().is_auto()) || size.is_percentage() || size.is_calculated();
},
[](Size const& size) { return size.is_length_percentage(); },
[](Flex const&) { return false; });
}

View file

@ -38,11 +38,6 @@ Length::Length(double value, Type type)
}
Length::~Length() = default;
Length Length::make_auto()
{
return Length(0, Type::Auto);
}
Length Length::make_px(double value)
{
return Length(value, Type::Px);
@ -55,11 +50,6 @@ Length Length::make_px(CSSPixels value)
Length Length::percentage_of(Percentage const& percentage) const
{
if (is_auto()) {
dbgln("Attempting to get percentage of an auto length, this seems wrong? But for now we just return the original length.");
return *this;
}
return Length { percentage.as_fraction() * raw_value(), m_type };
}
@ -191,11 +181,6 @@ CSSPixels Length::to_px(ResolutionContext const& context) const
CSSPixels Length::to_px_slow_case(Layout::Node const& layout_node) const
{
if (is_auto()) {
// FIXME: We really, really shouldn't end up here, but we do, and so frequently that
// adding a dbgln() here outputs a couple hundred lines loading `welcome.html`.
return 0;
}
if (!layout_node.document().browsing_context())
return 0;
@ -223,9 +208,6 @@ CSSPixels Length::to_px_slow_case(Layout::Node const& layout_node) const
String Length::to_string(SerializationMode serialization_mode) const
{
if (is_auto())
return "auto"_string;
// https://drafts.csswg.org/cssom/#serialize-a-css-value
// -> <length>
// The <number> component serialized as per <number> followed by the unit in its canonical form as defined in its
@ -334,8 +316,6 @@ StringView Length::unit_name() const
return "pc"sv;
case Type::Px:
return "px"sv;
case Type::Auto:
return "auto"sv;
}
VERIFY_NOT_REACHED();
}

View file

@ -68,9 +68,6 @@ public:
Pt,
Pc,
Px,
// FIXME: Remove auto somehow
Auto,
};
struct FontMetrics {
@ -90,12 +87,10 @@ public:
Length(double value, Type type);
~Length();
static Length make_auto();
static Length make_px(double value);
static Length make_px(CSSPixels value);
Length percentage_of(Percentage const&) const;
bool is_auto() const { return m_type == Type::Auto; }
bool is_px() const { return m_type == Type::Px; }
bool is_absolute() const
@ -185,8 +180,6 @@ public:
ALWAYS_INLINE CSSPixels to_px(CSSPixelRect const& viewport_rect, FontMetrics const& font_metrics, FontMetrics const& root_font_metrics) const
{
if (is_auto())
return 0;
if (is_absolute())
return absolute_length_to_px();
if (is_font_relative())
@ -254,11 +247,8 @@ private:
class LengthOrAuto {
public:
LengthOrAuto(Length length)
: m_length(move(length))
{
if (length.is_auto())
m_length = {};
else
m_length = move(length);
}
static LengthOrAuto make_auto() { return LengthOrAuto { OptionalNone {} }; }

View file

@ -3173,7 +3173,6 @@ RefPtr<FitContentStyleValue const> Parser::parse_fit_content_value(TokenStream<C
if (component_value.is_ident("fit-content"sv)) {
transaction.commit();
return FitContentStyleValue::create();
return nullptr;
}
if (!component_value.is_function())
@ -3192,8 +3191,6 @@ RefPtr<FitContentStyleValue const> Parser::parse_fit_content_value(TokenStream<C
return nullptr;
transaction.commit();
if (maybe_length->is_auto())
return FitContentStyleValue::create();
return FitContentStyleValue::create(maybe_length.release_value());
}

View file

@ -208,8 +208,6 @@ class LengthPercentage : public PercentageOr<Length, LengthPercentage> {
public:
using PercentageOr<Length, LengthPercentage>::PercentageOr;
bool is_auto() const { return is_length() && length().is_auto(); }
bool is_length() const { return is_t(); }
Length const& length() const { return get_t(); }
};
@ -217,19 +215,13 @@ public:
class LengthPercentageOrAuto {
public:
LengthPercentageOrAuto(LengthPercentage length_percentage)
: m_length_percentage(move(length_percentage))
{
if (length_percentage.is_auto())
m_length_percentage = {};
else
m_length_percentage = move(length_percentage);
}
LengthPercentageOrAuto(Length length)
: m_length_percentage(move(length))
{
if (length.is_auto())
m_length_percentage = {};
else
m_length_percentage = move(length);
}
LengthPercentageOrAuto(Percentage percentage)

View file

@ -48,8 +48,6 @@ Size Size::make_calculated(NonnullRefPtr<CalculatedStyleValue const> calculated)
Size Size::make_length_percentage(LengthPercentage const& length_percentage)
{
if (length_percentage.is_auto())
return make_auto();
if (length_percentage.is_length())
return make_length(length_percentage.length());
if (length_percentage.is_percentage())

View file

@ -2807,9 +2807,6 @@ CalculatedStyleValue::CalculationResult CalculatedStyleValue::CalculationResult:
[](Frequency const& frequency) { return frequency.to_hertz(); },
[&context](Length const& length) {
// Handle some common cases first, so we can resolve more without a context
if (length.is_auto())
return 0.0;
if (length.is_absolute())
return length.absolute_length_to_px_without_rounding();

View file

@ -13,7 +13,6 @@ namespace Web::CSS {
ValueComparingNonnullRefPtr<LengthStyleValue const> LengthStyleValue::create(Length const& length)
{
VERIFY(!length.is_auto());
if (length.is_px()) {
if (length.raw_value() == 0) {
static auto value = adopt_ref(*new (nothrow) LengthStyleValue(CSS::Length::make_px(0)));