LibWeb: Restrict CSS gap properties to values allowed by the spec

Gap values are now represented by Variant<LengthPercentage, NormalGap>.
NormalGap is just an empty struct to represent the `normal` keyword.

This fixes a long-standing issue where we were incorrectly storing gaps
as CSS::Size, which led to us allowing a bunch of invalid gap values.
This commit is contained in:
Andreas Kling 2024-11-09 17:38:09 +01:00 committed by Andreas Kling
commit 107b20e84d
Notes: github-actions[bot] 2024-11-09 18:23:29 +00:00
17 changed files with 157 additions and 120 deletions

View file

@ -96,7 +96,7 @@ clear: none
clip: auto clip: auto
clip-path: none clip-path: none
column-count: auto column-count: auto
column-gap: auto column-gap: normal
column-span: none column-span: none
column-width: auto column-width: auto
content: normal content: normal
@ -172,7 +172,7 @@ position: static
r: 0px r: 0px
right: auto right: auto
rotate: none rotate: none
row-gap: auto row-gap: normal
rx: auto rx: auto
ry: auto ry: auto
scrollbar-gutter: auto scrollbar-gutter: auto

View file

@ -6,24 +6,24 @@ Rerun
Found 18 tests Found 18 tests
5 Pass 16 Pass
13 Fail 2 Fail
Details Details
Result Test Name MessageFail Default column-gap is 'normal' Result Test Name MessagePass Default column-gap is 'normal'
Pass column-gap accepts pixels Pass column-gap accepts pixels
Pass column-gap accepts em Pass column-gap accepts em
Pass column-gap accepts vw Pass column-gap accepts vw
Pass column-gap accepts percentage Pass column-gap accepts percentage
Fail column-gap accepts calc() Fail column-gap accepts calc()
Fail column-gap accepts calc() mixing fixed and percentage values Fail column-gap accepts calc() mixing fixed and percentage values
Fail Initial column-gap is 'normal' Pass Initial column-gap is 'normal'
Fail Initial column-gap is 'normal' 2 Pass Initial column-gap is 'normal' 2
Fail Initial inherited column-gap is 'normal' Pass Initial inherited column-gap is 'normal'
Pass column-gap is inheritable Pass column-gap is inheritable
Fail Negative column-gap is invalid Pass Negative column-gap is invalid
Fail 'max-content' column-gap is invalid Pass 'max-content' column-gap is invalid
Fail 'none' column-gap is invalid Pass 'none' column-gap is invalid
Fail column-gap with multiple values is invalid Pass column-gap with multiple values is invalid
Fail Angle column-gap is invalid Pass Angle column-gap is invalid
Fail Resolution column-gap is invalid Pass Resolution column-gap is invalid
Fail Time column-gap is invalid Pass Time column-gap is invalid

View file

@ -6,11 +6,11 @@ Rerun
Found 6 tests Found 6 tests
6 Fail 6 Pass
Details Details
Result Test Name MessageFail colum-gap:normal computes to normal on multicol elements Result Test Name MessagePass colum-gap:normal computes to normal on multicol elements
Fail row-gap:normal computes to normal on multicol elements Pass row-gap:normal computes to normal on multicol elements
Fail colum-gap:normal computes to normal on grid Pass colum-gap:normal computes to normal on grid
Fail row-gap:normal computes to normal on grid Pass row-gap:normal computes to normal on grid
Fail colum-gap:normal (main axis) computes to normal on flexbox Pass colum-gap:normal (main axis) computes to normal on flexbox
Fail row-gap:normal (cross axis) computes to normal on flexbox Pass row-gap:normal (cross axis) computes to normal on flexbox

View file

