Allow percentage values with a fractional component (implements https://github.com/mapnik/mapnik/issues/4437)

(https://www.w3.org/TR/css-color-4/#funcdef-rgba)
This commit is contained in:
Artem Pavlenko 2024-04-15 14:09:04 +01:00
parent 93ab8b4690
commit 5ac45af78e
2 changed files with 53 additions and 16 deletions

View file

@ -352,9 +352,9 @@ auto const rgb_color_def = lit("rgb")
>> attr(255) >> lit(')'); >> attr(255) >> lit(')');
auto const rgb_color_percent_def = lit("rgb") auto const rgb_color_percent_def = lit("rgb")
>> lit('(') >> dec3[percent_red] >> lit('%') >> lit('(') >> double_[percent_red] >> lit('%')
>> lit(',') >> dec3[percent_green] >> lit('%') >> lit(',') >> double_[percent_green] >> lit('%')
>> lit(',') >> dec3[percent_blue] >> lit('%') >> lit(',') >> double_[percent_blue] >> lit('%')
>> attr(255) >> lit(')'); >> attr(255) >> lit(')');
auto const rgba_color_def = lit("rgba") auto const rgba_color_def = lit("rgba")
@ -364,24 +364,24 @@ auto const rgba_color_def = lit("rgba")
>> lit(',') >> double_[opacity] >> lit(')'); >> lit(',') >> double_[opacity] >> lit(')');
auto const rgba_color_percent_def = lit("rgba") auto const rgba_color_percent_def = lit("rgba")
>> lit('(') >> dec3[percent_red] >> lit('%') >> lit('(') >> double_[percent_red] >> lit('%')
>> lit(',') >> dec3[percent_green] >> lit('%') >> lit(',') >> double_[percent_green] >> lit('%')
>> lit(',') >> dec3[percent_blue] >> lit('%') >> lit(',') >> double_[percent_blue] >> lit('%')
>> lit(',') >> double_[opacity] >> lit(')'); >> lit(',') >> double_[opacity] >> lit(')');
auto const hsl_values = x3::rule<class hsl_values, std::tuple<std::uint16_t,std::uint8_t,std::uint8_t, double >> {} = auto const hsl_values = x3::rule<class hsl_values, std::tuple<std::uint16_t, double, double, double >> {} =
lit("hsl") lit("hsl")
>> lit('(') >> dec3 >> lit('(') >> dec3
>> lit(',') >> dec3 >> lit('%') >> lit(',') >> double_ >> lit('%')
>> lit(',') >> dec3 >> lit('%') >> lit(',') >> double_ >> lit('%')
>> attr(1.0) >> lit(')') >> attr(1.0) >> lit(')')
; ;
auto const hsla_values = x3::rule<class hsla_values, std::tuple<std::uint16_t,std::uint8_t,std::uint8_t, double >> {} = auto const hsla_values = x3::rule<class hsla_values, std::tuple<std::uint16_t, double, double, double >> {} =
lit("hsla") lit("hsla")
>> lit('(') >> dec3 >> lit('(') >> dec3
>> lit(',') >> dec3 >> lit('%') >> lit(',') >> double_ >> lit('%')
>> lit(',') >> dec3 >> lit('%') >> lit(',') >> double_ >> lit('%')
>> lit(',') >> double_ >> lit(')') >> lit(',') >> double_ >> lit(')')
; ;

View file

@ -14,6 +14,9 @@ TEST_CASE("CSS color")
using namespace mapnik::css_color_grammar; using namespace mapnik::css_color_grammar;
CHECK(percent_converter::call(1.0) == 3); CHECK(percent_converter::call(1.0) == 3);
CHECK(percent_converter::call(60.0) == 153); CHECK(percent_converter::call(60.0) == 153);
CHECK(percent_converter::call(10) == 26);
CHECK(percent_converter::call(35) == 89);
CHECK(percent_converter::call(35.4999) == 91);
// should not overflow on invalid input // should not overflow on invalid input
CHECK(percent_converter::call(100000.0) == 255); CHECK(percent_converter::call(100000.0) == 255);
CHECK(percent_converter::call(-100000.0) == 0); CHECK(percent_converter::call(-100000.0) == 0);
@ -35,13 +38,20 @@ TEST_CASE("CSS color")
} }
{ {
// rgb (percent) // rgb (percent)
std::string s("rgb(50%,0%,100%)"); std::string s1("rgb(50%,0%,100%)");
mapnik::color c; mapnik::color c;
CHECK(boost::spirit::x3::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c)); CHECK(boost::spirit::x3::phrase_parse(s1.cbegin(), s1.cend(), color_grammar, space, c));
CHECK(c.alpha() == 0xff); CHECK(c.alpha() == 0xff);
CHECK(c.red() == 0x80); CHECK(c.red() == 0x80);
CHECK(c.green() == 0x00); CHECK(c.green() == 0x00);
CHECK(c.blue() == 0xff); CHECK(c.blue() == 0xff);
// rgb (fractional percent)
std::string s2("rgb(50.5%,0.5%,99.5%)"); // #8101fe
CHECK(boost::spirit::x3::phrase_parse(s2.cbegin(), s2.cend(), color_grammar, space, c));
CHECK(c.alpha() == 0xff);
CHECK(c.red() == 0x81);
CHECK(c.green() == 0x01);
CHECK(c.blue() == 0xfe);
} }
{ {
// rgba // rgba
@ -55,13 +65,20 @@ TEST_CASE("CSS color")
} }
{ {
// rgba (percent) // rgba (percent)
std::string s("rgba(50%,0%,100%,0.5)"); std::string s1("rgba(50%,0%,100%,0.5)");
mapnik::color c; mapnik::color c;
CHECK(boost::spirit::x3::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c)); CHECK(boost::spirit::x3::phrase_parse(s1.cbegin(), s1.cend(), color_grammar, space, c));
CHECK(c.alpha() == 0x80); CHECK(c.alpha() == 0x80);
CHECK(c.red() == 0x80); CHECK(c.red() == 0x80);
CHECK(c.green() == 0x00); CHECK(c.green() == 0x00);
CHECK(c.blue() == 0xff); CHECK(c.blue() == 0xff);
// rgba (fractional percent)
std::string s2("rgb(50.5%,0.5%,99.5%)"); //#8101fe80
CHECK(boost::spirit::x3::phrase_parse(s2.cbegin(), s2.cend(), color_grammar, space, c));
CHECK(c.alpha() == 0x80);
CHECK(c.red() == 0x81);
CHECK(c.green() == 0x01);
CHECK(c.blue() == 0xfe);
} }
{ {
// named colours // named colours
@ -83,6 +100,16 @@ TEST_CASE("CSS color")
CHECK(c.green() == 64); CHECK(c.green() == 64);
CHECK(c.blue() == 191); CHECK(c.blue() == 191);
} }
// hsl (fractional percent)
{
std::string s("hsl(240,50.5%,49.5%)"); //Color(R=62,G=62,B=190,A=255)
mapnik::color c;
CHECK(boost::spirit::x3::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c));
CHECK(c.alpha() == 255);
CHECK(c.red() == 62);
CHECK(c.green() == 62);
CHECK(c.blue() == 190);
}
// hsl (hue range 0..360) // hsl (hue range 0..360)
{ {
std::string s1("hsl(0, 100%, 50%)"); std::string s1("hsl(0, 100%, 50%)");
@ -116,6 +143,16 @@ TEST_CASE("CSS color")
CHECK(c.green() == 64); CHECK(c.green() == 64);
CHECK(c.blue() == 191); CHECK(c.blue() == 191);
} }
// hsla (fractional percent)
{
std::string s("hsl(240,50.5%,49.5%,0.5)"); //Color(R=62,G=62,B=190,A=128)
mapnik::color c;
CHECK(boost::spirit::x3::phrase_parse(s.cbegin(), s.cend(), color_grammar, space, c));
CHECK(c.alpha() == 128);
CHECK(c.red() == 62);
CHECK(c.green() == 62);
CHECK(c.blue() == 190);
}
// hsla (hue range 0..360) // hsla (hue range 0..360)
{ {
std::string s1("hsla(0, 100%, 50%, 1)"); std::string s1("hsla(0, 100%, 50%, 1)");