Skip to content

Commit

Permalink
css: Expand the flex-flow shorthand property
Browse files Browse the repository at this point in the history
  • Loading branch information
robinlinden committed Oct 26, 2023
1 parent b8423de commit d2b4d13
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 0 deletions.
58 changes: 58 additions & 0 deletions css/parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,8 @@ void Parser::add_declaration(
expand_border_radius_values(declarations, value);
} else if (name == "text-decoration") {
expand_text_decoration_values(declarations, value);
} else if (name == "flex-flow") {
expand_flex_flow(declarations, value);
} else if (is_in_array<kBorderShorthandProperties>(name)) {
expand_border(name, declarations, value);
} else {
Expand Down Expand Up @@ -638,6 +640,62 @@ void Parser::expand_text_decoration_values(std::map<PropertyId, std::string> &de
declarations.insert_or_assign(PropertyId::TextDecorationStyle, "solid");
}

// https://developer.mozilla.org/en-US/docs/Web/CSS/flex-flow
void Parser::expand_flex_flow(std::map<PropertyId, std::string> &declarations, std::string_view value) {
static constexpr std::array kGlobalValues{"inherit", "initial", "revert", "revert-layer", "unset"};

auto is_wrap = [](std::string_view str) {
return str == "wrap" || str == "nowrap" || str == "wrap-reverse";
};
auto is_direction = [](std::string_view str) {
return str == "row" || str == "row-reverse" || str == "column" || str == "column-reverse";
};

std::string direction{"row"};
std::string wrap{"nowrap"};

Tokenizer tokenizer{value, ' '};
if (tokenizer.size() != 1 && tokenizer.size() != 2) {
spdlog::warn("Unsupported flex-flow value: '{}'", value);
return;
}

auto first = tokenizer.get();
auto second = tokenizer.next().get();
// Global values are only allowed if there's a single value.
if (first && !second && is_in_array<kGlobalValues>(*first)) {
wrap = direction = *first;
declarations.insert_or_assign(PropertyId::FlexDirection, std::move(direction));
declarations.insert_or_assign(PropertyId::FlexWrap, std::move(wrap));
return;
}

// No duplicates of wrap or direction allowed.
if ((first && second)
&& ((is_wrap(*first) && !is_direction(*second)) || (is_direction(*first) && !is_wrap(*second)))) {
spdlog::warn("Unsupported flex-flow value: '{}'", value);
return;
}

for (auto const &v : std::array{first, second}) {
if (!v) {
continue;
}

if (is_wrap(*v)) {
wrap = *v;
} else if (is_direction(*v)) {
direction = *v;
} else {
spdlog::warn("Unsupported flex-flow value: '{}'", value);
return;
}
}

declarations.insert_or_assign(PropertyId::FlexDirection, std::move(direction));
declarations.insert_or_assign(PropertyId::FlexWrap, std::move(wrap));
}

void Parser::expand_edge_values(
std::map<PropertyId, std::string> &declarations, std::string property, std::string_view value) const {
std::string_view top = "", bottom = "", left = "", right = "";
Expand Down
3 changes: 3 additions & 0 deletions css/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ class Parser {

static void expand_text_decoration_values(std::map<PropertyId, std::string> &declarations, std::string_view value);

// https://developer.mozilla.org/en-US/docs/Web/CSS/flex-flow
static void expand_flex_flow(std::map<PropertyId, std::string> &, std::string_view);

void expand_edge_values(
std::map<PropertyId, std::string> &declarations, std::string property, std::string_view value) const;

Expand Down
42 changes: 42 additions & 0 deletions css/parser_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1025,5 +1025,47 @@ int main() {
std::ignore = css::parse("p { font-size:");
});

etest::test("parser: flex-flow shorthand, global value", [] {
expect_eq(css::parse("p { flex-flow: revert; }").rules.at(0).declarations,
std::map<css::PropertyId, std::string>{
{css::PropertyId::FlexDirection, "revert"s},
{css::PropertyId::FlexWrap, "revert"s},
});
expect_eq(css::parse("p { flex-flow: revert row; }").rules.at(0).declarations,
std::map<css::PropertyId, std::string>{});
});

etest::test("parser: flex-flow shorthand, one value", [] {
expect_eq(css::parse("p { flex-flow: column; }").rules.at(0).declarations,
std::map<css::PropertyId, std::string>{
{css::PropertyId::FlexDirection, "column"s},
{css::PropertyId::FlexWrap, "nowrap"s},
});
expect_eq(css::parse("p { flex-flow: wrap; }").rules.at(0).declarations,
std::map<css::PropertyId, std::string>{
{css::PropertyId::FlexDirection, "row"s},
{css::PropertyId::FlexWrap, "wrap"s},
});
expect_eq(css::parse("p { flex-flow: aaaaaaaaaa; }").rules.at(0).declarations,
std::map<css::PropertyId, std::string>{});
});

etest::test("parser: flex-flow shorthand, two values", [] {
expect_eq(css::parse("p { flex-flow: column wrap; }").rules.at(0).declarations,
std::map<css::PropertyId, std::string>{
{css::PropertyId::FlexDirection, "column"s},
{css::PropertyId::FlexWrap, "wrap"s},
});
expect_eq(css::parse("p { flex-flow: wrap wrap; }").rules.at(0).declarations, //
std::map<css::PropertyId, std::string>{});
expect_eq(css::parse("p { flex-flow: wrap asdf; }").rules.at(0).declarations, //
std::map<css::PropertyId, std::string>{});
});

etest::test("parser: flex-flow shorthand, too many values :(", [] {
expect_eq(css::parse("p { flex-flow: column wrap nowrap; }").rules.at(0).declarations,
std::map<css::PropertyId, std::string>{});
});

return etest::run_all_tests();
}

0 comments on commit d2b4d13

Please sign in to comment.