@ -6,10 +6,10 @@ Rerun
Found 26 tests Found 26 tests
10 Pass 21 Pass
16 Fail 5 Fail
Details Details
Result Test Name MessageFail Default gap is 'normal' Result Test Name MessagePass Default gap is 'normal'
Pass gap accepts pixels Pass gap accepts pixels
Pass gap accepts pixels 2 Pass gap accepts pixels 2
Pass gap accepts pixels combined with percentage Pass gap accepts pixels combined with percentage
@ -22,16 +22,16 @@ Pass gap accepts percentage 2
Fail gap accepts calc() Fail gap accepts calc()
Fail gap accepts calc() mixing fixed and percentage values Fail gap accepts calc() mixing fixed and percentage values
Fail gap accepts calc() 2 Fail gap accepts calc() 2
Fail Initial gap is 'normal' Pass Initial gap is 'normal'
Fail Initial gap is 'normal' 2 Pass Initial gap is 'normal' 2
Fail Initial inherited gap is 'normal' Pass Initial inherited gap is 'normal'
Pass gap is inheritable Pass gap is inheritable
Fail Negative gap is invalid Pass Negative gap is invalid
Fail 'max-content' gap is invalid Pass 'max-content' gap is invalid
Fail 'none' gap is invalid Pass 'none' gap is invalid
Fail Angle gap is invalid Pass Angle gap is invalid
Fail Resolution gap is invalid Pass Resolution gap is invalid
Fail Time gap is invalid Pass Time gap is invalid
Fail gap with three values is invalid Pass gap with three values is invalid
Fail gap with slash is invalid Fail gap with slash is invalid
Fail gap with one wrong value is invalid Fail gap with one wrong value is invalid

View file

@ -6,22 +6,22 @@ Rerun
Found 16 tests Found 16 tests
2 Pass 6 Pass
14 Fail 10 Fail
Details Details
Result Test Name MessageFail e.style['gap'] = "normal" should set the property value Result Test Name MessageFail e.style['gap'] = "normal" should set the property value
Fail e.style['gap'] = "10px" should set the property value Fail e.style['gap'] = "10px" should set the property value
Fail e.style['gap'] = "normal normal" should set the property value Fail e.style['gap'] = "normal normal" should set the property value
Fail e.style['gap'] = "10px 10px" should set the property value Fail e.style['gap'] = "10px 10px" should set the property value
Fail e.style['column-gap'] = "normal" should set the property value Pass e.style['column-gap'] = "normal" should set the property value
Pass e.style['column-gap'] = "10px" should set the property value Pass e.style['column-gap'] = "10px" should set the property value
Fail e.style['row-gap'] = "normal" should set the property value Pass e.style['row-gap'] = "normal" should set the property value
Pass e.style['row-gap'] = "10px" should set the property value Pass e.style['row-gap'] = "10px" should set the property value
Fail 'row-gap: normal; column-gap: normal;' is serialized to 'gap: normal;' Fail 'row-gap: normal; column-gap: normal;' is serialized to 'gap: normal;'
Fail getPropertyValue for 'row-gap: normal; column-gap: normal;' returns 'normal' Fail getPropertyValue for 'row-gap: normal; column-gap: normal;' returns 'normal'
Fail 'row-gap: 10px; column-gap: 10px;' is serialized to 'gap: 10px;' Fail 'row-gap: 10px; column-gap: 10px;' is serialized to 'gap: 10px;'
Fail getPropertyValue for 'row-gap: 10px; column-gap: 10px;' returns '10px' Fail getPropertyValue for 'row-gap: 10px; column-gap: 10px;' returns '10px'
Fail 'row-gap: 10px; column-gap: normal;' is serialized to 'gap: 10px normal;' Fail 'row-gap: 10px; column-gap: normal;' is serialized to 'gap: 10px normal;'
Fail getPropertyValue for 'row-gap: 10px; column-gap: normal;' returns '10px normal' Pass getPropertyValue for 'row-gap: 10px; column-gap: normal;' returns '10px normal'
Fail 'column-gap: normal; row-gap: 10px;' is serialized to 'gap: 10px normal;' Fail 'column-gap: normal; row-gap: 10px;' is serialized to 'gap: 10px normal;'
Fail getPropertyValue for 'column-gap: normal; row-gap: 10px;' returns '10px normal' Pass getPropertyValue for 'column-gap: normal; row-gap: 10px;' returns '10px normal'

View file

