LibWeb: Parse grid-template property

This commit is contained in:
martinfalisse 2023-04-29 19:32:56 +02:00 committed by Andreas Kling
parent bebf4363db
commit 22202715fc
Notes: sideshowbarker 2024-07-17 08:55:54 +09:00
13 changed files with 351 additions and 3 deletions

View File

@ -0,0 +1,54 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x216 children: not-inline
BlockContainer <body> at (8,8) content-size 784x200 children: not-inline
Box <div.mw-page-container-inner> at (8,8) content-size 784x0 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 0x0 children: inline
TextNode <#text>
BlockContainer <div.vector-main-menu-container> at (8,8) content-size 196x0 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 0x0 children: inline
TextNode <#text>
BlockContainer <div.vector-sitenotice-container> at (8,8) content-size 784x0 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 0x0 children: inline
TextNode <#text>
BlockContainer <div.mw-content-container> at (204,8) content-size 588x0 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 0x0 children: inline
TextNode <#text>
BlockContainer <div.mw-footer-container> at (8,8) content-size 784x0 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 0x0 children: inline
TextNode <#text>
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
TextNode <#text>
TextNode <#text>
Box <section#page> at (8,8) content-size 784x200 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 0x0 children: inline
TextNode <#text>
BlockContainer <header> at (8,8) content-size 784x30 children: inline
line 0 width: 55.703125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 6, rect: [8,8 55.703125x17.46875]
"Header"
TextNode <#text>
BlockContainer <(anonymous)> at (8,8) content-size 0x0 children: inline
TextNode <#text>
BlockContainer <nav> at (8,38) content-size 120x170 children: inline
line 0 width: 80.6875, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 10, rect: [8,38 80.6875x17.46875]
"Navigation"
TextNode <#text>
BlockContainer <(anonymous)> at (8,8) content-size 0x0 children: inline
TextNode <#text>
BlockContainer <main> at (128,38) content-size 664x140 children: inline
line 0 width: 79.515625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 9, rect: [128,38 79.515625x17.46875]
"Main area"
TextNode <#text>
BlockContainer <(anonymous)> at (8,8) content-size 0x0 children: inline
TextNode <#text>
BlockContainer <footer> at (128,178) content-size 664x30 children: inline
line 0 width: 57.671875, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 6, rect: [128,178 57.671875x17.46875]
"Footer"
TextNode <#text>
BlockContainer <(anonymous)> at (8,8) content-size 0x0 children: inline
TextNode <#text>
BlockContainer <(anonymous)> at (8,208) content-size 784x0 children: inline
TextNode <#text>

View File

@ -0,0 +1,78 @@
<style>
body {
font-family: 'SerenitySans';
}
.mw-page-container-inner {
display: grid;
grid-template: min-content min-content 1fr min-content / 12.25em minmax(0, 1fr);
grid-template-areas:
'siteNotice siteNotice'
'mainMenu pageContent'
'toc pageContent'
'footer footer'
}
.vector-sitenotice-container {
grid-area: siteNotice
}
.vector-main-menu-container {
grid-area: mainMenu;
overflow-anchor: none
}
.mw-content-container {
grid-area: pageContent
}
.mw-footer-container {
grid-area: footer
}
</style>
<!-- Shouldn't crash :) -->
<div class="mw-page-container-inner">
<div class="vector-main-menu-container"></div>
<div class="vector-sitenotice-container"></div>
<div class="mw-content-container"></div>
<div class="mw-footer-container"></div>
</div>
<style>
#page {
display: grid;
width: 100%;
height: 200px;
grid-template:
[header-left] "head head" 30px
[header-right] [main-left] "nav main" 1fr
[main-right] [footer-left] "nav foot" 30px [footer-right] / 120px 1fr;
}
header {
background-color: lime;
grid-area: head;
}
nav {
background-color: lightblue;
grid-area: nav;
}
main {
background-color: yellow;
grid-area: main;
}
footer {
background-color: red;
grid-area: foot;
}
</style>
<section id="page">
<header>Header</header>
<nav>Navigation</nav>
<main>Main area</main>
<footer>Footer</footer>
</section>

View File

