Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,32 @@ inline bool grid_layout_equal(
}
return true;
};
const auto areas_equal = [](const auto& left_areas, const auto& right_areas) {
if (left_areas.size() != right_areas.size()) return false;
for (size_t index = 0; index < left_areas.size(); ++index) {
const auto& left_area = left_areas[index];
const auto& right_area = right_areas[index];
if (left_area.name != right_area.name
|| left_area.row_start != right_area.row_start
|| left_area.row_end != right_area.row_end
|| left_area.column_start != right_area.column_start
|| left_area.column_end != right_area.column_end) return false;
}
return true;
};
return tracks_equal(left.template_columns, right.template_columns)
&& tracks_equal(left.template_rows, right.template_rows)
&& tracks_equal(left.auto_columns, right.auto_columns)
&& areas_equal(left.template_areas, right.template_areas)
&& left.template_area_row_count == right.template_area_row_count
&& left.template_area_column_count == right.template_area_column_count
&& left.subgrid_columns == right.subgrid_columns
&& left.two_columns == right.two_columns
&& left.auto_flow_column == right.auto_flow_column
&& left.fractional_rows == right.fractional_rows
&& left.span_all == right.span_all
&& left.column_start == right.column_start
&& left.template_areas_value == right.template_areas_value
&& left.area_value == right.area_value
&& left.row_value == right.row_value
&& left.row_start_value == right.row_start_value
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,130 @@ inline std::vector<node_style::grid_data::track> parse_simple_grid_tracks(
return tracks;
}

struct parsed_grid_template_areas final {
std::vector<node_style::grid_data::named_area> areas;
size_t row_count{0};
size_t column_count{0};
std::string serialized{"none"};
};

inline std::optional<parsed_grid_template_areas> parse_grid_template_areas(
std::string_view value)
{
const auto trim = [](std::string_view input) {
const auto first = input.find_first_not_of(" \t\r\n\f");
if (first == std::string_view::npos) return std::string_view{};
return input.substr(first, input.find_last_not_of(" \t\r\n\f") - first + 1U);
};
value = trim(value);
if (value == "none") return parsed_grid_template_areas{};
if (value.empty()) return std::nullopt;

std::vector<std::vector<std::string>> rows;
std::string serialized;
size_t cursor = 0;
while (cursor < value.size()) {
while (cursor < value.size()
&& std::isspace(static_cast<unsigned char>(value[cursor]))) ++cursor;
if (cursor == value.size()) break;
const auto quote = value[cursor];
if (quote != '\'' && quote != '"') return std::nullopt;
++cursor;
std::string row_text;
auto closed = false;
while (cursor < value.size()) {
const auto character = value[cursor++];
if (character == quote) {
closed = true;
break;
}
if (character == '\\') {
if (cursor == value.size()) return std::nullopt;
row_text.push_back(value[cursor++]);
continue;
}
if (character == '\n' || character == '\r' || character == '\f') {
return std::nullopt;
}
row_text.push_back(character);
}
if (!closed) return std::nullopt;

std::vector<std::string> cells;
std::istringstream tokens(row_text);
std::string token;
while (tokens >> token) {
const auto empty_cell = std::all_of(
token.begin(), token.end(), [](char character) { return character == '.'; });
if (empty_cell) token = ".";
else {
const auto first = static_cast<unsigned char>(token.front());
if (!(std::isalpha(first) || first == '_' || first == '-')) return std::nullopt;
if (!std::all_of(token.begin() + 1, token.end(), [](unsigned char character) {
return std::isalnum(character) || character == '_' || character == '-';
})) return std::nullopt;
if (token == "auto" || token == "span" || token == "initial"
|| token == "inherit" || token == "unset" || token == "revert"
|| token == "revert-layer" || token == "default") return std::nullopt;
}
cells.push_back(std::move(token));
}
if (cells.empty()) return std::nullopt;
if (!rows.empty() && cells.size() != rows.front().size()) return std::nullopt;
if (!serialized.empty()) serialized.push_back(' ');
serialized.push_back('"');
for (size_t index = 0; index < cells.size(); ++index) {
if (index != 0) serialized.push_back(' ');
serialized += cells[index];
}
serialized.push_back('"');
rows.push_back(std::move(cells));
}
if (rows.empty()) return std::nullopt;

parsed_grid_template_areas result;
result.row_count = rows.size();
result.column_count = rows.front().size();
result.serialized = std::move(serialized);
for (size_t row = 0; row < rows.size(); ++row) {
for (size_t column = 0; column < rows[row].size(); ++column) {
const auto& name = rows[row][column];
if (name == ".") continue;
auto found = std::find_if(result.areas.begin(), result.areas.end(),
[&](const auto& area) { return area.name == name; });
if (found == result.areas.end()) {
result.areas.push_back({name, row, row + 1U, column, column + 1U});
} else {
found->row_start = std::min(found->row_start, row);
found->row_end = std::max(found->row_end, row + 1U);
found->column_start = std::min(found->column_start, column);
found->column_end = std::max(found->column_end, column + 1U);
}
}
}
for (const auto& area : result.areas) {
for (size_t row = area.row_start; row < area.row_end; ++row) {
for (size_t column = area.column_start; column < area.column_end; ++column) {
if (rows[row][column] != area.name) return std::nullopt;
}
}
}
return result;
}

