LibWeb: Parse CSS grid subgrid track listings

Parse subgrid track listings for grid-template rows and columns,
including fixed and auto-fill name-repeat line-name lists. Preserve
the subgrid keyword through computed values and shorthand serialization,
and make interpolation discrete instead of routing subgrid lists through
the explicit track interpolation path.

Import WPT coverage for subgrid grid-template parsing and computed
values, and add text coverage for discrete subgrid track-list animation.
This commit is contained in:
Andreas Kling 2026-05-25 11:37:34 +02:00 committed by Alexander Kalenik
parent ceb25e10d4
commit 19e5b57672
15 changed files with 484 additions and 3 deletions

View file

@ -239,8 +239,30 @@ GridTrackSizeList GridTrackSizeList::make_none()
return GridTrackSizeList();
}
GridTrackSizeList GridTrackSizeList::make_line_name_list()
{
GridTrackSizeList list;
list.m_preserve_line_name_sets = true;
return list;
}
GridTrackSizeList GridTrackSizeList::make_subgrid()
{
GridTrackSizeList list;
list.m_is_subgrid = true;
list.m_preserve_line_name_sets = true;
return list;
}
void GridTrackSizeList::serialize(StringBuilder& builder, SerializationMode mode) const
{
if (m_is_subgrid) {
builder.append("subgrid"sv);
if (m_list.is_empty())
return;
builder.append(" "sv);
}
if (m_list.is_empty()) {
builder.append("none"sv);
return;
@ -280,6 +302,11 @@ bool GridTrackSizeList::operator==(GridTrackSizeList const& other) const = defau
void GridTrackSizeList::append(GridLineNames&& line_names)
{
if (m_preserve_line_name_sets) {
m_list.append(move(line_names));
return;
}
if (!m_list.is_empty() && m_list.last().has<GridLineNames>()) {
auto& last_line_names = m_list.last().get<GridLineNames>();
for (auto const& name : line_names.names())
@ -297,6 +324,8 @@ void GridTrackSizeList::append(ExplicitGridTrack&& explicit_track)
GridTrackSizeList GridTrackSizeList::absolutized(ComputationContext const& context) const
{
GridTrackSizeList result;
result.m_is_subgrid = m_is_subgrid;
result.m_preserve_line_name_sets = m_preserve_line_name_sets;
for (auto const& item : m_list) {
item.visit(
[&result, &context](ExplicitGridTrack const& track) {

View file

@ -78,6 +78,7 @@ private:
struct GridLineName {
FlyString name;
bool implicit { false };
bool adopted_from_parent_grid { false };
bool operator==(GridLineName const& other) const = default;
};
@ -118,15 +119,18 @@ private:
class GridTrackSizeList {
public:
static GridTrackSizeList make_none();
static GridTrackSizeList make_line_name_list();
static GridTrackSizeList make_subgrid();
Vector<CSS::ExplicitGridTrack> track_list() const;
auto const& list() const { return m_list; }
bool is_subgrid() const { return m_is_subgrid; }
void serialize(StringBuilder&, SerializationMode) const;
String to_string(SerializationMode) const;
bool operator==(GridTrackSizeList const& other) const;
bool is_empty() const { return m_list.is_empty(); }
bool is_empty() const { return !m_is_subgrid && m_list.is_empty(); }
void append(GridLineNames&&);
void append(ExplicitGridTrack&&);
@ -136,6 +140,8 @@ public:
bool is_computationally_independent() const;
private:
bool m_is_subgrid { false };
bool m_preserve_line_name_sets { false };
Vector<Variant<ExplicitGridTrack, GridLineNames>> m_list;
};

View file

@ -577,6 +577,15 @@ static void append_grid_track_with_line_names(GridTrackSizeList& list, ExplicitG
static Optional<GridTrackSizeList> interpolate_grid_track_size_list(DOM::Element& element, CalculationContext const& calculation_context, GridTrackSizeList const& from, GridTrackSizeList const& to, float delta)
{
// https://drafts.csswg.org/css-grid-2/#track-sizing
// Animation type: if the list lengths match, by computed value type per item in the computed track list;
// discrete otherwise.
//
// https://drafts.csswg.org/css-grid-2/#computed-track-list-subgrid
// The computed track list of a subgrid axis is the subgrid keyword followed by a list of line names.
if (from.is_subgrid() || to.is_subgrid())
return {};
auto interpolate_grid_size = [&](GridSize const& from_grid_size, GridSize const& to_grid_size) -> GridSize {
return GridSize { *interpolate_value(element, calculation_context, from_grid_size.style_value(), to_grid_size.style_value(), delta, AllowDiscrete::Yes) };
};
@ -2260,6 +2269,15 @@ static T composite_raw_values(T underlying_raw_value, T animated_raw_value)
static Optional<GridTrackSizeList> composite_grid_track_size_list(PropertyID property_id, CalculationContext const& calculation_context, GridTrackSizeList const& underlying, GridTrackSizeList const& animated, Bindings::CompositeOperation composite_operation)
{
// https://drafts.csswg.org/css-grid-2/#track-sizing
// Animation type: if the list lengths match, by computed value type per item in the computed track list;
// discrete otherwise.
//
// https://drafts.csswg.org/css-grid-2/#computed-track-list-subgrid
// The computed track list of a subgrid axis is the subgrid keyword followed by a list of line names.
if (underlying.is_subgrid() || animated.is_subgrid())
return {};
auto composite_grid_size = [&](GridSize const& underlying_grid_size, GridSize const& animated_grid_size) -> Optional<GridSize> {
if (auto composited_value = composite_value(property_id, underlying_grid_size.style_value(), animated_grid_size.style_value(), composite_operation))
return GridSize { *composited_value };

View file

@ -343,6 +343,7 @@ private:
Optional<GridRepeat> parse_grid_track_repeat(TokenStream<ComponentValue>&);
Optional<GridRepeat> parse_grid_auto_repeat(TokenStream<ComponentValue>&);
Optional<GridRepeat> parse_grid_fixed_repeat(TokenStream<ComponentValue>&);
Optional<GridRepeat> parse_grid_name_repeat(TokenStream<ComponentValue>&);
using GridRepeatTypeParser = AK::Function<Optional<GridRepeatParams>(TokenStream<ComponentValue>&)>;
using GridTrackParser = AK::Function<Optional<ExplicitGridTrack>(TokenStream<ComponentValue>&)>;

View file

@ -5334,7 +5334,7 @@ RefPtr<GridAutoFlowStyleValue const> Parser::parse_grid_auto_flow_value(TokenStr
// https://www.w3.org/TR/css-grid-2/#track-sizing
RefPtr<StyleValue const> Parser::parse_grid_track_size_list(TokenStream<ComponentValue>& tokens)
{
// none | <track-list> | <auto-track-list> | FIXME: subgrid <line-name-list>?
// none | <track-list> | <auto-track-list> | subgrid <line-name-list>?
// none
{
@ -5347,6 +5347,40 @@ RefPtr<StyleValue const> Parser::parse_grid_track_size_list(TokenStream<Componen
}
}
// subgrid <line-name-list>?
{
auto transaction = tokens.begin_transaction();
tokens.discard_whitespace();
if (tokens.has_next_token() && tokens.next_token().is_ident("subgrid"sv)) {
tokens.discard_a_token(); // subgrid
auto track_list = GridTrackSizeList::make_subgrid();
bool has_auto_fill_repeat = false;
tokens.discard_whitespace();
while (tokens.has_next_token()) {
if (tokens.next_token().is_block() && tokens.next_token().block().is_square()) {
auto line_names = parse_grid_line_names(tokens);
if (!line_names.has_value())
return nullptr;
track_list.append(line_names.release_value());
} else if (auto name_repeat = parse_grid_name_repeat(tokens); name_repeat.has_value()) {
if (name_repeat->is_auto_fill()) {
if (has_auto_fill_repeat)
return nullptr;
has_auto_fill_repeat = true;
}
track_list.append(ExplicitGridTrack(name_repeat.release_value()));
} else {
return nullptr;
}
tokens.discard_whitespace();
}
transaction.commit();
return GridTrackSizeListStyleValue::create(move(track_list));
}
}
// <auto-track-list>
if (auto auto_track_list = parse_grid_auto_track_list(tokens); !auto_track_list.is_empty()) {
return GridTrackSizeListStyleValue::create(GridTrackSizeList(move(auto_track_list)));

View file

@ -4642,6 +4642,67 @@ Optional<GridRepeat> Parser::parse_grid_fixed_repeat(TokenStream<ComponentValue>
return parse_grid_track_repeat_impl(tokens, parse_repeat_type, parse_track);
}
// https://drafts.csswg.org/css-grid-2/#typedef-name-repeat
Optional<GridRepeat> Parser::parse_grid_name_repeat(TokenStream<ComponentValue>& tokens)
{
// <name-repeat> = repeat( [ <integer [1,∞]> | auto-fill ] , <line-names>+ )
auto transaction = tokens.begin_transaction();
tokens.discard_whitespace();
if (!tokens.has_next_token())
return {};
auto const& token = tokens.consume_a_token();
if (!token.is_function())
return {};
auto const& function_token = token.function();
if (!function_token.name.equals_ignoring_ascii_case("repeat"sv))
return {};
auto context_guard = push_temporary_value_parsing_context(FunctionContext { function_token.name });
auto function_tokens = TokenStream(function_token.value);
auto comma_separated_list = parse_a_comma_separated_list_of_component_values(function_tokens);
if (comma_separated_list.size() != 2)
return {};
TokenStream first_arg_tokens { comma_separated_list[0] };
first_arg_tokens.discard_whitespace();
Optional<GridRepeatParams> repeat_params;
if (auto maybe_integer = parse_integer_value(first_arg_tokens, { .min = 1, .max = NumericLimits<i32>::max() })) {
repeat_params = GridRepeatParams { GridRepeatType::Fixed, maybe_integer };
} else if (first_arg_tokens.has_next_token() && first_arg_tokens.next_token().is_ident("auto-fill"sv)) {
first_arg_tokens.discard_a_token(); // auto-fill
repeat_params = GridRepeatParams { GridRepeatType::AutoFill };
} else {
return {};
}
first_arg_tokens.discard_whitespace();
if (first_arg_tokens.has_next_token())
return {};
TokenStream second_arg_tokens { comma_separated_list[1] };
GridTrackSizeList line_name_list = GridTrackSizeList::make_line_name_list();
size_t parsed_line_name_count = 0;
second_arg_tokens.discard_whitespace();
while (second_arg_tokens.has_next_token()) {
if (!second_arg_tokens.next_token().is_block() || !second_arg_tokens.next_token().block().is_square())
return {};
auto line_names = parse_grid_line_names(second_arg_tokens);
if (!line_names.has_value())
return {};
line_name_list.append(line_names.release_value());
++parsed_line_name_count;
second_arg_tokens.discard_whitespace();
}
if (parsed_line_name_count == 0)
return {};
transaction.commit();
return GridRepeat(move(line_name_list), repeat_params.release_value());
}
// https://www.w3.org/TR/css-grid-2/#typedef-track-size
Optional<ExplicitGridTrack> Parser::parse_grid_track_size(TokenStream<ComponentValue>& tokens)
{

View file

@ -749,7 +749,7 @@ void ShorthandStyleValue::serialize(StringBuilder& builder, SerializationMode mo
auto& rows = rows_value->as_grid_track_size_list();
auto& columns = columns_value->as_grid_track_size_list();
if (areas.row_count() == 0 && rows.grid_track_size_list().track_list().size() == 0 && columns.grid_track_size_list().track_list().size() == 0) {
if (areas.row_count() == 0 && rows.grid_track_size_list().is_empty() && columns.grid_track_size_list().is_empty()) {
builder.append("none"sv);
return;
}

View file

@ -0,0 +1,3 @@
250: subgrid [a] [b] [c]
500: subgrid [x] [y] [z]
750: subgrid [x] [y] [z]

View file

@ -0,0 +1,55 @@
Harness status: OK
Found 50 tests
50 Pass
Pass Property grid-template-columns value 'subgrid []'
Pass Property grid-template-columns value 'subgrid [a]'
Pass Property grid-template-columns value 'subgrid [a] [b]'
Pass Property grid-template-columns value 'subgrid [] [b]'
Pass Property grid-template-columns value 'subgrid [a] [b] [b] [c]'
Pass Property grid-template-columns value 'subgrid [a] [b c d] [e f] [e f] [g]'
Pass Property grid-template-columns value 'subgrid [a b c] [d] [e f]'
Pass Property grid-template-columns value 'subgrid repeat(auto-fill, [c])'
Pass Property grid-template-columns value 'subgrid repeat(auto-fill, [])'
Pass Property grid-template-columns value 'subgrid repeat(auto-fill, [c]) [g] [h i]'
Pass Property grid-template-columns value 'subgrid [a] repeat(auto-fill, [c]) [g] [h i]'
Pass Property grid-template-columns value 'subgrid [a b] repeat(auto-fill, [c]) [g]'
Pass Property grid-template-columns value 'subgrid [a] [b] repeat(auto-fill, [c]) [g h]'
Pass Property grid-template-columns value 'subgrid [a] [b] repeat(auto-fill, [c])'
Pass Property grid-template-columns value 'subgrid repeat(auto-fill, [c d])'
Pass Property grid-template-columns value 'subgrid repeat(auto-fill, [c d]) [g] [h i]'
Pass Property grid-template-columns value 'subgrid [a] repeat(auto-fill, [c d]) [g] [h i]'
Pass Property grid-template-columns value 'subgrid [a b] repeat(auto-fill, [c d]) [g]'
Pass Property grid-template-columns value 'subgrid [a] [b] repeat(auto-fill, [c d]) [g h]'
Pass Property grid-template-columns value 'subgrid [a] [b] repeat(auto-fill, [c d])'
Pass Property grid-template-columns value 'subgrid repeat(auto-fill, [c] [d])'
Pass Property grid-template-columns value 'subgrid repeat(auto-fill, [c] [d]) [g] [h i]'
Pass Property grid-template-columns value 'subgrid [a] repeat(auto-fill, [c] [d]) [g] [h i]'
Pass Property grid-template-columns value 'subgrid [a b] repeat(auto-fill, [c] [d]) [g]'
Pass Property grid-template-columns value 'subgrid [a] [b] repeat(auto-fill, [c] [d]) [g h]'
Pass Property grid-template-columns value 'subgrid [a] [b] repeat(auto-fill, [c] [d])'
Pass Property grid-template-columns value 'subgrid repeat(auto-fill, [c] [d e])'
Pass Property grid-template-columns value 'subgrid repeat(auto-fill, [c] [d e]) [g] [h i]'
Pass Property grid-template-columns value 'subgrid [a] repeat(auto-fill, [c] [d e]) [g] [h i]'
Pass Property grid-template-columns value 'subgrid [a b] repeat(auto-fill, [c] [d e]) [g]'
Pass Property grid-template-columns value 'subgrid [a] [b] repeat(auto-fill, [c] [d e]) [g h]'
Pass Property grid-template-columns value 'subgrid [a] [b] repeat(auto-fill, [c] [d e])'
Pass Property grid-template-columns value 'subgrid [a] repeat(2, [c] [d e])'
Pass Property grid-template-columns value 'subgrid repeat(1, [])'
Pass Property grid-template-columns value 'subgrid repeat(2, [])'
Pass Property grid-template-columns value 'subgrid repeat(2, [a])'
Pass Property grid-template-columns value 'subgrid repeat(2, [a] [])'
Pass Property grid-template-columns value 'subgrid repeat(2, [] [a] [])'
Pass Property grid-template-columns value 'subgrid repeat(2, [] [] []) repeat(auto-fill, [] [] [])'
Pass Property grid-template-columns value 'subgrid repeat(1, [a b])'
Pass Property grid-template-columns value 'subgrid repeat(2, [a b])'
Pass Property grid-template-columns value 'subgrid repeat(1, [a] [b])'
Pass Property grid-template-columns value 'subgrid repeat(2, [a] [b])'
Pass Property grid-template-columns value 'subgrid [a] repeat(2, [b])'
Pass Property grid-template-columns value 'subgrid repeat(2, [a]) [b]'
Pass Property grid-template-columns value 'subgrid [a] repeat(2, [b] [c d]) [e]'
Pass Property grid-template-columns value 'subgrid repeat(2, [a b]) repeat(auto-fill, [c] [d e])'
Pass Property grid-template-columns value 'subgrid repeat(auto-fill, [a] [b c]) repeat(2, [d e])'
Pass Property grid-template-columns value 'subgrid repeat(2, [a b]) repeat(auto-fill, [c] [d e]) repeat(2, [f g])'
Pass Property grid-template-columns value 'subgrid [a] [b c] repeat(2, [d e]) [f] [g h] repeat(auto-fill, [i] [j k]) [l] repeat(2, [m n]) [o]'

View file

@ -0,0 +1,27 @@
Harness status: OK
Found 22 tests
22 Pass
Pass e.style['grid-template-rows'] = "subgrid subgrid" should not set the property value
Pass e.style['grid-template-rows'] = "subgrid none" should not set the property value
Pass e.style['grid-template-rows'] = "subgrid 1px" should not set the property value
Pass e.style['grid-template-rows'] = "subgrid [a] 1px" should not set the property value
Pass e.style['grid-template-rows'] = "subgrid repeat(auto-fill, 1px)" should not set the property value
Pass e.style['grid-template-rows'] = "subgrid repeat(auto-fill, line)" should not set the property value
Pass e.style['grid-template-rows'] = "subgrid repeat(auto-fit, [a])" should not set the property value
Pass e.style['grid-template-rows'] = "subgrid repeat(2, 1px)" should not set the property value
Pass e.style['grid-template-rows'] = "subgrid repeat(2, line)" should not set the property value
Pass e.style['grid-template-rows'] = "subgrid repeat(2," should not set the property value
Pass e.style['grid-template-rows'] = "subgrid repeat(auto-fill, [a]) repeat(auto-fill, [b]" should not set the property value
Pass e.style['grid-template-columns'] = "subgrid subgrid" should not set the property value
Pass e.style['grid-template-columns'] = "subgrid none" should not set the property value
Pass e.style['grid-template-columns'] = "subgrid 1px" should not set the property value
Pass e.style['grid-template-columns'] = "subgrid [a] 1px" should not set the property value
Pass e.style['grid-template-columns'] = "subgrid repeat(auto-fill, 1px)" should not set the property value
Pass e.style['grid-template-columns'] = "subgrid repeat(auto-fill, line)" should not set the property value
Pass e.style['grid-template-columns'] = "subgrid repeat(auto-fit, [a])" should not set the property value
Pass e.style['grid-template-columns'] = "subgrid repeat(2, 1px)" should not set the property value
Pass e.style['grid-template-columns'] = "subgrid repeat(2, line)" should not set the property value
Pass e.style['grid-template-columns'] = "subgrid repeat(2," should not set the property value
Pass e.style['grid-template-columns'] = "subgrid repeat(auto-fill, [a]) repeat(auto-fill, [b]" should not set the property value

View file

@ -0,0 +1,43 @@
Harness status: OK
Found 38 tests
38 Pass
Pass e.style['grid-template-rows'] = "subgrid" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [a]" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [a] [b]" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [a] [b] [c]" should set the property value
Pass e.style['grid-template-rows'] = "subgrid []" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [a] [b] [] [c]" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [] [] [] [c]" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [] [] [] []" should set the property value
Pass e.style['grid-template-rows'] = "subgrid repeat(auto-fill, [a])" should set the property value
Pass e.style['grid-template-rows'] = "subgrid repeat(auto-fill, [])" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [a] repeat(auto-fill, [b])" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [a] repeat(auto-fill, [b]) [c]" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [] repeat(auto-fill, []) []" should set the property value
Pass e.style['grid-template-rows'] = "subgrid repeat(2, [a])" should set the property value
Pass e.style['grid-template-rows'] = "subgrid repeat(2, [a] [b])" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [a] repeat(2, [b])" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [a] repeat(2, [b]) [c]" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [] repeat(2, []) []" should set the property value
Pass e.style['grid-template-rows'] = "subgrid [a] repeat(2, [b]) repeat(auto-fill, [c]) [d]" should set the property value
Pass e.style['grid-template-columns'] = "subgrid" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [a]" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [a] [b]" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [a] [b] [c]" should set the property value
Pass e.style['grid-template-columns'] = "subgrid []" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [a] [b] [] [c]" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [] [] [] [c]" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [] [] [] []" should set the property value
Pass e.style['grid-template-columns'] = "subgrid repeat(auto-fill, [a])" should set the property value
Pass e.style['grid-template-columns'] = "subgrid repeat(auto-fill, [])" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [a] repeat(auto-fill, [b])" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [a] repeat(auto-fill, [b]) [c]" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [] repeat(auto-fill, []) []" should set the property value
Pass e.style['grid-template-columns'] = "subgrid repeat(2, [a])" should set the property value
Pass e.style['grid-template-columns'] = "subgrid repeat(2, [a] [b])" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [a] repeat(2, [b])" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [a] repeat(2, [b]) [c]" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [] repeat(2, []) []" should set the property value
Pass e.style['grid-template-columns'] = "subgrid [a] repeat(2, [b]) repeat(auto-fill, [c]) [d]" should set the property value

View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<style>
body {
margin: 0;
}
.parent {
display: grid;
grid-template-columns: 10px 20px;
}
.target {
display: grid;
grid-column: 1 / span 2;
grid-template-columns: subgrid [a] [b] [c];
}
</style>
<div class="parent"><div class="target"></div></div>
<script src="../include.js"></script>
<script>
test(() => {
const target = document.querySelector(".target");
const animation = target.animate([
{ gridTemplateColumns: "subgrid [a] [b] [c]" },
{ gridTemplateColumns: "subgrid [x] [y] [z]" },
], { duration: 1000, fill: "both" });
animation.pause();
for (const time of [250, 500, 750]) {
animation.currentTime = time;
println(`${time}: ${getComputedStyle(target).gridTemplateColumns}`);
}
});
</script>

View file

@ -0,0 +1,69 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Grid Layout Test: getComputedStyle().gridTemplateColumns</title>
<link rel="author" title="Mozilla" href="https://mozilla.org">
<link rel="help" href="https://drafts.csswg.org/css-grid-2/#resolved-track-list" "title"="2.3. Resolved Value of a Track Listing">
<meta name="assert" content="Checks the resolved value of grid-template-columns or grid-template-columns on an element which is not a grid container.">
<style>
#target {
display: block;
height: 1px;
font-size: 1px;
}
</style>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../css/support/computed-testcommon.js"></script>
<div id="target"></div>
<script>
test_computed_value("grid-template-columns", "subgrid []");
test_computed_value("grid-template-columns", "subgrid [a]");
test_computed_value("grid-template-columns", "subgrid [a] [b]");
test_computed_value("grid-template-columns", "subgrid [] [b]");
test_computed_value("grid-template-columns", "subgrid [a] [b] [b] [c]");
test_computed_value("grid-template-columns", "subgrid [a] [b c d] [e f] [e f] [g]");
test_computed_value("grid-template-columns", "subgrid [a b c] [d] [e f]");
test_computed_value("grid-template-columns", "subgrid repeat(auto-fill, [c])");
test_computed_value("grid-template-columns", "subgrid repeat(auto-fill, [])");
test_computed_value("grid-template-columns", "subgrid repeat(auto-fill, [c]) [g] [h i]");
test_computed_value("grid-template-columns", "subgrid [a] repeat(auto-fill, [c]) [g] [h i]");
test_computed_value("grid-template-columns", "subgrid [a b] repeat(auto-fill, [c]) [g]");
test_computed_value("grid-template-columns", "subgrid [a] [b] repeat(auto-fill, [c]) [g h]");
test_computed_value("grid-template-columns", "subgrid [a] [b] repeat(auto-fill, [c])");
test_computed_value("grid-template-columns", "subgrid repeat(auto-fill, [c d])");
test_computed_value("grid-template-columns", "subgrid repeat(auto-fill, [c d]) [g] [h i]");
test_computed_value("grid-template-columns", "subgrid [a] repeat(auto-fill, [c d]) [g] [h i]");
test_computed_value("grid-template-columns", "subgrid [a b] repeat(auto-fill, [c d]) [g]");
test_computed_value("grid-template-columns", "subgrid [a] [b] repeat(auto-fill, [c d]) [g h]");
test_computed_value("grid-template-columns", "subgrid [a] [b] repeat(auto-fill, [c d])");
test_computed_value("grid-template-columns", "subgrid repeat(auto-fill, [c] [d])");
test_computed_value("grid-template-columns", "subgrid repeat(auto-fill, [c] [d]) [g] [h i]");
test_computed_value("grid-template-columns", "subgrid [a] repeat(auto-fill, [c] [d]) [g] [h i]");
test_computed_value("grid-template-columns", "subgrid [a b] repeat(auto-fill, [c] [d]) [g]");
test_computed_value("grid-template-columns", "subgrid [a] [b] repeat(auto-fill, [c] [d]) [g h]");
test_computed_value("grid-template-columns", "subgrid [a] [b] repeat(auto-fill, [c] [d])");
test_computed_value("grid-template-columns", "subgrid repeat(auto-fill, [c] [d e])");
test_computed_value("grid-template-columns", "subgrid repeat(auto-fill, [c] [d e]) [g] [h i]");
test_computed_value("grid-template-columns", "subgrid [a] repeat(auto-fill, [c] [d e]) [g] [h i]");
test_computed_value("grid-template-columns", "subgrid [a b] repeat(auto-fill, [c] [d e]) [g]");
test_computed_value("grid-template-columns", "subgrid [a] [b] repeat(auto-fill, [c] [d e]) [g h]");
test_computed_value("grid-template-columns", "subgrid [a] [b] repeat(auto-fill, [c] [d e])");
test_computed_value("grid-template-columns", "subgrid [a] repeat(2, [c] [d e])");
test_computed_value("grid-template-columns", "subgrid repeat(1, [])");
test_computed_value("grid-template-columns", "subgrid repeat(2, [])");
test_computed_value("grid-template-columns", "subgrid repeat(2, [a])");
test_computed_value("grid-template-columns", "subgrid repeat(2, [a] [])");
test_computed_value("grid-template-columns", "subgrid repeat(2, [] [a] [])");
test_computed_value("grid-template-columns", "subgrid repeat(2, [] [] []) repeat(auto-fill, [] [] [])");
test_computed_value("grid-template-columns", "subgrid repeat(1, [a b])");
test_computed_value("grid-template-columns", "subgrid repeat(2, [a b])");
test_computed_value("grid-template-columns", "subgrid repeat(1, [a] [b])");
test_computed_value("grid-template-columns", "subgrid repeat(2, [a] [b])");
test_computed_value("grid-template-columns", "subgrid [a] repeat(2, [b])");
test_computed_value("grid-template-columns", "subgrid repeat(2, [a]) [b]");
test_computed_value("grid-template-columns", "subgrid [a] repeat(2, [b] [c d]) [e]");
test_computed_value("grid-template-columns", "subgrid repeat(2, [a b]) repeat(auto-fill, [c] [d e])");
test_computed_value("grid-template-columns", "subgrid repeat(auto-fill, [a] [b c]) repeat(2, [d e])");
test_computed_value("grid-template-columns", "subgrid repeat(2, [a b]) repeat(auto-fill, [c] [d e]) repeat(2, [f g])");
test_computed_value("grid-template-columns", "subgrid [a] [b c] repeat(2, [d e]) [f] [g h] repeat(auto-fill, [i] [j k]) [l] repeat(2, [m n]) [o]");
</script>

View file

@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Grid Layout Test: parsing 'grid' with invalid values</title>
<link rel="help" href="https://drafts.csswg.org/css-grid-2">
<meta name="assert" content="grid-template supports the grammar `none | <track-list> | <auto-track-list> | subgrid <line-name-list>?`.">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
// <'grid-template'> invalid values
test_invalid_value("grid-template-rows", 'subgrid subgrid');
test_invalid_value("grid-template-rows", 'subgrid none');
test_invalid_value("grid-template-rows", 'subgrid 1px');
test_invalid_value("grid-template-rows", 'subgrid [a] 1px');
test_invalid_value("grid-template-rows", 'subgrid repeat(auto-fill, 1px)');
test_invalid_value("grid-template-rows", 'subgrid repeat(auto-fill, line)');
test_invalid_value("grid-template-rows", 'subgrid repeat(auto-fit, [a])');
test_invalid_value("grid-template-rows", 'subgrid repeat(2, 1px)');
test_invalid_value("grid-template-rows", 'subgrid repeat(2, line)');
test_invalid_value("grid-template-rows", 'subgrid repeat(2,');
test_invalid_value("grid-template-rows", 'subgrid repeat(auto-fill, [a]) repeat(auto-fill, [b]');
test_invalid_value("grid-template-columns", 'subgrid subgrid');
test_invalid_value("grid-template-columns", 'subgrid none');
test_invalid_value("grid-template-columns", 'subgrid 1px');
test_invalid_value("grid-template-columns", 'subgrid [a] 1px');
test_invalid_value("grid-template-columns", 'subgrid repeat(auto-fill, 1px)');
test_invalid_value("grid-template-columns", 'subgrid repeat(auto-fill, line)');
test_invalid_value("grid-template-columns", 'subgrid repeat(auto-fit, [a])');
test_invalid_value("grid-template-columns", 'subgrid repeat(2, 1px)');
test_invalid_value("grid-template-columns", 'subgrid repeat(2, line)');
test_invalid_value("grid-template-columns", 'subgrid repeat(2,');
test_invalid_value("grid-template-columns", 'subgrid repeat(auto-fill, [a]) repeat(auto-fill, [b]');
</script>
</body>
</html>

View file

@ -0,0 +1,58 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Grid Layout Test: parsing 'grid' with valid values</title>
<link rel="help" href="https://drafts.csswg.org/css-grid-2">
<meta name="assert" content="grid-template supports the grammar `none | <track-list> | <auto-track-list> | subgrid <line-name-list>?`.">
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<script src="../../../css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
// <'grid-template'> values
test_valid_value("grid-template-rows", 'subgrid');
test_valid_value("grid-template-rows", 'subgrid [a]');
test_valid_value("grid-template-rows", 'subgrid [a] [b]');
test_valid_value("grid-template-rows", 'subgrid [a] [b] [c]');
test_valid_value("grid-template-rows", 'subgrid []');
test_valid_value("grid-template-rows", 'subgrid [a] [b] [] [c]');
test_valid_value("grid-template-rows", 'subgrid [] [] [] [c]');
test_valid_value("grid-template-rows", 'subgrid [] [] [] []');
test_valid_value("grid-template-rows", 'subgrid repeat(auto-fill, [a])');
test_valid_value("grid-template-rows", 'subgrid repeat(auto-fill, [])');
test_valid_value("grid-template-rows", 'subgrid [a] repeat(auto-fill, [b])');
test_valid_value("grid-template-rows", 'subgrid [a] repeat(auto-fill, [b]) [c]');
test_valid_value("grid-template-rows", 'subgrid [] repeat(auto-fill, []) []');
test_valid_value("grid-template-rows", 'subgrid repeat(2, [a])');
test_valid_value("grid-template-rows", 'subgrid repeat(2, [a] [b])');
test_valid_value("grid-template-rows", 'subgrid [a] repeat(2, [b])');
test_valid_value("grid-template-rows", 'subgrid [a] repeat(2, [b]) [c]');
test_valid_value("grid-template-rows", 'subgrid [] repeat(2, []) []');
test_valid_value("grid-template-rows", 'subgrid [a] repeat(2, [b]) repeat(auto-fill, [c]) [d]');
test_valid_value("grid-template-columns", 'subgrid');
test_valid_value("grid-template-columns", 'subgrid [a]');
test_valid_value("grid-template-columns", 'subgrid [a] [b]');
test_valid_value("grid-template-columns", 'subgrid [a] [b] [c]');
test_valid_value("grid-template-columns", 'subgrid []');
test_valid_value("grid-template-columns", 'subgrid [a] [b] [] [c]');
test_valid_value("grid-template-columns", 'subgrid [] [] [] [c]');
test_valid_value("grid-template-columns", 'subgrid [] [] [] []');
test_valid_value("grid-template-columns", 'subgrid repeat(auto-fill, [a])');
test_valid_value("grid-template-columns", 'subgrid repeat(auto-fill, [])');
test_valid_value("grid-template-columns", 'subgrid [a] repeat(auto-fill, [b])');
test_valid_value("grid-template-columns", 'subgrid [a] repeat(auto-fill, [b]) [c]');
test_valid_value("grid-template-columns", 'subgrid [] repeat(auto-fill, []) []');
test_valid_value("grid-template-columns", 'subgrid repeat(2, [a])');
test_valid_value("grid-template-columns", 'subgrid repeat(2, [a] [b])');
test_valid_value("grid-template-columns", 'subgrid [a] repeat(2, [b])');
test_valid_value("grid-template-columns", 'subgrid [a] repeat(2, [b]) [c]');
test_valid_value("grid-template-columns", 'subgrid [] repeat(2, []) []');
test_valid_value("grid-template-columns", 'subgrid [a] repeat(2, [b]) repeat(auto-fill, [c]) [d]');
</script>
</body>
</html>