@ -87,6 +87,7 @@ set(SOURCES
CSS/StyleValues/GridTemplateAreaStyleValue.cpp
CSS/StyleValues/GridTrackPlacementStyleValue.cpp
CSS/StyleValues/GridTrackPlacementShorthandStyleValue.cpp
CSS/StyleValues/GridTrackSizeListShorthandStyleValue.cpp
CSS/StyleValues/GridTrackSizeListStyleValue.cpp
CSS/StyleValues/IdentifierStyleValue.cpp
CSS/StyleValues/ImageStyleValue.cpp

View File

@ -51,6 +51,7 @@
#include <LibWeb/CSS/StyleValues/GridTemplateAreaStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackPlacementShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackSizeListShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
#include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h>
#include <LibWeb/CSS/StyleValues/ImageStyleValue.h>
@ -6269,7 +6270,7 @@ Optional<CSS::ExplicitGridTrack> Parser::parse_track_sizing_function(ComponentVa
}
}
RefPtr<StyleValue> Parser::parse_grid_track_size_list(Vector<ComponentValue> const& component_values)
RefPtr<StyleValue> Parser::parse_grid_track_size_list(Vector<ComponentValue> const& component_values, bool allow_separate_line_name_blocks)
{
Vector<CSS::ExplicitGridTrack> track_list;
Vector<Vector<String>> line_names_list;
@ -6278,7 +6279,7 @@ RefPtr<StyleValue> Parser::parse_grid_track_size_list(Vector<ComponentValue> con
while (tokens.has_next_token()) {
auto token = tokens.next_token();
if (token.is_block()) {
if (last_object_was_line_names)
if (last_object_was_line_names && !allow_separate_line_name_blocks)
return GridTrackSizeListStyleValue::make_auto();
last_object_was_line_names = true;
Vector<String> line_names;
@ -6445,6 +6446,53 @@ RefPtr<StyleValue> Parser::parse_grid_track_placement_shorthand_value(Vector<Com
return {};
}
// https://www.w3.org/TR/css-grid-2/#explicit-grid-shorthand
// 7.4. Explicit Grid Shorthand: the grid-template property
RefPtr<StyleValue> Parser::parse_grid_track_size_list_shorthand_value(Vector<ComponentValue> const& component_values)
{
// The grid-template property is a shorthand for setting grid-template-columns, grid-template-rows,
// and grid-template-areas in a single declaration. It has several distinct syntax forms:
// none
// - Sets all three properties to their initial values (none).
// <'grid-template-rows'> / <'grid-template-columns'>
// - Sets grid-template-rows and grid-template-columns to the specified values, respectively, and sets grid-template-areas to none.
// [ <line-names>? <string> <track-size>? <line-names>? ]+ [ / <explicit-track-list> ]?
// - Sets grid-template-areas to the strings listed.
// - Sets grid-template-rows to the <track-size>s following each string (filling in auto for any missing sizes),
// and splicing in the named lines defined before/after each size.
// - Sets grid-template-columns to the track listing specified after the slash (or none, if not specified).
Vector<ComponentValue> template_rows_tokens;
Vector<ComponentValue> template_columns_tokens;
Vector<ComponentValue> template_area_tokens;
int forward_slash_index = -1;
for (size_t x = 0; x < component_values.size(); x++) {
if (component_values[x].is_token() && component_values[x].token().is(Token::Type::Delim) && component_values[x].token().delim() == "/"sv) {
forward_slash_index = x;
break;
}
}
for (size_t x = 0; x < (forward_slash_index > -1 ? forward_slash_index : component_values.size()); x++) {
if (component_values[x].is_token() && component_values[x].token().is(Token::Type::String))
template_area_tokens.append(component_values[x]);
else
template_rows_tokens.append(component_values[x]);
}
if (forward_slash_index > -1) {
for (size_t x = forward_slash_index + 1; x < component_values.size(); x++)
template_columns_tokens.append(component_values[x]);
}
auto parsed_template_areas_values = parse_grid_template_areas_value(template_area_tokens);
auto parsed_template_rows_values = parse_grid_track_size_list(template_rows_tokens, true);
auto parsed_template_columns_values = parse_grid_track_size_list(template_columns_tokens);
return GridTrackSizeListShorthandStyleValue::create(
parsed_template_areas_values.release_nonnull()->as_grid_template_area(),
parsed_template_rows_values.release_nonnull()->as_grid_track_size_list(),
parsed_template_columns_values.release_nonnull()->as_grid_track_size_list());
}
RefPtr<StyleValue> Parser::parse_grid_area_shorthand_value(Vector<ComponentValue> const& component_values)
{
auto tokens = TokenStream { component_values };
@ -6708,6 +6756,10 @@ Parser::ParseErrorOr<NonnullRefPtr<StyleValue>> Parser::parse_css_value(Property
if (auto parsed_value = parse_grid_track_placement(component_values))
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::GridTemplate:
if (auto parsed_value = parse_grid_track_size_list_shorthand_value(component_values))
return parsed_value.release_nonnull();
return ParseError::SyntaxError;
case PropertyID::GridTemplateColumns:
if (auto parsed_value = parse_grid_track_size_list(component_values))
return parsed_value.release_nonnull();

View File

@ -318,7 +318,8 @@ private:
RefPtr<StyleValue> parse_text_decoration_line_value(TokenStream<ComponentValue>&);
RefPtr<StyleValue> parse_transform_value(Vector<ComponentValue> const&);
RefPtr<StyleValue> parse_transform_origin_value(Vector<ComponentValue> const&);
RefPtr<StyleValue> parse_grid_track_size_list(Vector<ComponentValue> const&);
RefPtr<StyleValue> parse_grid_track_size_list(Vector<ComponentValue> const&, bool allow_separate_line_name_blocks = false);
RefPtr<StyleValue> parse_grid_track_size_list_shorthand_value(Vector<ComponentValue> const&);
RefPtr<StyleValue> parse_grid_track_placement(Vector<ComponentValue> const&);
RefPtr<StyleValue> parse_grid_track_placement_shorthand_value(Vector<ComponentValue> const&);
RefPtr<StyleValue> parse_grid_template_areas_value(Vector<ComponentValue> const&);

View File

@ -941,6 +941,23 @@
"string"
]
},
"grid-template": {
"inherited": false,
"initial": "auto",
"valid-identifiers": [
"auto"
],
"valid-types": [
"length",
"percentage",
"string"
],
"longhands": [
"grid-template-areas",
"grid-template-rows",
"grid-template-columns"
]
},
"grid-template-areas": {
"inherited": false,
"initial": "auto",

View File

@ -23,6 +23,7 @@
#include <LibWeb/CSS/StyleValues/GridAreaShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackPlacementShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackSizeListShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
#include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h>
#include <LibWeb/CSS/StyleValues/InitialStyleValue.h>
@ -484,6 +485,26 @@ RefPtr<StyleValue const> ResolvedCSSStyleDeclaration::style_value_for_property(L
return GridTrackPlacementStyleValue::create(layout_node.computed_values().grid_row_end());
case CSS::PropertyID::GridRowStart:
return GridTrackPlacementStyleValue::create(layout_node.computed_values().grid_row_start());
case CSS::PropertyID::GridTemplate: {
auto maybe_grid_template_areas = property(CSS::PropertyID::GridTemplateAreas);
auto maybe_grid_template_rows = property(CSS::PropertyID::GridTemplateRows);
auto maybe_grid_template_columns = property(CSS::PropertyID::GridTemplateColumns);
RefPtr<GridTemplateAreaStyleValue const> grid_template_areas;
RefPtr<GridTrackSizeListStyleValue const> grid_template_rows, grid_template_columns;
if (maybe_grid_template_areas.has_value()) {
VERIFY(maybe_grid_template_areas.value().value->is_grid_template_area());
grid_template_areas = maybe_grid_template_areas.value().value->as_grid_template_area();
}
if (maybe_grid_template_rows.has_value()) {
VERIFY(maybe_grid_template_rows.value().value->is_grid_track_size_list());
grid_template_rows = maybe_grid_template_rows.value().value->as_grid_track_size_list();
}
if (maybe_grid_template_columns.has_value()) {
VERIFY(maybe_grid_template_columns.value().value->is_grid_track_size_list());
grid_template_columns = maybe_grid_template_columns.value().value->as_grid_track_size_list();
}
return GridTrackSizeListShorthandStyleValue::create(grid_template_areas.release_nonnull(), grid_template_rows.release_nonnull(), grid_template_columns.release_nonnull());
}
case CSS::PropertyID::GridTemplateColumns:
return GridTrackSizeListStyleValue::create(layout_node.computed_values().grid_template_columns());
case CSS::PropertyID::GridTemplateRows:

View File

@ -37,6 +37,8 @@
#include <LibWeb/CSS/StyleValues/GridAreaShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackPlacementShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackSizeListShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
#include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h>
#include <LibWeb/CSS/StyleValues/LengthStyleValue.h>
#include <LibWeb/CSS/StyleValues/ListStyleStyleValue.h>
@ -623,6 +625,20 @@ static void set_property_expanding_shorthands(StyleProperties& style, CSS::Prope
return;
}
if (property_id == CSS::PropertyID::GridTemplate) {
if (value.is_grid_track_size_list_shorthand()) {
auto const& shorthand = value.as_grid_track_size_list_shorthand();
style.set_property(CSS::PropertyID::GridTemplateAreas, shorthand.areas());
style.set_property(CSS::PropertyID::GridTemplateRows, shorthand.rows());
style.set_property(CSS::PropertyID::GridTemplateColumns, shorthand.columns());
return;
}
style.set_property(CSS::PropertyID::GridTemplateAreas, value);
style.set_property(CSS::PropertyID::GridTemplateRows, value);
style.set_property(CSS::PropertyID::GridTemplateColumns, value);
return;
}
if (property_id == CSS::PropertyID::Gap || property_id == CSS::PropertyID::GridGap) {
if (value.is_value_list()) {
auto const& values_list = value.as_value_list();

View File

@ -30,6 +30,7 @@
#include <LibWeb/CSS/StyleValues/GridTemplateAreaStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackPlacementShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackPlacementStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackSizeListShorthandStyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
#include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h>
#include <LibWeb/CSS/StyleValues/ImageStyleValue.h>
@ -236,6 +237,12 @@ GridTrackSizeListStyleValue const& StyleValue::as_grid_track_size_list() const
return static_cast<GridTrackSizeListStyleValue const&>(*this);
}
GridTrackSizeListShorthandStyleValue const& StyleValue::as_grid_track_size_list_shorthand() const
{
VERIFY(is_grid_track_size_list_shorthand());
return static_cast<GridTrackSizeListShorthandStyleValue const&>(*this);
}
LinearGradientStyleValue const& StyleValue::as_linear_gradient() const
{
VERIFY(is_linear_gradient());

View File

@ -109,6 +109,7 @@ public:
GridTrackPlacement,
GridTrackPlacementShorthand,
GridTrackSizeList,
GridTrackSizeListShorthand,
Identifier,
Image,
Inherit,
@ -160,6 +161,7 @@ public:
bool is_grid_track_placement() const { return type() == Type::GridTrackPlacement; }
bool is_grid_track_placement_shorthand() const { return type() == Type::GridTrackPlacementShorthand; }
bool is_grid_track_size_list() const { return type() == Type::GridTrackSizeList; }
bool is_grid_track_size_list_shorthand() const { return type() == Type::GridTrackSizeListShorthand; }
bool is_identifier() const { return type() == Type::Identifier; }
bool is_image() const { return type() == Type::Image; }
bool is_inherit() const { return type() == Type::Inherit; }
@ -208,6 +210,7 @@ public:
GridTemplateAreaStyleValue const& as_grid_template_area() const;
GridTrackPlacementShorthandStyleValue const& as_grid_track_placement_shorthand() const;
GridTrackPlacementStyleValue const& as_grid_track_placement() const;
GridTrackSizeListShorthandStyleValue const& as_grid_track_size_list_shorthand() const;
GridTrackSizeListStyleValue const& as_grid_track_size_list() const;
IdentifierStyleValue const& as_identifier() const;
ImageStyleValue const& as_image() const;
@ -255,6 +258,7 @@ public:
GridTemplateAreaStyleValue& as_grid_template_area() { return const_cast<GridTemplateAreaStyleValue&>(const_cast<StyleValue const&>(*this).as_grid_template_area()); }
GridTrackPlacementShorthandStyleValue& as_grid_track_placement_shorthand() { return const_cast<GridTrackPlacementShorthandStyleValue&>(const_cast<StyleValue const&>(*this).as_grid_track_placement_shorthand()); }
GridTrackPlacementStyleValue& as_grid_track_placement() { return const_cast<GridTrackPlacementStyleValue&>(const_cast<StyleValue const&>(*this).as_grid_track_placement()); }
GridTrackSizeListShorthandStyleValue& as_grid_track_size_list_shorthand() { return const_cast<GridTrackSizeListShorthandStyleValue&>(const_cast<StyleValue const&>(*this).as_grid_track_size_list_shorthand()); }
GridTrackSizeListStyleValue& as_grid_track_size_list() { return const_cast<GridTrackSizeListStyleValue&>(const_cast<StyleValue const&>(*this).as_grid_track_size_list()); }
IdentifierStyleValue& as_identifier() { return const_cast<IdentifierStyleValue&>(const_cast<StyleValue const&>(*this).as_identifier()); }
ImageStyleValue& as_image() { return const_cast<ImageStyleValue&>(const_cast<StyleValue const&>(*this).as_image()); }

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2023, Martin Falisse <mfalisse@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "GridTrackSizeListShorthandStyleValue.h"
#include <LibWeb/CSS/StyleValues/GridTrackSizeListStyleValue.h>
namespace Web::CSS {
ValueComparingNonnullRefPtr<GridTrackSizeListShorthandStyleValue> GridTrackSizeListShorthandStyleValue::create(
ValueComparingNonnullRefPtr<GridTemplateAreaStyleValue const> areas,
ValueComparingNonnullRefPtr<GridTrackSizeListStyleValue const> rows,
ValueComparingNonnullRefPtr<GridTrackSizeListStyleValue const> columns)
{
return adopt_ref(*new GridTrackSizeListShorthandStyleValue(move(areas), move(rows), move(columns)));
}
ErrorOr<String> GridTrackSizeListShorthandStyleValue::to_string() const
{
auto construct_rows_string = [&]() -> ErrorOr<String> {
StringBuilder builder;
size_t idx = 0;
for (auto const& row : m_properties.rows->grid_track_size_list().track_list()) {
if (m_properties.areas->grid_template_area().size() > idx) {
TRY(builder.try_append("\""sv));
for (size_t y = 0; y < m_properties.areas->grid_template_area()[idx].size(); ++y) {
TRY(builder.try_append(m_properties.areas->grid_template_area()[idx][y]));
if (y != m_properties.areas->grid_template_area()[idx].size() - 1)
TRY(builder.try_append(" "sv));
}
TRY(builder.try_append("\" "sv));
}
TRY(builder.try_append(TRY(row.to_string())));
if (idx < m_properties.rows->grid_track_size_list().track_list().size() - 1)
TRY(builder.try_append(' '));
idx++;
}
return TRY(builder.to_string());
};
if (m_properties.columns->grid_track_size_list().track_list().size() == 0)
return String::formatted("{}", TRY(construct_rows_string()));
return String::formatted("{} / {}", TRY(construct_rows_string()), TRY(m_properties.columns->grid_track_size_list().to_string()));
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2023, Martin Falisse <mfalisse@outlook.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/CSS/StyleValue.h>
#include <LibWeb/CSS/StyleValues/GridTemplateAreaStyleValue.h>
namespace Web::CSS {
class GridTrackSizeListShorthandStyleValue final : public StyleValueWithDefaultOperators<GridTrackSizeListShorthandStyleValue> {
public:
static ValueComparingNonnullRefPtr<GridTrackSizeListShorthandStyleValue> create(
ValueComparingNonnullRefPtr<GridTemplateAreaStyleValue const> areas,
ValueComparingNonnullRefPtr<GridTrackSizeListStyleValue const> rows,
ValueComparingNonnullRefPtr<GridTrackSizeListStyleValue const> columns);
virtual ~GridTrackSizeListShorthandStyleValue() override = default;
auto rows() const { return m_properties.rows; }
auto columns() const { return m_properties.columns; }
auto areas() const { return m_properties.areas; }
virtual ErrorOr<String> to_string() const override;
bool properties_equal(GridTrackSizeListShorthandStyleValue const& other) const { return m_properties == other.m_properties; };
private:
GridTrackSizeListShorthandStyleValue(
ValueComparingNonnullRefPtr<GridTemplateAreaStyleValue const> areas,
ValueComparingNonnullRefPtr<GridTrackSizeListStyleValue const> rows,
ValueComparingNonnullRefPtr<GridTrackSizeListStyleValue const> columns)
: StyleValueWithDefaultOperators(Type::GridTrackSizeListShorthand)
, m_properties { .areas = move(areas), .rows = move(rows), .columns = move(columns) }
{
}
struct Properties {
ValueComparingNonnullRefPtr<GridTemplateAreaStyleValue const> areas;
ValueComparingNonnullRefPtr<GridTrackSizeListStyleValue const> rows;
ValueComparingNonnullRefPtr<GridTrackSizeListStyleValue const> columns;
bool operator==(Properties const&) const = default;
} m_properties;
};
}

View File

@ -105,6 +105,7 @@ class GridTrackPlacement;
class GridTrackPlacementShorthandStyleValue;
class GridTrackPlacementStyleValue;
class GridTrackSizeList;
class GridTrackSizeListShorthandStyleValue;
class GridTrackSizeListStyleValue;
class IdentifierStyleValue;
class ImageStyleValue;