@ -6,24 +6,24 @@ Rerun
Found 18 tests Found 18 tests
5 Pass 16 Pass
13 Fail 2 Fail
Details Details
Result Test Name MessageFail Default grid-column-gap is 'normal' Result Test Name MessagePass Default grid-column-gap is 'normal'
Pass grid-column-gap accepts pixels Pass grid-column-gap accepts pixels
Pass grid-column-gap accepts em Pass grid-column-gap accepts em
Pass grid-column-gap accepts vw Pass grid-column-gap accepts vw
Pass grid-column-gap accepts percentage Pass grid-column-gap accepts percentage
Fail grid-column-gap accepts calc() Fail grid-column-gap accepts calc()
Fail grid-column-gap accepts calc() mixing fixed and percentage values Fail grid-column-gap accepts calc() mixing fixed and percentage values
Fail Initial grid-column-gap is 'normal' Pass Initial grid-column-gap is 'normal'
Fail Initial grid-column-gap is 'normal' 2 Pass Initial grid-column-gap is 'normal' 2
Fail Initial inherited grid-column-gap is 'normal' Pass Initial inherited grid-column-gap is 'normal'
Pass grid-column-gap is inheritable Pass grid-column-gap is inheritable
Fail Negative grid-column-gap is invalid Pass Negative grid-column-gap is invalid
Fail 'max-content' grid-column-gap is invalid Pass 'max-content' grid-column-gap is invalid
Fail 'none' grid-column-gap is invalid Pass 'none' grid-column-gap is invalid
Fail grid-column-gap with multiple values is invalid Pass grid-column-gap with multiple values is invalid
Fail Angle grid-column-gap is invalid Pass Angle grid-column-gap is invalid
Fail Resolution grid-column-gap is invalid Pass Resolution grid-column-gap is invalid
Fail Time grid-column-gap is invalid Pass Time grid-column-gap is invalid

View file

@ -6,10 +6,10 @@ Rerun
Found 26 tests Found 26 tests
10 Pass 21 Pass
16 Fail 5 Fail
Details Details
Result Test Name MessageFail Default grid-gap is 'normal' Result Test Name MessagePass Default grid-gap is 'normal'
Pass grid-gap accepts pixels Pass grid-gap accepts pixels
Pass grid-gap accepts pixels 2 Pass grid-gap accepts pixels 2
Pass grid-gap accepts pixels combined with percentage Pass grid-gap accepts pixels combined with percentage
@ -22,16 +22,16 @@ Pass grid-gap accepts percentage 2
Fail grid-gap accepts calc() Fail grid-gap accepts calc()
Fail grid-gap accepts calc() mixing fixed and percentage values Fail grid-gap accepts calc() mixing fixed and percentage values
Fail grid-gap accepts calc() 2 Fail grid-gap accepts calc() 2
Fail Initial grid-gap is 'normal' Pass Initial grid-gap is 'normal'
Fail Initial grid-gap is 'normal' 2 Pass Initial grid-gap is 'normal' 2
Fail Initial inherited grid-gap is 'normal' Pass Initial inherited grid-gap is 'normal'
Pass grid-gap is inheritable Pass grid-gap is inheritable
Fail Negative grid-gap is invalid Pass Negative grid-gap is invalid
Fail 'max-content' grid-gap is invalid Pass 'max-content' grid-gap is invalid
Fail 'none' grid-gap is invalid Pass 'none' grid-gap is invalid
Fail Angle grid-gap is invalid Pass Angle grid-gap is invalid
Fail Resolution grid-gap is invalid Pass Resolution grid-gap is invalid
Fail Time grid-gap is invalid Pass Time grid-gap is invalid
Fail grid-gap with three values is invalid Pass grid-gap with three values is invalid
Fail grid-gap with slash is invalid Fail grid-gap with slash is invalid
Fail grid-gap with one wrong value is invalid Fail grid-gap with one wrong value is invalid

View file

@ -6,24 +6,24 @@ Rerun
Found 18 tests Found 18 tests
5 Pass 16 Pass
13 Fail 2 Fail
Details Details
Result Test Name MessageFail Default grid-row-gap is 'normal' Result Test Name MessagePass Default grid-row-gap is 'normal'
Pass grid-row-gap accepts pixels Pass grid-row-gap accepts pixels
Pass grid-row-gap accepts em Pass grid-row-gap accepts em
Pass grid-row-gap accepts vw Pass grid-row-gap accepts vw
Pass grid-row-gap accepts percentage Pass grid-row-gap accepts percentage
Fail grid-row-gap accepts calc() Fail grid-row-gap accepts calc()
Fail grid-row-gap accepts calc() mixing fixed and percentage values Fail grid-row-gap accepts calc() mixing fixed and percentage values
Fail Initial grid-row-gap is 'normal' Pass Initial grid-row-gap is 'normal'
Fail Initial grid-row-gap is 'normal' 2 Pass Initial grid-row-gap is 'normal' 2
Fail Initial inherited grid-row-gap is 'normal' Pass Initial inherited grid-row-gap is 'normal'
Pass grid-row-gap is inheritable Pass grid-row-gap is inheritable
Fail Negative grid-row-gap is invalid Pass Negative grid-row-gap is invalid
Fail 'max-content' grid-row-gap is invalid Pass 'max-content' grid-row-gap is invalid
Fail 'none' grid-row-gap is invalid Pass 'none' grid-row-gap is invalid
Fail grid-row-gap with multiple values is invalid Pass grid-row-gap with multiple values is invalid
Fail Angle grid-row-gap is invalid Pass Angle grid-row-gap is invalid
Fail Resolution grid-row-gap is invalid Pass Resolution grid-row-gap is invalid
Fail Time grid-row-gap is invalid Pass Time grid-row-gap is invalid

View file

@ -6,24 +6,24 @@ Rerun
Found 18 tests Found 18 tests
5 Pass 16 Pass
13 Fail 2 Fail
Details Details
Result Test Name MessageFail Default row-gap is 'normal' Result Test Name MessagePass Default row-gap is 'normal'
Pass row-gap accepts pixels Pass row-gap accepts pixels
Pass row-gap accepts em Pass row-gap accepts em
Pass row-gap accepts vw Pass row-gap accepts vw
Pass row-gap accepts percentage Pass row-gap accepts percentage
Fail row-gap accepts calc() Fail row-gap accepts calc()
Fail row-gap accepts calc() mixing fixed and percentage values Fail row-gap accepts calc() mixing fixed and percentage values
Fail Initial row-gap is 'normal' Pass Initial row-gap is 'normal'
Fail Initial row-gap is 'normal' 2 Pass Initial row-gap is 'normal' 2
Fail Initial inherited row-gap is 'normal' Pass Initial inherited row-gap is 'normal'
Pass row-gap is inheritable Pass row-gap is inheritable
Fail Negative row-gap is invalid Pass Negative row-gap is invalid
Fail 'max-content' row-gap is invalid Pass 'max-content' row-gap is invalid
Fail 'none' row-gap is invalid Pass 'none' row-gap is invalid
Fail row-gap with multiple values is invalid Pass row-gap with multiple values is invalid
Fail Angle row-gap is invalid Pass Angle row-gap is invalid
Fail Resolution row-gap is invalid Pass Resolution row-gap is invalid
Fail Time row-gap is invalid Pass Time row-gap is invalid

View file

