Add viewbox fallback logic for dimension parsing
SVG's now have fallback on viewbox. Still debugging the boost Qi parser
This commit is contained in:
parent
8c2f15c94a
commit
a787d20e36
3 changed files with 66 additions and 10 deletions
|
@ -158,19 +158,20 @@ double parse_double_optional_percent(T & error_messages, const char* str, bool &
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
bool parse_integer_list(T & error_messages, const char* str, int* list)
|
||||
bool parse_double_list(T & error_messages, const char* str, double* list)
|
||||
{
|
||||
using namespace boost::spirit::qi;
|
||||
using boost::phoenix::ref;
|
||||
qi::_1_type _1;
|
||||
qi::int_type int_;
|
||||
qi::double_type double_;
|
||||
qi::char_type char_;
|
||||
|
||||
if (!parse(str, str + std::strlen(str), int_[ref(list[0])=_1] >> ' ' | ','
|
||||
>> int_[ref(list[1])=_1] >> ' ' | ','
|
||||
>> int_[ref(list[2])=_1] >> ' ' | ','
|
||||
>> int_[ref(list[3])=_1]))
|
||||
if (!parse(str, str + std::strlen(str), double_[ref(list[0])=_1] >> char_(' ') | char_(',')
|
||||
>> double_[ref(list[1])=_1] >> char_(' ') | char_(',')
|
||||
>> double_[ref(list[2])=_1] >> char_(' ') | char_(',')
|
||||
>> double_[ref(list[3])=_1]))
|
||||
{
|
||||
error_messages.emplace_back("failed to parse list of integers from " + std::string(str));
|
||||
error_messages.emplace_back("failed to parse list of doubles from " + std::string(str));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -484,16 +485,51 @@ void parse_dimensions(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
|||
{
|
||||
double width = 0;
|
||||
double height = 0;
|
||||
double aspect_ratio = 1;
|
||||
double viewbox[4] = {0,0,0,0};
|
||||
bool has_viewbox = false;
|
||||
bool has_percent_height = true;
|
||||
bool has_percent_width = true;
|
||||
|
||||
auto const* width_attr = node->first_attribute("width");
|
||||
if (width_attr)
|
||||
{
|
||||
width = parse_double(parser.error_messages_, width_attr->value());
|
||||
width = parse_double_optional_percent(parser.error_messages_, width_attr->value(), has_percent_width);
|
||||
}
|
||||
auto const* height_attr = node->first_attribute("height");
|
||||
if (height_attr)
|
||||
{
|
||||
height = parse_double(parser.error_messages_, height_attr->value());
|
||||
height = parse_double_optional_percent(parser.error_messages_, height_attr->value(), has_percent_height);
|
||||
}
|
||||
auto const* viewbox_attr = node->first_attribute("viewBox");
|
||||
if (viewbox_attr)
|
||||
{
|
||||
has_viewbox = parse_double_list(parser.error_messages_, viewbox_attr->value(), viewbox);
|
||||
}
|
||||
|
||||
std::cout << "Width = " << width << std::endl;
|
||||
std::cout << "Width has percent = " << has_percent_width << std::endl;
|
||||
std::cout << "Height has percent = " << has_percent_height << std::endl;
|
||||
std::cout << "Viewbox = " << viewbox[0] << "," << viewbox[1] << "," << viewbox[2] << "," << viewbox[3] << std::endl;
|
||||
std::cout << "Viewbox exists = " << has_viewbox << std::endl;
|
||||
|
||||
|
||||
if (has_percent_width && !has_percent_height && has_viewbox)
|
||||
{
|
||||
aspect_ratio = viewbox[2] / viewbox[3];
|
||||
width = aspect_ratio * height;
|
||||
}
|
||||
else if (!has_percent_width && has_percent_height && has_viewbox)
|
||||
{
|
||||
aspect_ratio = viewbox[2] / viewbox[3];
|
||||
height = height / aspect_ratio;
|
||||
}
|
||||
else if (has_percent_width && has_percent_height && has_viewbox)
|
||||
{
|
||||
width = viewbox[2];
|
||||
height = viewbox[3];
|
||||
}
|
||||
|
||||
parser.path_.set_dimensions(width, height);
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 07ea03efceb0631d0436dca3184b1211acb32cdd
|
||||
Subproject commit 644f8db7b62720e436aaa0489338029fcae771e6
|
|
@ -333,6 +333,26 @@ TEST_CASE("SVG parser") {
|
|||
REQUIRE(std::equal(expected.begin(),expected.end(), vec.begin(),detail::vertex_equal<3>()));
|
||||
}
|
||||
|
||||
SECTION("SVG viewbox fallback")
|
||||
{
|
||||
std::string svg_name("./test/data/svg/viewbox-missing-width-and-height.svg");
|
||||
std::ifstream in(svg_name.c_str());
|
||||
std::string svg_str((std::istreambuf_iterator<char>(in)),
|
||||
std::istreambuf_iterator<char>());
|
||||
|
||||
using namespace mapnik::svg;
|
||||
mapnik::svg_storage_type path;
|
||||
vertex_stl_adapter<svg_path_storage> stl_storage(path.source());
|
||||
svg_path_adapter svg_path(stl_storage);
|
||||
svg_converter_type svg(svg_path, path.attributes());
|
||||
svg_parser p(svg);
|
||||
p.parse_from_string(svg_str);
|
||||
auto width = svg.width();
|
||||
auto height = svg.height();
|
||||
REQUIRE(width == 100);
|
||||
REQUIRE(height == 100);
|
||||
}
|
||||
|
||||
SECTION("SVG rounded <rect>s missing rx or ry")
|
||||
{
|
||||
std::string svg_name("./test/data/svg/rounded_rect-missing-one-radius.svg");
|
||||
|
|
Loading…
Add table
Reference in a new issue