LibWeb/CSS: Absolutize grid-related StyleValues

This commit is contained in:
Sam Atkins 2025-11-18 15:25:03 +00:00 committed by Tim Ledbetter
parent 597fe8288c
commit 7de17dce9d
Notes: github-actions[bot] 2025-11-19 23:47:02 +00:00
12 changed files with 161 additions and 26 deletions

View file

@ -1,12 +1,14 @@
/*
* Copyright (c) 2023, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
* Copyright (c) 2022, Martin Falisse <mfalisse@outlook.com>
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "GridTrackPlacement.h"
#include <AK/StringBuilder.h>
#include <LibWeb/CSS/StyleValues/IntegerStyleValue.h>
namespace Web::CSS {
@ -38,4 +40,34 @@ String GridTrackPlacement::to_string(SerializationMode mode) const
return MUST(builder.to_string());
}
GridTrackPlacement GridTrackPlacement::absolutized(ComputationContext const& context) const
{
auto absolutize_integer_or_calculated = [&context](IntegerOrCalculated const& integer_or_calculated) {
if (!integer_or_calculated.is_calculated())
return integer_or_calculated;
auto absolutized = integer_or_calculated.calculated()->absolutized(context);
if (absolutized->is_calculated())
return IntegerOrCalculated { absolutized->as_calculated() };
VERIFY(absolutized->is_integer());
return IntegerOrCalculated { absolutized->as_integer().integer() };
};
return m_value.visit(
[this](Auto const&) {
return *this;
},
[&](AreaOrLine const& area_or_line) -> GridTrackPlacement {
return AreaOrLine {
.line_number = area_or_line.line_number.map(absolutize_integer_or_calculated),
.name = area_or_line.name,
};
},
[&](Span const& span) -> GridTrackPlacement {
return Span {
.value = absolutize_integer_or_calculated(span.value),
.name = span.name,
};
});
}
}

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2023, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
* Copyright (c) 2022, Martin Falisse <mfalisse@outlook.com>
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -55,6 +56,8 @@ public:
String to_string(SerializationMode mode) const;
GridTrackPlacement absolutized(ComputationContext const&) const;
bool operator==(GridTrackPlacement const& other) const = default;
private:

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2022, Martin Falisse <mfalisse@outlook.com>
* Copyright (c) 2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -110,6 +111,41 @@ String GridSize::to_string(SerializationMode mode) const
return m_value.visit([mode](auto const& it) { return it.to_string(mode); });
}
GridSize GridSize::absolutized(ComputationContext const& context) const
{
auto absolutize_length_percentage = [&context](LengthPercentage const& length_percentage) -> Optional<LengthPercentage> {
if (length_percentage.is_length()) {
auto length = length_percentage.length().absolutize(context.length_resolution_context.viewport_rect, context.length_resolution_context.font_metrics, context.length_resolution_context.root_font_metrics);
if (length.has_value())
return length.release_value();
return {};
}
if (length_percentage.is_calculated())
return LengthPercentage::from_style_value(length_percentage.calculated()->absolutized(context));
return {};
};
return m_value.visit(
[&](Size const& size) -> GridSize {
if (size.is_length_percentage()) {
if (auto result = absolutize_length_percentage(size.length_percentage()); result.has_value())
return Size::make_length_percentage(result.release_value());
}
if (size.is_fit_content() && size.fit_content_available_space().has_value()) {
if (auto result = absolutize_length_percentage(size.fit_content_available_space().value()); result.has_value()) {
return Size::make_fit_content(result.release_value());
}
}
return GridSize { size };
},
[](Flex const& flex) {
return GridSize { flex };
});
}
GridMinMax::GridMinMax(GridSize min_grid_size, GridSize max_grid_size)
: m_min_grid_size(move(min_grid_size))
, m_max_grid_size(move(max_grid_size))
@ -127,6 +163,14 @@ String GridMinMax::to_string(SerializationMode mode) const
return MUST(builder.to_string());
}
GridMinMax GridMinMax::absolutized(ComputationContext const& context) const
{
return GridMinMax {
m_min_grid_size.absolutized(context),
m_max_grid_size.absolutized(context),
};
}
GridRepeat::GridRepeat(GridRepeatType grid_repeat_type, GridTrackSizeList&& grid_track_size_list, size_t repeat_count)
: m_type(grid_repeat_type)
, m_grid_track_size_list(move(grid_track_size_list))
@ -162,6 +206,15 @@ String GridRepeat::to_string(SerializationMode mode) const
return MUST(builder.to_string());
}
GridRepeat GridRepeat::absolutized(ComputationContext const& context) const
{
return GridRepeat {
m_type,
m_grid_track_size_list.absolutized(context),
m_repeat_count,
};
}
ExplicitGridTrack::ExplicitGridTrack(Variant<GridRepeat, GridMinMax, GridSize>&& value)
: m_value(move(value))
{
@ -174,6 +227,13 @@ String ExplicitGridTrack::to_string(SerializationMode mode) const
});
}
ExplicitGridTrack ExplicitGridTrack::absolutized(ComputationContext const& context) const
{
return m_value.visit([&](auto const& it) {
return ExplicitGridTrack { it.absolutized(context) };
});
}
String GridLineNames::to_string() const
{
StringBuilder builder;
@ -239,4 +299,19 @@ void GridTrackSizeList::append(ExplicitGridTrack&& explicit_track)
m_list.append(move(explicit_track));
}
GridTrackSizeList GridTrackSizeList::absolutized(ComputationContext const& context) const
{
GridTrackSizeList result;
for (auto const& item : m_list) {
item.visit(
[&result, &context](ExplicitGridTrack const& track) {
result.append(track.absolutized(context));
},
[&result](GridLineNames names) {
result.append(move(names));
});
}
return result;
}
}

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2022, Martin Falisse <mfalisse@outlook.com>
* Copyright (c) 2025, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
* Copyright (c) 2025, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -40,6 +41,7 @@ public:
bool is_definite() const;
String to_string(SerializationMode) const;
GridSize absolutized(ComputationContext const&) const;
bool operator==(GridSize const& other) const = default;
private:
@ -54,6 +56,7 @@ public:
GridSize const& max_grid_size() const& { return m_max_grid_size; }
String to_string(SerializationMode) const;
GridMinMax absolutized(ComputationContext const&) const;
bool operator==(GridMinMax const& other) const = default;
private:
@ -97,6 +100,8 @@ public:
void append(GridLineNames&&);
void append(ExplicitGridTrack&&);
GridTrackSizeList absolutized(ComputationContext const&) const;
private:
Vector<Variant<ExplicitGridTrack, GridLineNames>> m_list;
};
@ -129,6 +134,7 @@ public:
GridRepeatType type() const& { return m_type; }
String to_string(SerializationMode) const;
GridRepeat absolutized(ComputationContext const&) const;
bool operator==(GridRepeat const& other) const = default;
private:
@ -151,6 +157,7 @@ public:
GridSize const& grid_size() const { return m_value.get<GridSize>(); }
String to_string(SerializationMode) const;
ExplicitGridTrack absolutized(ComputationContext const&) const;
bool operator==(ExplicitGridTrack const& other) const = default;
private:

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
@ -21,4 +21,12 @@ String GridTrackPlacementStyleValue::to_string(SerializationMode mode) const
return m_grid_track_placement.to_string(mode);
}
ValueComparingNonnullRefPtr<StyleValue const> GridTrackPlacementStyleValue::absolutized(ComputationContext const& context) const
{
auto absolutized_placement = m_grid_track_placement.absolutized(context);
if (absolutized_placement == m_grid_track_placement)
return *this;
return create(move(absolutized_placement));
}
}

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
@ -22,6 +22,8 @@ public:
GridTrackPlacement const& grid_track_placement() const { return m_grid_track_placement; }
virtual String to_string(SerializationMode) const override;
virtual ValueComparingNonnullRefPtr<StyleValue const> absolutized(ComputationContext const&) const override;
bool properties_equal(GridTrackPlacementStyleValue const& other) const { return m_grid_track_placement == other.m_grid_track_placement; }
private:

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
@ -31,4 +31,12 @@ ValueComparingNonnullRefPtr<GridTrackSizeListStyleValue const> GridTrackSizeList
return adopt_ref(*new (nothrow) GridTrackSizeListStyleValue(CSS::GridTrackSizeList()));
}
ValueComparingNonnullRefPtr<StyleValue const> GridTrackSizeListStyleValue::absolutized(ComputationContext const& context) const
{
auto absolutized = m_grid_track_size_list.absolutized(context);
if (absolutized == m_grid_track_size_list)
return *this;
return create(move(absolutized));
}
}

View file

@ -1,7 +1,7 @@
/*
* Copyright (c) 2018-2020, Andreas Kling <andreas@ladybird.org>
* Copyright (c) 2021, Tobias Christiansen <tobyase@serenityos.org>
* Copyright (c) 2021-2023, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2021-2025, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
@ -26,6 +26,8 @@ public:
virtual String to_string(SerializationMode) const override;
virtual ValueComparingNonnullRefPtr<StyleValue const> absolutized(ComputationContext const&) const override;
bool properties_equal(GridTrackSizeListStyleValue const& other) const { return m_grid_track_size_list == other.m_grid_track_size_list; }
private:

View file

@ -2,10 +2,10 @@ Harness status: OK
Found 25 tests
18 Pass
7 Fail
22 Pass
3 Fail
Pass Property grid-auto-columns value '1px'
Fail Property grid-auto-columns value 'calc(10px + 0.5em)'
Pass Property grid-auto-columns value 'calc(10px + 0.5em)'
Fail Property grid-auto-columns value 'calc(10px - 0.5em)'
Pass Property grid-auto-columns value '4%'
Pass Property grid-auto-columns value '5fr'
@ -13,13 +13,13 @@ Pass Property grid-auto-columns value 'min-content'
Pass Property grid-auto-columns value 'max-content'
Pass Property grid-auto-columns value 'auto'
Pass Property grid-auto-columns value 'minmax(1px, 5fr)'
Fail Property grid-auto-columns value 'minmax(calc(10px + 0.5em), max-content)'
Pass Property grid-auto-columns value 'minmax(calc(10px + 0.5em), max-content)'
Fail Property grid-auto-columns value 'minmax(calc(10px - 0.5em), max-content)'
Pass Property grid-auto-columns value 'minmax(4%, auto)'
Fail Property grid-auto-columns value 'minmax(min-content, calc(10px + 0.5em))'
Pass Property grid-auto-columns value 'minmax(min-content, calc(10px + 0.5em))'
Pass Property grid-auto-columns value 'minmax(auto, 4%)'
Pass Property grid-auto-columns value 'fit-content(1px)'
Fail Property grid-auto-columns value 'fit-content(calc(10px + 0.5em))'
Pass Property grid-auto-columns value 'fit-content(calc(10px + 0.5em))'
Fail Property grid-auto-columns value 'fit-content(calc(10px - 0.5em))'
Pass Property grid-auto-columns value 'fit-content(4%)'
Pass Property grid-auto-columns value '0px'

View file

@ -2,10 +2,10 @@ Harness status: OK
Found 25 tests
18 Pass
7 Fail
22 Pass
3 Fail
Pass Property grid-auto-rows value '1px'
Fail Property grid-auto-rows value 'calc(10px + 0.5em)'
Pass Property grid-auto-rows value 'calc(10px + 0.5em)'
Fail Property grid-auto-rows value 'calc(10px - 0.5em)'
Pass Property grid-auto-rows value '4%'
Pass Property grid-auto-rows value '5fr'
@ -13,13 +13,13 @@ Pass Property grid-auto-rows value 'min-content'
Pass Property grid-auto-rows value 'max-content'
Pass Property grid-auto-rows value 'auto'
Pass Property grid-auto-rows value 'minmax(1px, 5fr)'
Fail Property grid-auto-rows value 'minmax(calc(10px + 0.5em), max-content)'
Pass Property grid-auto-rows value 'minmax(calc(10px + 0.5em), max-content)'
Fail Property grid-auto-rows value 'minmax(calc(10px - 0.5em), max-content)'
Pass Property grid-auto-rows value 'minmax(4%, auto)'
Fail Property grid-auto-rows value 'minmax(min-content, calc(10px + 0.5em))'
Pass Property grid-auto-rows value 'minmax(min-content, calc(10px + 0.5em))'
Pass Property grid-auto-rows value 'minmax(auto, 4%)'
Pass Property grid-auto-rows value 'fit-content(1px)'
Fail Property grid-auto-rows value 'fit-content(calc(10px + 0.5em))'
Pass Property grid-auto-rows value 'fit-content(calc(10px + 0.5em))'
Fail Property grid-auto-rows value 'fit-content(calc(10px - 0.5em))'
Pass Property grid-auto-rows value 'fit-content(4%)'
Pass Property grid-auto-rows value '0px'

View file

@ -2,8 +2,7 @@ Harness status: OK
Found 32 tests
29 Pass
3 Fail
32 Pass
Pass Property grid-template-columns value 'none'
Pass Property grid-template-columns value '1px'
Pass Property grid-template-columns value '1px [a]'
@ -28,9 +27,9 @@ Pass Property grid-template-columns value '[a] 1px repeat(auto-fit, 2px [b] 3px)
Pass Property grid-template-rows value '100% [a] repeat(1, [b] 200% [c]) [d] 300%'
Pass Property grid-template-rows value '100% [a] repeat(auto-fill, [b] 200% [c]) [d] 300%'
Pass Property grid-template-rows value '100% [a] repeat(auto-fit, [b] 200% [c]) [d] 300%'
Fail Property grid-template-columns value '[a] 1em repeat(1, 2em [b] 3em) 4em [d]'
Fail Property grid-template-columns value '[a] 1em repeat(auto-fill, 2em [b] 3em) 4em [d]'
Fail Property grid-template-columns value '[a] 1em repeat(auto-fit, 2em [b] 3em) 4em [d]'
Pass Property grid-template-columns value '[a] 1em repeat(1, 2em [b] 3em) 4em [d]'
Pass Property grid-template-columns value '[a] 1em repeat(auto-fill, 2em [b] 3em) 4em [d]'
Pass Property grid-template-columns value '[a] 1em repeat(auto-fit, 2em [b] 3em) 4em [d]'
Pass Property grid-template-columns value 'repeat(1, 2px [a] 3px) [b] repeat(auto-fill, [c] 200% [d]) [e] 300%'
Pass Property grid-template-columns value '[a] repeat(auto-fill, [b] 200% [c]) repeat(1, 2px [d] 3px) [e] 300%'
Pass Property grid-template-columns value 'repeat(1, [a] 2px [b] 3px) [b] repeat(auto-fill, [c] 200% [d]) [e] 300%'

View file

@ -2,8 +2,7 @@ Harness status: OK
Found 24 tests
21 Pass
3 Fail
24 Pass
Pass Property grid-template-rows value 'none'
Pass Property grid-template-rows value '1px'
Pass Property grid-template-rows value '1px [a]'
@ -25,6 +24,6 @@ Pass Property grid-template-rows value '[a] 1px repeat(auto-fit, 2px [b] 3px) 4p
Pass Property grid-template-rows value '100% [a] repeat(1, [b] 200% [c]) [d] 300%'
Pass Property grid-template-rows value '100% [a] repeat(auto-fill, [b] 200% [c]) [d] 300%'
Pass Property grid-template-rows value '100% [a] repeat(auto-fit, [b] 200% [c]) [d] 300%'
Fail Property grid-template-rows value '[a] 1em repeat(1, 2em [b] 3em) 4em [d]'
Fail Property grid-template-rows value '[a] 1em repeat(auto-fill, 2em [b] 3em) 4em [d]'
Fail Property grid-template-rows value '[a] 1em repeat(auto-fit, 2em [b] 3em) 4em [d]'
Pass Property grid-template-rows value '[a] 1em repeat(1, 2em [b] 3em) 4em [d]'
Pass Property grid-template-rows value '[a] 1em repeat(auto-fill, 2em [b] 3em) 4em [d]'
Pass Property grid-template-rows value '[a] 1em repeat(auto-fit, 2em [b] 3em) 4em [d]'