@ -46,6 +46,8 @@ struct GridAutoFlow {
bool dense { false }; bool dense { false };
}; };
struct NormalGap { };
struct QuotesData { struct QuotesData {
enum class Type { enum class Type {
None, None,
@ -173,10 +175,10 @@ public:
static CSS::GridTrackPlacement grid_row_start() { return CSS::GridTrackPlacement::make_auto(); } static CSS::GridTrackPlacement grid_row_start() { return CSS::GridTrackPlacement::make_auto(); }
static CSS::GridAutoFlow grid_auto_flow() { return CSS::GridAutoFlow {}; } static CSS::GridAutoFlow grid_auto_flow() { return CSS::GridAutoFlow {}; }
static ColumnCount column_count() { return ColumnCount::make_auto(); } static ColumnCount column_count() { return ColumnCount::make_auto(); }
static CSS::Size column_gap() { return CSS::Size::make_auto(); } static Variant<LengthPercentage, NormalGap> column_gap() { return NormalGap {}; }
static CSS::ColumnSpan column_span() { return CSS::ColumnSpan::None; } static CSS::ColumnSpan column_span() { return CSS::ColumnSpan::None; }
static CSS::Size column_width() { return CSS::Size::make_auto(); } static CSS::Size column_width() { return CSS::Size::make_auto(); }
static CSS::Size row_gap() { return CSS::Size::make_auto(); } static Variant<LengthPercentage, NormalGap> row_gap() { return NormalGap {}; }
static CSS::BorderCollapse border_collapse() { return CSS::BorderCollapse::Separate; } static CSS::BorderCollapse border_collapse() { return CSS::BorderCollapse::Separate; }
static Vector<Vector<String>> grid_template_areas() { return {}; } static Vector<Vector<String>> grid_template_areas() { return {}; }
static CSS::Time transition_delay() { return CSS::Time::make_seconds(0); } static CSS::Time transition_delay() { return CSS::Time::make_seconds(0); }
@ -434,10 +436,10 @@ public:
CSS::GridTrackPlacement const& grid_row_end() const { return m_noninherited.grid_row_end; } CSS::GridTrackPlacement const& grid_row_end() const { return m_noninherited.grid_row_end; }
CSS::GridTrackPlacement const& grid_row_start() const { return m_noninherited.grid_row_start; } CSS::GridTrackPlacement const& grid_row_start() const { return m_noninherited.grid_row_start; }
CSS::ColumnCount column_count() const { return m_noninherited.column_count; } CSS::ColumnCount column_count() const { return m_noninherited.column_count; }
CSS::Size const& column_gap() const { return m_noninherited.column_gap; } Variant<LengthPercentage, NormalGap> const& column_gap() const { return m_noninherited.column_gap; }
CSS::ColumnSpan const& column_span() const { return m_noninherited.column_span; } CSS::ColumnSpan const& column_span() const { return m_noninherited.column_span; }
CSS::Size const& column_width() const { return m_noninherited.column_width; } CSS::Size const& column_width() const { return m_noninherited.column_width; }
CSS::Size const& row_gap() const { return m_noninherited.row_gap; } Variant<LengthPercentage, NormalGap> const& row_gap() const { return m_noninherited.row_gap; }
CSS::BorderCollapse border_collapse() const { return m_inherited.border_collapse; } CSS::BorderCollapse border_collapse() const { return m_inherited.border_collapse; }
Vector<Vector<String>> const& grid_template_areas() const { return m_noninherited.grid_template_areas; } Vector<Vector<String>> const& grid_template_areas() const { return m_noninherited.grid_template_areas; }
CSS::ObjectFit object_fit() const { return m_noninherited.object_fit; } CSS::ObjectFit object_fit() const { return m_noninherited.object_fit; }
@ -658,10 +660,10 @@ protected:
CSS::GridTrackPlacement grid_row_end { InitialValues::grid_row_end() }; CSS::GridTrackPlacement grid_row_end { InitialValues::grid_row_end() };
CSS::GridTrackPlacement grid_row_start { InitialValues::grid_row_start() }; CSS::GridTrackPlacement grid_row_start { InitialValues::grid_row_start() };
CSS::ColumnCount column_count { InitialValues::column_count() }; CSS::ColumnCount column_count { InitialValues::column_count() };
CSS::Size column_gap { InitialValues::column_gap() }; Variant<LengthPercentage, NormalGap> column_gap { InitialValues::column_gap() };
CSS::ColumnSpan column_span { InitialValues::column_span() }; CSS::ColumnSpan column_span { InitialValues::column_span() };
CSS::Size column_width { InitialValues::column_width() }; CSS::Size column_width { InitialValues::column_width() };
CSS::Size row_gap { InitialValues::row_gap() }; Variant<LengthPercentage, NormalGap> row_gap { InitialValues::row_gap() };
Vector<Vector<String>> grid_template_areas { InitialValues::grid_template_areas() }; Vector<Vector<String>> grid_template_areas { InitialValues::grid_template_areas() };
Gfx::Color stop_color { InitialValues::stop_color() }; Gfx::Color stop_color { InitialValues::stop_color() };
float stop_opacity { InitialValues::stop_opacity() }; float stop_opacity { InitialValues::stop_opacity() };
@ -802,10 +804,10 @@ public:
void set_grid_row_end(CSS::GridTrackPlacement value) { m_noninherited.grid_row_end = value; } void set_grid_row_end(CSS::GridTrackPlacement value) { m_noninherited.grid_row_end = value; }
void set_grid_row_start(CSS::GridTrackPlacement value) { m_noninherited.grid_row_start = value; } void set_grid_row_start(CSS::GridTrackPlacement value) { m_noninherited.grid_row_start = value; }
void set_column_count(CSS::ColumnCount value) { m_noninherited.column_count = value; } void set_column_count(CSS::ColumnCount value) { m_noninherited.column_count = value; }
void set_column_gap(CSS::Size const& column_gap) { m_noninherited.column_gap = column_gap; } void set_column_gap(Variant<LengthPercentage, NormalGap> const& column_gap) { m_noninherited.column_gap = column_gap; }
void set_column_span(CSS::ColumnSpan const& column_span) { m_noninherited.column_span = column_span; } void set_column_span(CSS::ColumnSpan const& column_span) { m_noninherited.column_span = column_span; }
void set_column_width(CSS::Size const& column_width) { m_noninherited.column_width = column_width; } void set_column_width(CSS::Size const& column_width) { m_noninherited.column_width = column_width; }
void set_row_gap(CSS::Size const& row_gap) { m_noninherited.row_gap = row_gap; } void set_row_gap(Variant<LengthPercentage, NormalGap> const& row_gap) { m_noninherited.row_gap = row_gap; }
void set_border_collapse(CSS::BorderCollapse const& border_collapse) { m_inherited.border_collapse = border_collapse; } void set_border_collapse(CSS::BorderCollapse const& border_collapse) { m_inherited.border_collapse = border_collapse; }
void set_grid_template_areas(Vector<Vector<String>> const& grid_template_areas) { m_noninherited.grid_template_areas = grid_template_areas; } void set_grid_template_areas(Vector<Vector<String>> const& grid_template_areas) { m_noninherited.grid_template_areas = grid_template_areas; }
void set_grid_auto_flow(CSS::GridAutoFlow grid_auto_flow) { m_noninherited.grid_auto_flow = grid_auto_flow; } void set_grid_auto_flow(CSS::GridAutoFlow grid_auto_flow) { m_noninherited.grid_auto_flow = grid_auto_flow; }

View file

@ -874,13 +874,13 @@
"column-gap": { "column-gap": {
"animation-type": "by-computed-value", "animation-type": "by-computed-value",
"inherited": false, "inherited": false,
"initial": "auto", "initial": "normal",
"valid-types": [ "valid-types": [
"length [0,∞]", "length [0,∞]",
"percentage [0,∞]" "percentage [0,∞]"
], ],
"valid-identifiers": [ "valid-identifiers": [
"auto" "normal"
], ],
"percentages-resolve-to": "length" "percentages-resolve-to": "length"
}, },
@ -1284,14 +1284,14 @@
}, },
"gap": { "gap": {
"inherited": false, "inherited": false,
"initial": "auto", "initial": "normal",
"valid-types": [ "valid-types": [
"length [0,∞]", "length [0,∞]",
"percentage [0,∞]" "percentage [0,∞]"
], ],
"max-values": 2, "max-values": 2,
"valid-identifiers": [ "valid-identifiers": [
"auto" "normal"
], ],
"percentages-resolve-to": "length", "percentages-resolve-to": "length",
"longhands": [ "longhands": [
@ -2311,13 +2311,13 @@
"row-gap": { "row-gap": {
"animation-type": "by-computed-value", "animation-type": "by-computed-value",
"inherited": false, "inherited": false,
"initial": "auto", "initial": "normal",
"valid-types": [ "valid-types": [
"length [0,∞]", "length [0,∞]",
"percentage [0,∞]" "percentage [0,∞]"
], ],
"valid-identifiers": [ "valid-identifiers": [
"auto" "normal"
], ],
"percentages-resolve-to": "length" "percentages-resolve-to": "length"
}, },

View file

@ -127,6 +127,26 @@ CSSStyleValue const* StyleProperties::maybe_null_property(CSS::PropertyID proper
return m_data->m_property_values[to_underlying(property_id)]; return m_data->m_property_values[to_underlying(property_id)];
} }
Variant<LengthPercentage, NormalGap> StyleProperties::gap_value(CSS::PropertyID id) const
{
auto const& value = property(id);
if (value.is_keyword()) {
VERIFY(value.as_keyword().keyword() == CSS::Keyword::Normal);
return NormalGap {};
}
if (value.is_math())
return LengthPercentage { const_cast<CSSMathValue&>(value.as_math()) };
if (value.is_percentage())
return LengthPercentage { value.as_percentage().percentage() };
if (value.is_length())
return LengthPercentage { value.as_length().length() };
VERIFY_NOT_REACHED();
}
CSS::Size StyleProperties::size_value(CSS::PropertyID id) const CSS::Size StyleProperties::size_value(CSS::PropertyID id) const
{ {
auto const& value = property(id); auto const& value = property(id);

View file

@ -87,6 +87,7 @@ public:
void set_transition_property_source(JS::GCPtr<CSS::CSSStyleDeclaration const> declaration) { m_data->m_transition_property_source = declaration; } void set_transition_property_source(JS::GCPtr<CSS::CSSStyleDeclaration const> declaration) { m_data->m_transition_property_source = declaration; }
CSS::Size size_value(CSS::PropertyID) const; CSS::Size size_value(CSS::PropertyID) const;
[[nodiscard]] Variant<LengthPercentage, NormalGap> gap_value(CSS::PropertyID) const;
LengthPercentage length_percentage_or_fallback(CSS::PropertyID, LengthPercentage const& fallback) const; LengthPercentage length_percentage_or_fallback(CSS::PropertyID, LengthPercentage const& fallback) const;
Optional<LengthPercentage> length_percentage(CSS::PropertyID) const; Optional<LengthPercentage> length_percentage(CSS::PropertyID) const;
LengthBox length_box(CSS::PropertyID left_id, CSS::PropertyID top_id, CSS::PropertyID right_id, CSS::PropertyID bottom_id, const CSS::Length& default_value) const; LengthBox length_box(CSS::PropertyID left_id, CSS::PropertyID top_id, CSS::PropertyID right_id, CSS::PropertyID bottom_id, const CSS::Length& default_value) const;

View file

@ -2292,18 +2292,25 @@ double FlexFormattingContext::FlexLine::sum_of_scaled_flex_shrink_factor_of_unfr
return sum; return sum;
} }
static CSSPixels gap_to_px(Variant<CSS::LengthPercentage, CSS::NormalGap> const& gap, Layout::Node const& grid_container, CSSPixels reference_value)
{
return gap.visit(
[](CSS::NormalGap) { return CSSPixels(0); },
[&](auto const& gap) { return gap.to_px(grid_container, reference_value); });
}
CSSPixels FlexFormattingContext::main_gap() const CSSPixels FlexFormattingContext::main_gap() const
{ {
auto const& computed_values = flex_container().computed_values(); auto const& computed_values = flex_container().computed_values();
auto gap = is_row_layout() ? computed_values.column_gap() : computed_values.row_gap(); auto const& gap = is_row_layout() ? computed_values.column_gap() : computed_values.row_gap();
return gap.to_px(flex_container(), inner_main_size(m_flex_container_state)); return gap_to_px(gap, flex_container(), inner_main_size(m_flex_container_state));
} }
CSSPixels FlexFormattingContext::cross_gap() const CSSPixels FlexFormattingContext::cross_gap() const
{ {
auto const& computed_values = flex_container().computed_values(); auto const& computed_values = flex_container().computed_values();
auto gap = is_row_layout() ? computed_values.row_gap() : computed_values.column_gap(); auto gap = is_row_layout() ? computed_values.row_gap() : computed_values.column_gap();
return gap.to_px(flex_container(), inner_cross_size(m_flex_container_state)); return gap_to_px(gap, flex_container(), inner_cross_size(m_flex_container_state));
} }
} }

View file

@ -12,6 +12,13 @@
namespace Web::Layout { namespace Web::Layout {
static CSSPixels gap_to_px(Variant<CSS::LengthPercentage, CSS::NormalGap> const& gap, Layout::Node const& grid_container, CSSPixels reference_value)
{
return gap.visit(
[](CSS::NormalGap) { return CSSPixels(0); },
[&](auto const& gap) { return gap.to_px(grid_container, reference_value); });
}
static Alignment to_alignment(CSS::JustifyContent value) static Alignment to_alignment(CSS::JustifyContent value)
{ {
switch (value) { switch (value) {
@ -192,7 +199,7 @@ int GridFormattingContext::count_of_repeated_auto_fill_or_fit_tracks(GridDimensi
auto const& available_size = dimension == GridDimension::Column ? m_available_space->width : m_available_space->height; auto const& available_size = dimension == GridDimension::Column ? m_available_space->width : m_available_space->height;
auto free_space = get_free_space(*m_available_space, dimension).to_px_or_zero(); auto free_space = get_free_space(*m_available_space, dimension).to_px_or_zero();
auto const& gap = dimension == GridDimension::Column ? grid_computed_values.column_gap() : grid_computed_values.row_gap(); auto const& gap = dimension == GridDimension::Column ? grid_computed_values.column_gap() : grid_computed_values.row_gap();
auto gap_px = gap.to_px(grid_container(), available_size.to_px_or_zero()); auto gap_px = gap_to_px(gap, grid_container(), available_size.to_px_or_zero());
auto size_of_repeated_tracks_with_gap = size_of_repeated_tracks + repeat_track_list.size() * gap_px; auto size_of_repeated_tracks_with_gap = size_of_repeated_tracks + repeat_track_list.size() * gap_px;
// If any number of repetitions would overflow, then 1 repetition. // If any number of repetitions would overflow, then 1 repetition.
if (free_space <= size_of_repeated_tracks_with_gap) { if (free_space <= size_of_repeated_tracks_with_gap) {
@ -564,8 +571,8 @@ void GridFormattingContext::initialize_gap_tracks(AvailableSpace const& availabl
// line. // line.
if (m_grid_columns.size() > 0) { if (m_grid_columns.size() > 0) {
CSSPixels column_gap_width = 0; CSSPixels column_gap_width = 0;
if (!grid_container().computed_values().column_gap().is_auto()) { if (!grid_container().computed_values().column_gap().has<CSS::NormalGap>()) {
column_gap_width = grid_container().computed_values().column_gap().to_px(grid_container(), available_space.width.to_px_or_zero()); column_gap_width = gap_to_px(grid_container().computed_values().column_gap(), grid_container(), available_space.width.to_px_or_zero());
} }
m_column_gap_tracks.ensure_capacity(m_grid_columns.size() - 1); m_column_gap_tracks.ensure_capacity(m_grid_columns.size() - 1);
@ -582,8 +589,8 @@ void GridFormattingContext::initialize_gap_tracks(AvailableSpace const& availabl
if (m_grid_rows.size() > 0) { if (m_grid_rows.size() > 0) {
CSSPixels row_gap_height = 0; CSSPixels row_gap_height = 0;
if (!grid_container().computed_values().row_gap().is_auto()) { if (!grid_container().computed_values().row_gap().has<CSS::NormalGap>()) {
row_gap_height = grid_container().computed_values().row_gap().to_px(grid_container(), available_space.height.to_px_or_zero()); row_gap_height = gap_to_px(grid_container().computed_values().row_gap(), grid_container(), available_space.height.to_px_or_zero());
} }
m_row_gap_tracks.ensure_capacity(m_grid_rows.size() - 1); m_row_gap_tracks.ensure_capacity(m_grid_rows.size() - 1);
@ -1775,7 +1782,7 @@ void GridFormattingContext::resolve_track_spacing(GridDimension const dimension)
auto const& computed_gap = is_column_dimension ? grid_container().computed_values().column_gap() : grid_container().computed_values().row_gap(); auto const& computed_gap = is_column_dimension ? grid_container().computed_values().column_gap() : grid_container().computed_values().row_gap();
auto const& available_size = is_column_dimension ? m_available_space->width.to_px_or_zero() : m_available_space->height.to_px_or_zero(); auto const& available_size = is_column_dimension ? m_available_space->width.to_px_or_zero() : m_available_space->height.to_px_or_zero();
space_between_tracks = max(space_between_tracks, computed_gap.to_px(grid_container(), available_size)); space_between_tracks = max(space_between_tracks, gap_to_px(computed_gap, grid_container(), available_size));
auto& gap_tracks = is_column_dimension ? m_column_gap_tracks : m_row_gap_tracks; auto& gap_tracks = is_column_dimension ? m_column_gap_tracks : m_row_gap_tracks;
for (auto& track : gap_tracks) { for (auto& track : gap_tracks) {

View file

@ -185,9 +185,9 @@ private:
bool has_gaps(GridDimension const dimension) const bool has_gaps(GridDimension const dimension) const
{ {
if (dimension == GridDimension::Column) { if (dimension == GridDimension::Column) {
return !grid_container().computed_values().column_gap().is_auto(); return !grid_container().computed_values().column_gap().has<CSS::NormalGap>();
} else { } else {
return !grid_container().computed_values().row_gap().is_auto(); return !grid_container().computed_values().row_gap().has<CSS::NormalGap>();
} }
} }

View file

@ -869,8 +869,8 @@ void NodeWithStyle::apply_style(const CSS::StyleProperties& computed_style)
computed_values.set_column_width(computed_style.size_value(CSS::PropertyID::ColumnWidth)); computed_values.set_column_width(computed_style.size_value(CSS::PropertyID::ColumnWidth));
computed_values.set_column_gap(computed_style.size_value(CSS::PropertyID::ColumnGap)); computed_values.set_column_gap(computed_style.gap_value(CSS::PropertyID::ColumnGap));
computed_values.set_row_gap(computed_style.size_value(CSS::PropertyID::RowGap)); computed_values.set_row_gap(computed_style.gap_value(CSS::PropertyID::RowGap));
if (auto border_collapse = computed_style.border_collapse(); border_collapse.has_value()) if (auto border_collapse = computed_style.border_collapse(); border_collapse.has_value())
computed_values.set_border_collapse(border_collapse.value()); computed_values.set_border_collapse(border_collapse.value());