make svg_path_grammar and svg_points_grammar stateless ref #3343

(https://github.com/mapnik/mapnik/pull/2231)
This commit is contained in:
artemp 2016-03-04 12:41:06 +01:00
parent 12aec35e2f
commit 4659f40401
5 changed files with 179 additions and 252 deletions

View file

@ -35,189 +35,128 @@
#include <boost/spirit/include/phoenix_operator.hpp>
#pragma GCC diagnostic pop
namespace mapnik { namespace svg {
namespace mapnik {
namespace svg {
using namespace boost::fusion;
inline double deg2rad(double deg)
{
return (M_PI * deg)/180.0;
return (M_PI * deg) / 180.0;
}
template <typename PathType>
struct move_to
{
using result_type = void;
explicit move_to(PathType & path)
: path_(path) {}
template <typename T0, typename T1>
void operator() (T0 v, T1 rel) const
template <typename PathType, typename T0, typename T1>
void operator()(PathType& path, T0 v, T1 rel) const
{
path_.move_to(at_c<0>(v),at_c<1>(v),rel); // impl
path.move_to(at_c<0>(v), at_c<1>(v), rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct hline_to
{
using result_type = void;
explicit hline_to(PathType & path)
: path_(path) {}
template <typename T0, typename T1>
void operator() (T0 const& x, T1 rel) const
template <typename PathType, typename T0, typename T1>
void operator()(PathType& path, T0 const& x, T1 rel) const
{
path_.hline_to(x,rel);
path.hline_to(x, rel);
}
PathType & path_;
};
template <typename PathType>
struct vline_to
{
using result_type = void;
explicit vline_to(PathType & path)
: path_(path) {}
template <typename T0, typename T1>
void operator() (T0 const& y, T1 rel) const
template <typename PathType, typename T0, typename T1>
void operator()(PathType& path, T0 const& y, T1 rel) const
{
path_.vline_to(y,rel);
path.vline_to(y, rel);
}
PathType & path_;
};
template <typename PathType>
struct line_to
{
using result_type = void;
explicit line_to(PathType & path)
: path_(path) {}
template <typename T0, typename T1>
void operator() (T0 const& v, T1 rel) const
template <typename PathType, typename T0, typename T1>
void operator()(PathType& path, T0 const& v, T1 rel) const
{
path_.line_to(at_c<0>(v),at_c<1>(v),rel); // impl
path.line_to(at_c<0>(v), at_c<1>(v), rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct curve4
{
using result_type = void;
explicit curve4(PathType & path)
: path_(path) {}
template <typename T0, typename T1,typename T2, typename T3>
void operator() (T0 const& v0, T1 const& v1, T2 const& v2, T3 rel) const
template <typename PathType, typename T0, typename T1, typename T2, typename T3>
void operator()(PathType& path, T0 const& v0, T1 const& v1, T2 const& v2, T3 rel) const
{
path_.curve4(at_c<0>(v0),at_c<1>(v0),
at_c<0>(v1),at_c<1>(v1),
at_c<0>(v2),at_c<1>(v2),
rel); // impl
path.curve4(at_c<0>(v0), at_c<1>(v0),
at_c<0>(v1), at_c<1>(v1),
at_c<0>(v2), at_c<1>(v2),
rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct curve4_smooth
{
using result_type = void;
explicit curve4_smooth(PathType & path)
: path_(path) {}
template <typename T0, typename T1,typename T2>
void operator() (T0 const& v0, T1 const& v1, T2 rel) const
template <typename PathType, typename T0, typename T1, typename T2>
void operator()(PathType& path, T0 const& v0, T1 const& v1, T2 rel) const
{
path_.curve4(at_c<0>(v0),at_c<1>(v0),
at_c<0>(v1),at_c<1>(v1),
rel); // impl
path.curve4(at_c<0>(v0), at_c<1>(v0),
at_c<0>(v1), at_c<1>(v1),
rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct curve3
{
using result_type = void;
explicit curve3(PathType & path)
: path_(path) {}
template <typename T0, typename T1,typename T2>
void operator() (T0 const& v0, T1 const& v1, T2 rel) const
template <typename PathType, typename T0, typename T1, typename T2>
void operator()(PathType& path, T0 const& v0, T1 const& v1, T2 rel) const
{
path_.curve3(at_c<0>(v0),at_c<1>(v0),
at_c<0>(v1),at_c<1>(v1),
rel); // impl
path.curve3(at_c<0>(v0), at_c<1>(v0),
at_c<0>(v1), at_c<1>(v1),
rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct curve3_smooth
{
using result_type = void;
explicit curve3_smooth(PathType & path)
: path_(path) {}
template <typename T0, typename T1>
void operator() (T0 const& v0, T1 rel) const
template <typename PathType, typename T0, typename T1>
void operator()(PathType& path, T0 const& v0, T1 rel) const
{
path_.curve3(at_c<0>(v0),at_c<1>(v0),
rel); // impl
path.curve3(at_c<0>(v0), at_c<1>(v0),
rel); // impl
}
PathType & path_;
};
template <typename PathType>
struct arc_to
{
using result_type = void;
explicit arc_to(PathType & path)
: path_(path) {}
template <typename T0, typename T1,typename T2, typename T3, typename T4, typename T5>
void operator() (T0 const& rv, T1 const& angle, T2 large_arc_flag, T3 sweep_flag, T4 const& v, T5 rel) const
template <typename PathType, typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
void operator()(PathType& path, T0 const& rv, T1 const& angle, T2 large_arc_flag, T3 sweep_flag, T4 const& v, T5 rel) const
{
path_.arc_to(at_c<0>(rv),at_c<1>(rv),
deg2rad(angle),large_arc_flag,sweep_flag,
at_c<0>(v),at_c<1>(v),
rel);
path.arc_to(at_c<0>(rv), at_c<1>(rv),
deg2rad(angle), large_arc_flag, sweep_flag,
at_c<0>(v), at_c<1>(v),
rel);
}
PathType & path_;
};
template <typename PathType>
struct close
{
using result_type = void;
explicit close(PathType & path)
: path_(path) {}
void operator()() const
template <typename PathType>
void operator()(PathType& path) const
{
path_.close_subpath();
path.close_subpath();
}
PathType & path_;
};
}}
} // namespace svg
} // namespace mapnik
#endif // MAPNIK_SVG_COMMANDS_HPP

View file

@ -34,103 +34,95 @@
namespace mapnik { namespace svg {
using namespace boost::spirit;
using namespace boost::phoenix;
using namespace boost::spirit;
using namespace boost::phoenix;
template <typename Iterator, typename SkipType, typename PathType>
struct svg_path_grammar : qi::grammar<Iterator,SkipType>
template <typename Iterator, typename PathType, typename SkipType>
struct svg_path_grammar : qi::grammar<Iterator, void(PathType&), SkipType>
{
svg_path_grammar()
: svg_path_grammar::base_type(start)
{
explicit svg_path_grammar(PathType & path)
: svg_path_grammar::base_type(start),
move_to_(move_to<PathType>(path)),
hline_to_(hline_to<PathType>(path)),
vline_to_(vline_to<PathType>(path)),
line_to_(line_to<PathType>(path)),
curve4_(curve4<PathType>(path)),
curve4_smooth_(curve4_smooth<PathType>(path)),
curve3_(curve3<PathType>(path)),
curve3_smooth_(curve3_smooth<PathType>(path)),
arc_to_(arc_to<PathType>(path)),
close_(close<PathType>(path))
{
qi::_1_type _1;
qi::_2_type _2;
qi::_3_type _3;
qi::_4_type _4;
qi::_5_type _5;
qi::_a_type _a;
qi::lit_type lit;
qi::double_type double_;
qi::int_type int_;
qi::no_case_type no_case;
qi::_1_type _1;
qi::_2_type _2;
qi::_3_type _3;
qi::_4_type _4;
qi::_5_type _5;
qi::_a_type _a;
qi::lit_type lit;
qi::_r1_type _r1;
qi::double_type double_;
qi::int_type int_;
qi::no_case_type no_case;
start = +cmd;
cmd = M >> *drawto_cmd;
drawto_cmd = L | H | V | C | S | Q | T | A | Z;
start = +cmd(_r1);
M = (lit('M')[_a = false] | lit('m')[_a = true] )
>> coord[move_to_(_1,_a)] // move_to
>> *(-lit(',') >> coord [ line_to_(_1,_a) ] ); // *line_to
cmd = M(_r1) >> *drawto_cmd(_r1);
H = (lit('H')[_a = false] | lit('h')[_a = true])
>> (double_[ hline_to_(_1,_a) ] % -lit(',')) ; // +hline_to
drawto_cmd = L(_r1) | H(_r1) | V(_r1) | C(_r1) | S(_r1) | Q(_r1) | T(_r1) | A(_r1) | Z(_r1);
V = (lit('V')[_a = false] | lit('v')[_a = true])
>> (double_ [ vline_to_(_1,_a) ] % -lit(',')); // +vline_to
M = (lit('M')[_a = false] | lit('m')[_a = true]) >> coord[move_to_(_r1, _1, _a)] // move_to
>> *(-lit(',') >> coord[line_to_(_r1, _1, _a)]); // *line_to
L = (lit('L')[_a = false] | lit('l')[_a = true])
>> (coord [ line_to_(_1,_a) ] % -lit(',')); // +line_to
H = (lit('H')[_a = false] | lit('h')[_a = true])
>> (double_[ hline_to_(_r1, _1,_a) ] % -lit(',')) ; // +hline_to
C = (lit('C')[_a = false] | lit('c')[_a = true])
>> ((coord >> -lit(',') >> coord >> -lit(',') >> coord) [ curve4_(_1,_2,_3,_a) ] % -lit(',')); // +curve4
V = (lit('V')[_a = false] | lit('v')[_a = true])
>> (double_ [ vline_to_(_r1, _1,_a) ] % -lit(',')); // +vline_to
S = (lit('S')[_a = false] | lit('s')[_a = true])
>> ((coord >> -lit(',') >> coord) [ curve4_smooth_(_1,_2,_a) ] % -lit(',')); // +curve4_smooth (smooth curveto)
L = (lit('L')[_a = false] | lit('l')[_a = true])
>> (coord [ line_to_(_r1, _1, _a) ] % -lit(',')); // +line_to
Q = (lit('Q')[_a = false] | lit('q')[_a = true])
>> ((coord >> -lit(',') >> coord) [ curve3_(_1,_2,_a) ] % -lit(',')); // +curve3 (quadratic-bezier-curveto)
C = (lit('C')[_a = false] | lit('c')[_a = true])
>> ((coord >> -lit(',') >> coord >> -lit(',') >> coord)[curve4_(_r1, _1, _2, _3, _a)] % -lit(',')); // +curve4
T = (lit('T')[_a = false] | lit('t')[_a = true])
>> ((coord ) [ curve3_smooth_(_1,_a) ] % -lit(',')); // +curve3_smooth (smooth-quadratic-bezier-curveto)
S = (lit('S')[_a = false] | lit('s')[_a = true])
>> ((coord >> -lit(',') >> coord) [ curve4_smooth_(_r1, _1,_2,_a) ] % -lit(',')); // +curve4_smooth (smooth curveto)
A = (lit('A')[_a = false] | lit('a')[_a = true])
>> ((coord >> -lit(',') >> double_ >> -lit(',')
>> int_ >> -lit(',') >> int_ >> -lit(',') >> coord) [arc_to_(_1,_2,_3,_4,_5,_a)] % -lit(',')); // arc_to;
Q = (lit('Q')[_a = false] | lit('q')[_a = true])
>> ((coord >> -lit(',') >> coord) [ curve3_(_r1, _1,_2,_a) ] % -lit(',')); // +curve3 (quadratic-bezier-curveto)
Z = no_case[lit('z')] [close_()]; // close path
T = (lit('T')[_a = false] | lit('t')[_a = true])
>> ((coord ) [ curve3_smooth_(_r1, _1,_a) ] % -lit(',')); // +curve3_smooth (smooth-quadratic-bezier-curveto)
coord = double_ >> -lit(',') >> double_;
}
A = (lit('A')[_a = false] | lit('a')[_a = true])
>> ((coord >> -lit(',') >> double_ >> -lit(',') >> int_ >> -lit(',') >> int_ >> -lit(',') >> coord)
[arc_to_(_r1, _1, _2, _3, _4, _5, _a)] % -lit(',')); // arc_to;
// rules
qi::rule<Iterator,SkipType> start;
qi::rule<Iterator,SkipType> cmd;
qi::rule<Iterator,SkipType> drawto_cmd;
qi::rule<Iterator,qi::locals<bool>,SkipType> M; // M,m
qi::rule<Iterator,qi::locals<bool>,SkipType> L; // L,l
qi::rule<Iterator,qi::locals<bool>,SkipType> H; // H,h
qi::rule<Iterator,qi::locals<bool>,SkipType> V; // V,v
qi::rule<Iterator,qi::locals<bool>,SkipType> C; // C,c
qi::rule<Iterator,qi::locals<bool>,SkipType> S; // S,s
qi::rule<Iterator,qi::locals<bool>,SkipType> Q; // Q,q
qi::rule<Iterator,qi::locals<bool>,SkipType> T; // T,t
qi::rule<Iterator,qi::locals<bool>,SkipType> A; // A,a
qi::rule<Iterator,SkipType> Z; // Z,z
Z = no_case[lit('z')] [close_(_r1)]; // close path
qi::rule<Iterator,boost::fusion::vector2<double,double>(),SkipType> coord;
coord = double_ >> -lit(',') >> double_;
}
// commands
function<move_to<PathType> > move_to_;
function<hline_to<PathType> > hline_to_;
function<vline_to<PathType> > vline_to_;
function<line_to<PathType> > line_to_;
function<curve4<PathType> > curve4_;
function<curve4_smooth<PathType> > curve4_smooth_;
function<curve3<PathType> > curve3_;
function<curve3_smooth<PathType> > curve3_smooth_;
function<arc_to<PathType> > arc_to_;
function<close<PathType> > close_;
};
// rules
qi::rule<Iterator, void(PathType&), SkipType> start;
qi::rule<Iterator, void(PathType&), SkipType> cmd;
qi::rule<Iterator, void(PathType&), SkipType> drawto_cmd;
qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> M; // M,m
qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> L; // L,l
qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> H; // H,h
qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> V; // V,v
qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> C; // C,c
qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> S; // S,s
qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> Q; // Q,q
qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> T; // T,t
qi::rule<Iterator, qi::locals<bool>, void(PathType&), SkipType> A; // A,a
qi::rule<Iterator, void(PathType&), SkipType> Z; // Z,z
qi::rule<Iterator, boost::fusion::vector2<double, double>(), SkipType> coord;
// commands
function<move_to> move_to_;
function<hline_to> hline_to_;
function<vline_to> vline_to_;
function<line_to> line_to_;
function<curve4> curve4_;
function<curve4_smooth> curve4_smooth_;
function<curve3> curve3_;
function<curve3_smooth> curve3_smooth_;
function<arc_to> arc_to_;
function<close> close_;
};
}}

View file

@ -36,39 +36,37 @@
namespace mapnik { namespace svg {
using namespace boost::spirit;
using namespace boost::phoenix;
using namespace boost::spirit;
using namespace boost::phoenix;
template <typename Iterator, typename SkipType, typename PathType>
struct svg_points_grammar : qi::grammar<Iterator,SkipType>
template <typename Iterator, typename PathType, typename SkipType>
struct svg_points_grammar : qi::grammar<Iterator, void(PathType&), SkipType>
{
svg_points_grammar()
: svg_points_grammar::base_type(start)
{
explicit svg_points_grammar(PathType & path)
: svg_points_grammar::base_type(start),
move_to_(move_to<PathType>(path)),
line_to_(line_to<PathType>(path)),
close_(close<PathType>(path))
{
qi::_1_type _1;
qi::lit_type lit;
qi::double_type double_;
qi::_1_type _1;
qi::_r1_type _r1;
qi::lit_type lit;
qi::double_type double_;
start = coord[move_to_(_1,false)] // move_to
>> *(-lit(',') >> coord [ line_to_(_1,false) ] ); // *line_to
start = coord[move_to_(_r1, _1, false)] // move_to
>> *(-lit(',') >> coord [ line_to_(_r1, _1,false) ] ); // *line_to
coord = double_ >> -lit(',') >> double_;
}
coord = double_ >> -lit(',') >> double_;
}
// rules
qi::rule<Iterator,SkipType> start;
qi::rule<Iterator,boost::fusion::vector2<double,double>(),SkipType> coord;
// rules
qi::rule<Iterator, void(PathType&), SkipType> start;
qi::rule<Iterator,boost::fusion::vector2<double,double>(),SkipType> coord;
// commands
function<move_to<PathType> > move_to_;
function<line_to<PathType> > line_to_;
function<close<PathType> > close_;
};
// commands
function<move_to> move_to_;
function<line_to> line_to_;
function<close> close_;
};
}}
}}
#endif // SVG_POINTS_GRAMMAR_HPP

View file

@ -21,35 +21,34 @@
*****************************************************************************/
// mapnik
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/svg/svg_path_parser.hpp>
#include <mapnik/svg/svg_path_grammar.hpp>
#include <mapnik/svg/svg_converter.hpp>
#include <mapnik/svg/svg_path_attributes.hpp>
#include <mapnik/svg/svg_path_grammar.hpp>
#include <mapnik/svg/svg_path_parser.hpp>
// agg
#include "agg_path_storage.h"
// stl
#include <string>
#include <cstring>
#include <string>
namespace mapnik { namespace svg {
namespace mapnik {
namespace svg {
template <typename PathType>
bool parse_path(const char* wkt, PathType & p)
{
using namespace boost::spirit;
using iterator_type = const char*;
using skip_type = ascii::space_type;
// FIXME! - for best performance this needs to be static const
// but for that not to crash the argument needs to be passed to phrase_parse
// rather than the grammar ctor - https://github.com/mapnik/mapnik/pull/2231
svg_path_grammar<iterator_type,skip_type,PathType> g(p);
iterator_type first = wkt;
iterator_type last = wkt + std::strlen(wkt);
bool status = qi::phrase_parse(first, last, g, skip_type());
return (status && (first == last));
}
template bool MAPNIK_DECL parse_path<svg_converter_type>(const char*, svg_converter_type&);
template <typename PathType>
bool parse_path(const char* wkt, PathType& p)
{
using namespace boost::spirit;
using iterator_type = const char*;
using skip_type = ascii::space_type;
static const svg_path_grammar<iterator_type, PathType, skip_type> g;
iterator_type first = wkt;
iterator_type last = wkt + std::strlen(wkt);
bool status = qi::phrase_parse(first, last, (g)(boost::phoenix::ref(p)), skip_type());
return (status && (first == last));
}
template bool MAPNIK_DECL parse_path<svg_converter_type>(const char*, svg_converter_type&);
}}
} // namespace svg
} // namespace mapnik

View file

@ -28,23 +28,22 @@
#include <string>
#include <cstring>
namespace mapnik { namespace svg {
namespace mapnik {
namespace svg {
template <typename PathType>
bool parse_points(const char* wkt, PathType & p)
{
using namespace boost::spirit;
using iterator_type = const char* ;
using skip_type = ascii::space_type;
// FIXME! - for best performance this needs to be static const
// but for that not to crash the argument needs to be passed to phrase_parse
// rather than the grammar ctor - https://github.com/mapnik/mapnik/pull/2231
svg_points_grammar<iterator_type,skip_type,PathType> g(p);
iterator_type first = wkt;
iterator_type last = wkt + std::strlen(wkt);
return qi::phrase_parse(first, last, g, skip_type());
}
template <typename PathType>
bool parse_points(const char* wkt, PathType& p)
{
using namespace boost::spirit;
using iterator_type = const char*;
using skip_type = ascii::space_type;
static const svg_points_grammar<iterator_type, PathType, skip_type> g;
iterator_type first = wkt;
iterator_type last = wkt + std::strlen(wkt);
return qi::phrase_parse(first, last, (g)(boost::phoenix::ref(p)), skip_type());
}
template bool parse_points<svg_converter_type>(const char*, svg_converter_type&);
template bool parse_points<svg_converter_type>(const char*, svg_converter_type&);
}}
} // namespace svg
} // namespace mapnik