srctree

Mikael Larsson parent f888c63a b89ee299
css: Add support for shorthand property padding

inlinesplit
css/parser.h added: 142, removed: 5, total 137
@@ -73,7 +73,8 @@ private:
skip_whitespace();
 
while (peek() != '}') {
rule.declarations.insert(parse_declaration());
auto [name, value] = parse_declaration();
add_declaration(rule.declarations, name, value);
skip_whitespace();
}
 
@@ -82,13 +83,69 @@ private:
return rule;
}
 
std::pair<std::string, std::string> parse_declaration() {
std::pair<std::string_view, std::string_view> parse_declaration() {
auto name = consume_while([](char c) { return c != ':'; });
consume_char(); // :
skip_whitespace();
auto value = consume_while([](char c) { return c != ';' && c != '}'; });
skip_if_neq('}'); // ;
return {std::string{name}, std::string{value}};
return {name, value};
}
 
void add_declaration(std::map<std::string, std::string>& declarations,
std::string_view name,
std::string_view value) {
if (name == "padding") {
expand_padding(declarations, value);
} else {
declarations.insert_or_assign(std::string{name}, std::string{value});
}
}
 
void expand_padding(std::map<std::string, std::string>& declarations, std::string_view value) {
std::string_view top = "", bottom = "", left = "", right = "";
auto values = split(value, ' ');
switch (values.size()) {
case 1:
top = bottom = left = right = values[0];
break;
case 2:
top = bottom = values[0];
left = right = values[1];
break;
case 3:
top = values[0];
left = right = values[1];
bottom = values[2];
break;
case 4:
top = values[0];
right = values[1];
bottom = values[2];
left = values[3];
break;
default:
break;
}
declarations.insert_or_assign("padding-top", std::string{top});
declarations.insert_or_assign("padding-bottom", std::string{bottom});
declarations.insert_or_assign("padding-left", std::string{left});
declarations.insert_or_assign("padding-right", std::string{right});
}
 
std::vector<std::string_view> split(std::string_view str, char delimiter) {
std::vector<std::string_view> result;
std::size_t pos = 0, loc = 0;
while ((loc = str.find(delimiter, pos)) != std::string_view::npos) {
if (auto substr = str.substr(pos, loc-pos); !substr.empty()) {
result.push_back(substr);
}
pos = loc+1;
}
if (pos < str.size()) {
result.push_back(str.substr(pos, str.size()-pos));
}
return result;
}
};
 
 
css/parser_test.cpp added: 142, removed: 5, total 137
@@ -134,5 +134,85 @@ int main() {
expect(a.media_query.empty());
});
 
etest::test("parser: shorthand padding, one value", [] {
auto rules = css::parse("p { padding: 10px; }"sv);
require(rules.size() == 1);
 
auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "10px"s);
expect(body.declarations.at("padding-bottom"s) == "10px"s);
expect(body.declarations.at("padding-left"s) == "10px"s);
expect(body.declarations.at("padding-right"s) == "10px"s);
});
 
etest::test("parser: shorthand padding, two values", [] {
auto rules = css::parse("p { padding: 12em 36em; }"sv);
require(rules.size() == 1);
 
auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "12em"s);
expect(body.declarations.at("padding-bottom"s) == "12em"s);
expect(body.declarations.at("padding-left"s) == "36em"s);
expect(body.declarations.at("padding-right"s) == "36em"s);
});
 
etest::test("parser: shorthand padding, three values", [] {
auto rules = css::parse("p { padding: 12px 36px 52px; }"sv);
require(rules.size() == 1);
 
auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "12px"s);
expect(body.declarations.at("padding-bottom"s) == "52px"s);
expect(body.declarations.at("padding-left"s) == "36px"s);
expect(body.declarations.at("padding-right"s) == "36px"s);
});
 
etest::test("parser: shorthand padding, four values", [] {
auto rules = css::parse("p { padding: 12px 36px 52px 2px; }"sv);
require(rules.size() == 1);
 
auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "12px"s);
expect(body.declarations.at("padding-right"s) == "36px"s);
expect(body.declarations.at("padding-bottom"s) == "52px"s);
expect(body.declarations.at("padding-left"s) == "2px"s);
});
 
etest::test("parser: shorthand padding overridden", [] {
auto rules = css::parse("p {\n"
"padding: 10px;\n"
"padding-top: 15px;\n"
"padding-left: 25px;\n"
"}\n"sv);
require(rules.size() == 1);
 
auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "15px"s);
expect(body.declarations.at("padding-bottom"s) == "10px"s);
expect(body.declarations.at("padding-left"s) == "25px"s);
expect(body.declarations.at("padding-right"s) == "10px"s);
});
 
etest::test("parser: override padding with shorthand", [] {
auto rules = css::parse("p {\n"
"padding-bottom: 5px;\n"
"padding-left: 25px;\n"
"padding: 12px 40px;\n"
"}\n"sv);
require(rules.size() == 1);
 
auto body = rules[0];
expect(body.declarations.size() == 4);
expect(body.declarations.at("padding-top"s) == "12px"s);
expect(body.declarations.at("padding-bottom"s) == "12px"s);
expect(body.declarations.at("padding-left"s) == "40px"s);
expect(body.declarations.at("padding-right"s) == "40px"s);
});
 
return etest::run_all_tests();
}