inline bool apply_grid_template_areas(node_style& style, const std::string& value)
{
const auto parsed = parse_grid_template_areas(value);
if (!parsed.has_value()) return false;
auto& grid = style.mutable_grid();
grid.template_areas = parsed->areas;
grid.template_area_row_count = parsed->row_count;
grid.template_area_column_count = parsed->column_count;
grid.template_areas_value = parsed->serialized;
grid.two_columns = grid.subgrid_columns || grid.template_columns.size() > 1U
|| parsed->column_count > 1U;
return true;
}

inline bool apply_grid_placement_declaration(
node_style& style,
Expand Down Expand Up @@ -200,12 +324,25 @@ inline bool apply_grid_placement_declaration(
const auto component = [&](size_t index) {
return index < components.size() ? components[index] : std::string{"auto"};
};
const auto custom_identifier = [](const std::string& token) {
if (token.empty() || token == "auto" || token == "span"
|| token == "inherit" || token == "initial" || token == "unset"
|| token == "revert" || token == "revert-layer"
|| token.starts_with("span ")) return false;
int32_t integer = 0;
const auto parsed = std::from_chars(
token.data(), token.data() + token.size(), integer);
return parsed.ec != std::errc{} || parsed.ptr != token.data() + token.size();
};
if (name == "grid-area") {
grid.area_value = value;
grid.row_start_value = component(0);
grid.column_start_value = component(1);
grid.row_end_value = component(2);
grid.column_end_value = component(3);
const auto omitted = components.size() == 1U
&& custom_identifier(grid.row_start_value)
? grid.row_start_value : std::string{"auto"};
grid.column_start_value = components.size() > 1U ? component(1) : omitted;
grid.row_end_value = components.size() > 2U ? component(2) : omitted;
grid.column_end_value = components.size() > 3U ? component(3) : omitted;
grid.row_value =
grid.row_start_value + " / " + grid.row_end_value;
update_column_layout();
Expand All @@ -214,12 +351,16 @@ inline bool apply_grid_placement_declaration(
if (name == "grid-row") {
grid.row_value = value;
grid.row_start_value = component(0);
grid.row_end_value = component(1);
grid.row_end_value = components.size() > 1U ? component(1)
: custom_identifier(grid.row_start_value)
? grid.row_start_value : std::string{"auto"};
return true;
}

grid.column_start_value = component(0);
grid.column_end_value = component(1);
grid.column_end_value = components.size() > 1U ? component(1)
: custom_identifier(grid.column_start_value)
? grid.column_start_value : std::string{"auto"};
update_column_layout();
// Preserve the authored one-component shorthand serialization rather
// than inflating `2` to `2 / auto`.
Expand All @@ -231,7 +372,15 @@ template<typename Decision,typename Protected>
bool apply_grid_value(dom_node& node,const std::string& name,const std::string& value,
Decision& decision,Protected&& is_inline)
{
if (name == "grid-template-columns" && !is_inline(inline_grid)) {
if (name == "grid-template-areas" && !is_inline(inline_grid)) {
if (!apply_grid_template_areas(node.style, value)) {
decision.classification = "unsupported";
decision.semantic_slice = "invalid grid-template-areas declarations are ignored";
return true;
}
decision.classification = "supported";
decision.semantic_slice = "rectangular named grid template areas";
} else if (name == "grid-template-columns" && !is_inline(inline_grid)) {
auto& grid = node.style.mutable_grid();
const auto first = value.find_first_not_of(" \t\r\n");
const auto last = value.find_last_not_of(" \t\r\n");
Expand All @@ -245,6 +394,7 @@ bool apply_grid_value(dom_node& node,const std::string& name,const std::string&
: parse_simple_grid_tracks(value);
grid.two_columns = grid.subgrid_columns
|| grid.template_columns.size() > 1U
|| grid.template_area_column_count > 1U
|| (grid.template_columns.empty() && has_multiple_grid_columns(value));
decision.classification = "partially-supported";
decision.semantic_slice =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ inline uint64_t property_mask(std::string_view name)
if (name == "flex-basis") return inline_flex_basis;
if (name == "flex-wrap" || name == "flexWrap") return inline_flex_wrap;
if (name == "grid-template-columns" || name == "grid-template-rows"
|| name == "grid-template-areas"
|| name == "grid-area" || name == "grid-row"
|| name == "grid-row-start" || name == "grid-row-end"
|| name == "grid-column" || name == "grid-column-start"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ inline void apply_all_unset(dom_node& node)
reset.z_index_auto = previous.z_index_auto;
}
if (has_inline({"flex-basis", "flex"})) reset.flex_basis = previous.flex_basis;
if (has_inline({"grid-template-columns", "grid-template-rows",
if (has_inline({"grid-template-columns", "grid-template-rows", "grid-template-areas",
"grid-auto-columns", "grid-auto-flow",
"grid-area", "grid-row", "grid-row-start", "grid-row-end",
"grid-column", "grid-column-start", "grid-column-end"})) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -309,16 +309,28 @@ struct node_style final {
sizing kind{sizing::automatic};
};

struct named_area final {
std::string name;
size_t row_start{0};
size_t row_end{0};
size_t column_start{0};
size_t column_end{0};
};

std::vector<track> template_columns;
std::vector<track> template_rows;
std::vector<track> auto_columns;
std::vector<named_area> template_areas;
size_t template_area_row_count{0};
size_t template_area_column_count{0};
bool subgrid_columns{false};
bool two_columns{false};
bool auto_flow_column{false};
bool fractional_rows{false};
bool span_all{false};
bool compiled_full_columns{false};
int32_t column_start{0};
std::string template_areas_value{"none"};
std::string area_value{"auto"};
std::string row_value{"auto"};
std::string row_start_value{"auto"};
Expand Down
Loading
Loading