initial support for strict SVG parsing (WIP)
This commit is contained in:
parent
df0bbe404c
commit
3f591af871
5 changed files with 53 additions and 32 deletions
|
@ -55,7 +55,7 @@ public:
|
|||
inline bool is_uri(std::string const& path) { return is_svg_uri(path) || is_image_uri(path); }
|
||||
bool is_svg_uri(std::string const& path);
|
||||
bool is_image_uri(std::string const& path);
|
||||
std::shared_ptr<marker const> find(std::string const& key, bool update_cache = false);
|
||||
std::shared_ptr<marker const> find(std::string const& key, bool update_cache = false, bool strict = false);
|
||||
void clear();
|
||||
};
|
||||
|
||||
|
|
|
@ -40,13 +40,14 @@ namespace mapnik { namespace svg {
|
|||
{
|
||||
using error_message_container = std::vector<std::string> ;
|
||||
public:
|
||||
explicit svg_parser(svg_converter_type & path);
|
||||
explicit svg_parser(svg_converter_type & path, bool strict = false);
|
||||
~svg_parser();
|
||||
error_message_container const& error_messages() const;
|
||||
bool parse(std::string const& filename);
|
||||
bool parse_from_string(std::string const& svg);
|
||||
svg_converter_type & path_;
|
||||
bool is_defs_;
|
||||
bool strict_;
|
||||
std::map<std::string, gradient> gradient_map_;
|
||||
std::pair<std::string, gradient> temporary_gradient_;
|
||||
error_message_container error_messages_;
|
||||
|
|
|
@ -141,7 +141,7 @@ struct visitor_create_marker
|
|||
} // end detail ns
|
||||
|
||||
std::shared_ptr<mapnik::marker const> marker_cache::find(std::string const& uri,
|
||||
bool update_cache)
|
||||
bool update_cache, bool strict)
|
||||
{
|
||||
if (uri.empty())
|
||||
{
|
||||
|
@ -174,15 +174,15 @@ std::shared_ptr<mapnik::marker const> marker_cache::find(std::string const& uri,
|
|||
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
|
||||
svg_path_adapter svg_path(stl_storage);
|
||||
svg_converter_type svg(svg_path, marker_path->attributes());
|
||||
svg_parser p(svg);
|
||||
svg_parser p(svg, strict);
|
||||
|
||||
if (!p.parse_from_string(known_svg_string))
|
||||
if (!p.parse_from_string(known_svg_string) && !strict)
|
||||
{
|
||||
for (auto const& msg : p.error_messages())
|
||||
{
|
||||
MAPNIK_LOG_ERROR(marker_cache) << "SVG PARSING ERROR:\"" << msg << "\"";
|
||||
}
|
||||
return std::make_shared<mapnik::marker const>(mapnik::marker_null());
|
||||
//return std::make_shared<mapnik::marker const>(mapnik::marker_null());
|
||||
}
|
||||
//svg.arrange_orientations();
|
||||
double lox,loy,hix,hiy;
|
||||
|
@ -214,16 +214,16 @@ std::shared_ptr<mapnik::marker const> marker_cache::find(std::string const& uri,
|
|||
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
|
||||
svg_path_adapter svg_path(stl_storage);
|
||||
svg_converter_type svg(svg_path, marker_path->attributes());
|
||||
svg_parser p(svg);
|
||||
svg_parser p(svg, strict);
|
||||
|
||||
|
||||
if (!p.parse(uri))
|
||||
if (!p.parse(uri) && !strict)
|
||||
{
|
||||
for (auto const& msg : p.error_messages())
|
||||
{
|
||||
MAPNIK_LOG_ERROR(marker_cache) << "SVG PARSING ERROR:\"" << msg << "\"";
|
||||
}
|
||||
return std::make_shared<mapnik::marker const>(mapnik::marker_null());
|
||||
//return std::make_shared<mapnik::marker const>(mapnik::marker_null());
|
||||
}
|
||||
//svg.arrange_orientations();
|
||||
double lox,loy,hix,hiy;
|
||||
|
|
|
@ -115,6 +115,15 @@ BOOST_SPIRIT_DEFINE(key, value, key_value, key_value_sequence_ordered);
|
|||
|
||||
}}
|
||||
|
||||
namespace {
|
||||
template <typename T>
|
||||
void on_error(T & error_messages, std::string const& msg, bool strict)
|
||||
{
|
||||
if (strict) throw std::runtime_error(msg);
|
||||
else error_messages.emplace_back(msg);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
mapnik::color parse_color(T & error_messages, const char* str)
|
||||
{
|
||||
|
@ -125,7 +134,7 @@ mapnik::color parse_color(T & error_messages, const char* str)
|
|||
}
|
||||
catch (mapnik::config_error const& ex)
|
||||
{
|
||||
error_messages.emplace_back(ex.what());
|
||||
on_error(error_messages, ex.what(), false);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
@ -144,7 +153,7 @@ double parse_double(T & error_messages, const char* str)
|
|||
double val = 0.0;
|
||||
if (!parse(str, str + std::strlen(str), double_, val))
|
||||
{
|
||||
error_messages.emplace_back("Failed to parse double: \"" + std::string(str) + "\"");
|
||||
on_error(error_messages,"Failed to parse double: \"" + std::string(str) + "\"", false);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
@ -178,12 +187,12 @@ double parse_svg_value(T & error_messages, const char* str, bool & is_percent)
|
|||
x3::lit('%')[apply_percent]),
|
||||
x3::space))
|
||||
{
|
||||
error_messages.emplace_back("Failed to parse SVG value: '" + std::string(str) + "'");
|
||||
on_error(error_messages,"Failed to parse SVG value: '" + std::string(str) + "'", false);
|
||||
}
|
||||
else if (cur != end)
|
||||
{
|
||||
error_messages.emplace_back("Failed to parse SVG value: '" + std::string(str) +
|
||||
"', trailing garbage: '" + cur + "'");
|
||||
on_error(error_messages,"Failed to parse SVG value: '" + std::string(str) +
|
||||
"', trailing garbage: '" + cur + "'", false);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
@ -198,7 +207,7 @@ bool parse_viewbox(T & error_messages, const char* str, V & viewbox)
|
|||
x3::double_ > -x3::lit(',') >
|
||||
x3::double_, x3::space, viewbox))
|
||||
{
|
||||
error_messages.emplace_back("failed to parse SVG viewbox from " + std::string(str));
|
||||
on_error(error_messages,"failed to parse SVG viewbox from " + std::string(str), false);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -261,7 +270,7 @@ bool traverse_tree(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
|||
else
|
||||
{
|
||||
parser.path_.push_attr();
|
||||
parse_attr(parser, node);
|
||||
//parse_attr(parser, node);
|
||||
if (parser.path_.display())
|
||||
{
|
||||
if (std::strcmp(name, "path") == 0)
|
||||
|
@ -299,6 +308,7 @@ bool traverse_tree(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
|||
else
|
||||
{
|
||||
//std::cerr << "unprocessed node <--[" << node->name() << "]\n";
|
||||
on_error(parser.error_messages_, std::string("Unsupported element:\"") + node->name(), parser.strict_);
|
||||
}
|
||||
}
|
||||
parser.path_.pop_attr();
|
||||
|
@ -387,7 +397,7 @@ void parse_attr(svg_parser & parser, char const* name, char const* value )
|
|||
{
|
||||
std::stringstream ss;
|
||||
ss << "Failed to find gradient fill: " << id;
|
||||
parser.error_messages_.push_back(ss.str());
|
||||
on_error(parser.error_messages_, ss.str(), parser.strict_);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -424,7 +434,7 @@ void parse_attr(svg_parser & parser, char const* name, char const* value )
|
|||
{
|
||||
std::stringstream ss;
|
||||
ss << "Failed to find gradient stroke: " << id;
|
||||
parser.error_messages_.push_back(ss.str());
|
||||
on_error(parser.error_messages_, ss.str(), parser.strict_);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -489,6 +499,10 @@ void parse_attr(svg_parser & parser, char const* name, char const* value )
|
|||
{
|
||||
parser.path_.display(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
on_error(parser.error_messages_, std::string("Unsupported attribute:\"") + name, parser.strict_);
|
||||
}
|
||||
}
|
||||
|
||||
void parse_attr(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
||||
|
@ -576,12 +590,12 @@ void parse_path(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
|||
if (id_attr == nullptr) id_attr = node->first_attribute("id");
|
||||
if (id_attr)
|
||||
{
|
||||
parser.error_messages_.push_back(std::string("unable to parse invalid svg <path> with id '")
|
||||
+ id_attr->value() + "'");
|
||||
on_error(parser.error_messages_, std::string("unable to parse invalid svg <path> with id '")
|
||||
+ id_attr->value() + "'", parser.strict_);
|
||||
}
|
||||
else
|
||||
{
|
||||
parser.error_messages_.push_back(std::string("unable to parse invalid svg <path>"));
|
||||
on_error(parser.error_messages_, std::string("unable to parse invalid svg <path>"), parser.strict_);
|
||||
}
|
||||
}
|
||||
parser.path_.end_path();
|
||||
|
@ -597,7 +611,7 @@ void parse_polygon(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
|||
parser.path_.begin_path();
|
||||
if (!mapnik::svg::parse_points(attr->value(), parser.path_))
|
||||
{
|
||||
parser.error_messages_.push_back(std::string("Failed to parse <polygon> 'points'"));
|
||||
on_error(parser.error_messages_, std::string("Failed to parse <polygon> 'points'"), parser.strict_);
|
||||
}
|
||||
parser.path_.close_subpath();
|
||||
parser.path_.end_path();
|
||||
|
@ -612,7 +626,7 @@ void parse_polyline(svg_parser & parser, rapidxml::xml_node<char> const* node)
|
|||
parser.path_.begin_path();
|
||||
if (!mapnik::svg::parse_points(attr->value(), parser.path_))
|
||||
{
|
||||
parser.error_messages_.push_back(std::string("Failed to parse <polyline> 'points'"));
|
||||
on_error(parser.error_messages_, std::string("Failed to parse <polyline> 'points'"), parser.strict_);
|
||||
}
|
||||
parser.path_.end_path();
|
||||
}
|
||||
|
@ -917,7 +931,7 @@ bool parse_common_gradient(svg_parser & parser, rapidxml::xml_node<char> const*
|
|||
{
|
||||
std::stringstream ss;
|
||||
ss << "Failed to find linked gradient " << linkid;
|
||||
parser.error_messages_.push_back(ss.str());
|
||||
on_error(parser.error_messages_, ss.str(), parser.strict_);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -981,8 +995,7 @@ void parse_radial_gradient(svg_parser & parser, rapidxml::xml_node<char> const*
|
|||
{
|
||||
fy = parse_svg_value(parser.error_messages_, attr->value(), has_percent);
|
||||
}
|
||||
else
|
||||
fy = cy;
|
||||
else fy = cy;
|
||||
|
||||
attr = node->first_attribute("r");
|
||||
if (attr != nullptr)
|
||||
|
@ -1049,9 +1062,10 @@ void parse_linear_gradient(svg_parser & parser, rapidxml::xml_node<char> const*
|
|||
}
|
||||
|
||||
svg_parser::svg_parser(svg_converter<svg_path_adapter,
|
||||
agg::pod_bvector<mapnik::svg::path_attributes> > & path)
|
||||
agg::pod_bvector<mapnik::svg::path_attributes> > & path, bool strict)
|
||||
: path_(path),
|
||||
is_defs_(false) {}
|
||||
is_defs_(false),
|
||||
strict_(strict) {}
|
||||
|
||||
svg_parser::~svg_parser() {}
|
||||
|
||||
|
|
|
@ -144,6 +144,7 @@ int main (int argc,char** argv)
|
|||
|
||||
bool verbose = false;
|
||||
bool auto_open = false;
|
||||
bool strict = false;
|
||||
int status = 0;
|
||||
std::vector<std::string> svg_files;
|
||||
mapnik::logger::instance().set_severity(mapnik::logger::error);
|
||||
|
@ -156,18 +157,19 @@ int main (int argc,char** argv)
|
|||
("version,V","print version string")
|
||||
("verbose,v","verbose output")
|
||||
("open","automatically open the file after rendering (os x only)")
|
||||
("strict","enables strict SVG parsing")
|
||||
("svg",po::value<std::vector<std::string> >(),"svg file to read")
|
||||
;
|
||||
|
||||
po::positional_options_description p;
|
||||
p.add("svg",-1);
|
||||
p.add("svg", -1);
|
||||
po::variables_map vm;
|
||||
po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), vm);
|
||||
po::notify(vm);
|
||||
|
||||
if (vm.count("version"))
|
||||
{
|
||||
std::clog <<"version " << MAPNIK_VERSION_STRING << std::endl;
|
||||
std::clog << "version " << MAPNIK_VERSION_STRING << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -187,6 +189,11 @@ int main (int argc,char** argv)
|
|||
auto_open = true;
|
||||
}
|
||||
|
||||
if (vm.count("strict"))
|
||||
{
|
||||
strict = true;
|
||||
}
|
||||
|
||||
if (vm.count("svg"))
|
||||
{
|
||||
svg_files=vm["svg"].as< std::vector<std::string> >();
|
||||
|
@ -211,8 +218,7 @@ int main (int argc,char** argv)
|
|||
{
|
||||
std::clog << "found: " << svg_name << "\n";
|
||||
}
|
||||
|
||||
std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false);
|
||||
std::shared_ptr<mapnik::marker const> marker = mapnik::marker_cache::instance().find(svg_name, false, strict);
|
||||
main_marker_visitor visitor(svg_name, verbose, auto_open);
|
||||
status = mapnik::util::apply_visitor(visitor, *marker);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue