SVG parser - simplify viewport/viewBox
logic + use functions e.g 'premultiply' rather than operator*=
for clarity.
This commit is contained in:
parent
d417b8933a
commit
32263cde89
3 changed files with 88 additions and 93 deletions
|
@ -111,7 +111,6 @@ class MAPNIK_DECL svg_parser : private util::noncopyable
|
|||
mapnik::css_data css_data_;
|
||||
boost::optional<viewbox> vbox_{};
|
||||
double normalized_diagonal_ = 0.0;
|
||||
agg::trans_affine viewbox_tr_{};
|
||||
std::deque<double> font_sizes_{};
|
||||
error_handler err_handler_;
|
||||
};
|
||||
|
|
|
@ -64,7 +64,7 @@ auto const matrix_action = [](auto const& ctx) {
|
|||
auto d = boost::fusion::at_c<3>(attr);
|
||||
auto e = boost::fusion::at_c<4>(attr);
|
||||
auto f = boost::fusion::at_c<5>(attr);
|
||||
tr = agg::trans_affine(a, b, c, d, e, f) * tr;
|
||||
tr.premultiply(agg::trans_affine(a, b, c, d, e, f));
|
||||
};
|
||||
|
||||
auto const rotate_action = [](auto const& ctx) {
|
||||
|
@ -75,14 +75,14 @@ auto const rotate_action = [](auto const& ctx) {
|
|||
auto cy = boost::fusion::at_c<2>(attr) ? *boost::fusion::at_c<2>(attr) : 0.0;
|
||||
if (cx == 0.0 && cy == 0.0)
|
||||
{
|
||||
tr = agg::trans_affine_rotation(agg::deg2rad(a)) * tr;
|
||||
tr.premultiply(agg::trans_affine_rotation(agg::deg2rad(a)));
|
||||
}
|
||||
else
|
||||
{
|
||||
agg::trans_affine t = agg::trans_affine_translation(-cx, -cy);
|
||||
t *= agg::trans_affine_rotation(agg::deg2rad(a));
|
||||
t *= agg::trans_affine_translation(cx, cy);
|
||||
tr = t * tr;
|
||||
tr.premultiply(t);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -92,9 +92,9 @@ auto const translate_action = [](auto const& ctx) {
|
|||
auto tx = boost::fusion::at_c<0>(attr);
|
||||
auto ty = boost::fusion::at_c<1>(attr);
|
||||
if (ty)
|
||||
tr = agg::trans_affine_translation(tx, *ty) * tr;
|
||||
tr.premultiply(agg::trans_affine_translation(tx, *ty));
|
||||
else
|
||||
tr = agg::trans_affine_translation(tx, 0.0) * tr;
|
||||
tr.premultiply(agg::trans_affine_translation(tx, 0.0));
|
||||
};
|
||||
|
||||
auto const scale_action = [](auto const& ctx) {
|
||||
|
@ -103,21 +103,21 @@ auto const scale_action = [](auto const& ctx) {
|
|||
auto sx = boost::fusion::at_c<0>(attr);
|
||||
auto sy = boost::fusion::at_c<1>(attr);
|
||||
if (sy)
|
||||
tr = agg::trans_affine_scaling(sx, *sy) * tr;
|
||||
tr.premultiply(agg::trans_affine_scaling(sx, *sy));
|
||||
else
|
||||
tr = agg::trans_affine_scaling(sx, sx) * tr;
|
||||
tr.premultiply(agg::trans_affine_scaling(sx, sx));
|
||||
};
|
||||
|
||||
auto const skewX_action = [](auto const& ctx) {
|
||||
auto& tr = extract_transform(ctx);
|
||||
auto skew_x = _attr(ctx);
|
||||
tr = agg::trans_affine_skewing(agg::deg2rad(skew_x), 0.0) * tr;
|
||||
tr.premultiply(agg::trans_affine_skewing(agg::deg2rad(skew_x), 0.0));
|
||||
};
|
||||
|
||||
auto const skewY_action = [](auto const& ctx) {
|
||||
auto& tr = extract_transform(ctx);
|
||||
auto skew_y = _attr(ctx);
|
||||
tr = agg::trans_affine_skewing(0.0, agg::deg2rad(skew_y)) * tr;
|
||||
tr.premultiply(agg::trans_affine_skewing(0.0, agg::deg2rad(skew_y)));
|
||||
};
|
||||
|
||||
// rules
|
||||
|
|
|
@ -54,6 +54,8 @@ MAPNIK_DISABLE_WARNING_POP
|
|||
#include <fstream>
|
||||
#include <array>
|
||||
|
||||
|
||||
|
||||
namespace mapnik {
|
||||
namespace svg {
|
||||
|
||||
|
@ -531,36 +533,45 @@ void traverse_tree(svg_parser& parser, rapidxml::xml_node<char> const* node)
|
|||
{
|
||||
switch (name)
|
||||
{
|
||||
case "g"_case:
|
||||
if (node->first_node() != nullptr)
|
||||
{
|
||||
parser.path_.push_attr();
|
||||
parse_id(parser, node);
|
||||
if (parser.css_style_)
|
||||
process_css(parser, node);
|
||||
parse_attr(parser, node);
|
||||
}
|
||||
break;
|
||||
case "use"_case:
|
||||
case "g"_case:
|
||||
if (node->first_node() != nullptr)
|
||||
{
|
||||
parser.path_.push_attr();
|
||||
parse_id(parser, node);
|
||||
if (parser.css_style_)
|
||||
process_css(parser, node);
|
||||
parse_attr(parser, node);
|
||||
parse_use(parser, node);
|
||||
parser.path_.pop_attr();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
break;
|
||||
case "svg"_case:
|
||||
if (node->first_node() != nullptr)
|
||||
{
|
||||
parser.path_.push_attr();
|
||||
parse_id(parser, node);
|
||||
if (parser.css_style_)
|
||||
process_css(parser, node);
|
||||
parse_attr(parser, node);
|
||||
if (parser.path_.display())
|
||||
{
|
||||
parse_element(parser, node->name(), node);
|
||||
}
|
||||
parser.path_.pop_attr();
|
||||
parse_dimensions(parser, node);
|
||||
}
|
||||
|
||||
break;
|
||||
case "use"_case:
|
||||
parser.path_.push_attr();
|
||||
parse_id(parser, node);
|
||||
if (parser.css_style_)
|
||||
process_css(parser, node);
|
||||
parse_attr(parser, node);
|
||||
parse_use(parser, node);
|
||||
parser.path_.pop_attr();
|
||||
break;
|
||||
default:
|
||||
parser.path_.push_attr();
|
||||
parse_id(parser, node);
|
||||
if (parser.css_style_)
|
||||
process_css(parser, node);
|
||||
parse_attr(parser, node);
|
||||
if (parser.path_.display())
|
||||
{
|
||||
parse_element(parser, node->name(), node);
|
||||
}
|
||||
parser.path_.pop_attr();
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -642,38 +653,26 @@ void parse_element(svg_parser& parser, char const* name, rapidxml::xml_node<char
|
|||
switch (name_to_int(name))
|
||||
{
|
||||
case "path"_case:
|
||||
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||
parse_path(parser, node);
|
||||
break;
|
||||
case "polygon"_case:
|
||||
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||
parse_polygon(parser, node);
|
||||
break;
|
||||
case "polyline"_case:
|
||||
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||
parse_polyline(parser, node);
|
||||
break;
|
||||
case "line"_case:
|
||||
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||
parse_line(parser, node);
|
||||
break;
|
||||
case "rect"_case:
|
||||
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||
parse_rect(parser, node);
|
||||
break;
|
||||
case "circle"_case:
|
||||
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||
parse_circle(parser, node);
|
||||
break;
|
||||
case "ellipse"_case:
|
||||
parser.path_.transform().multiply(parser.viewbox_tr_);
|
||||
parse_ellipse(parser, node);
|
||||
break;
|
||||
case "svg"_case:
|
||||
parser.path_.push_attr();
|
||||
parse_dimensions(parser, node);
|
||||
parse_attr(parser, node);
|
||||
break;
|
||||
default:
|
||||
handle_unsupported(parser, unsupported_elements, name, "element");
|
||||
break;
|
||||
|
@ -893,7 +892,6 @@ void parse_dimensions(svg_parser& parser, rapidxml::xml_node<char> const* node)
|
|||
viewbox vbox = {0, 0, 0, 0};
|
||||
bool has_percent_height = true;
|
||||
bool has_percent_width = true;
|
||||
|
||||
auto const* width_attr = node->first_attribute("width");
|
||||
if (width_attr)
|
||||
{
|
||||
|
@ -933,58 +931,56 @@ void parse_dimensions(svg_parser& parser, rapidxml::xml_node<char> const* node)
|
|||
double sx = width / vbox.width;
|
||||
double sy = height / vbox.height;
|
||||
double scale = preserve_aspect_ratio.second ? std::min(sx, sy) : std::max(sx, sy);
|
||||
|
||||
switch (preserve_aspect_ratio.first)
|
||||
{
|
||||
case none:
|
||||
t = agg::trans_affine_scaling(sx, sy) * t;
|
||||
break;
|
||||
case xMinYMin:
|
||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||
break;
|
||||
case xMinYMid:
|
||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||
t = agg::trans_affine_translation(0, -0.5 * (vbox.height - height / scale)) * t;
|
||||
break;
|
||||
case xMinYMax:
|
||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||
t = agg::trans_affine_translation(0, -1.0 * (vbox.height - height / scale)) * t;
|
||||
break;
|
||||
case xMidYMin:
|
||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||
t = agg::trans_affine_translation(-0.5 * (vbox.width - width / scale), 0.0) * t;
|
||||
break;
|
||||
case xMidYMid: // (the default)
|
||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||
t = agg::trans_affine_translation(-0.5 * (vbox.width - width / scale),
|
||||
-0.5 * (vbox.height - height / scale)) *
|
||||
t;
|
||||
break;
|
||||
case xMidYMax:
|
||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||
t = agg::trans_affine_translation(-0.5 * (vbox.width - width / scale),
|
||||
-1.0 * (vbox.height - height / scale)) *
|
||||
t;
|
||||
break;
|
||||
case xMaxYMin:
|
||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||
t = agg::trans_affine_translation(-1.0 * (vbox.width - width / scale), 0.0) * t;
|
||||
break;
|
||||
case xMaxYMid:
|
||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||
t = agg::trans_affine_translation(-1.0 * (vbox.width - width / scale),
|
||||
-0.5 * (vbox.height - height / scale)) *
|
||||
t;
|
||||
break;
|
||||
case xMaxYMax:
|
||||
t = agg::trans_affine_scaling(scale, scale) * t;
|
||||
t = agg::trans_affine_translation(-1.0 * (vbox.width - width / scale),
|
||||
-1.0 * (vbox.height - height / scale)) *
|
||||
t;
|
||||
case none:
|
||||
t.premultiply(agg::trans_affine_scaling(sx, sy));
|
||||
break;
|
||||
case xMinYMin:
|
||||
t.premultiply(agg::trans_affine_scaling(scale, scale));
|
||||
break;
|
||||
case xMinYMid:
|
||||
t.premultiply(agg::trans_affine_scaling(scale, scale));
|
||||
t.premultiply(agg::trans_affine_translation(0, -0.5 * (vbox.height - height / scale)));
|
||||
break;
|
||||
case xMinYMax:
|
||||
t.premultiply(agg::trans_affine_scaling(scale, scale));
|
||||
t.premultiply(agg::trans_affine_translation(0, -1.0 * (vbox.height - height / scale)));
|
||||
break;
|
||||
case xMidYMin:
|
||||
t.premultiply(agg::trans_affine_scaling(scale, scale));
|
||||
t.premultiply(agg::trans_affine_translation(-0.5 * (vbox.width - width / scale), 0.0));
|
||||
break;
|
||||
case xMidYMid: // (the default)
|
||||
t.premultiply(agg::trans_affine_scaling(scale, scale));
|
||||
t.premultiply(agg::trans_affine_translation(-0.5 * (vbox.width - width / scale),
|
||||
-0.5 * (vbox.height - height / scale)));
|
||||
break;
|
||||
case xMidYMax:
|
||||
t.premultiply(agg::trans_affine_scaling(scale, scale));
|
||||
t.premultiply(agg::trans_affine_translation(-0.5 * (vbox.width - width / scale),
|
||||
-1.0 * (vbox.height - height / scale)));
|
||||
break;
|
||||
case xMaxYMin:
|
||||
t.premultiply(agg::trans_affine_scaling(scale, scale));
|
||||
t.premultiply(agg::trans_affine_translation(-1.0 * (vbox.width - width / scale), 0.0));
|
||||
break;
|
||||
case xMaxYMid:
|
||||
t.premultiply(agg::trans_affine_scaling(scale, scale));
|
||||
t.premultiply(agg::trans_affine_translation(-1.0 * (vbox.width - width / scale),
|
||||
-0.5 * (vbox.height - height / scale)));
|
||||
break;
|
||||
case xMaxYMax:
|
||||
t.premultiply(agg::trans_affine_scaling(scale, scale));
|
||||
t.premultiply(agg::trans_affine_translation(-1.0 * (vbox.width - width / scale),
|
||||
-1.0 * (vbox.height - height / scale)));
|
||||
break;
|
||||
};
|
||||
|
||||
t.premultiply(agg::trans_affine_translation(-vbox.x0, -vbox.y0));
|
||||
parser.path_.transform().premultiply(t);
|
||||
}
|
||||
t = agg::trans_affine_translation(-vbox.x0, -vbox.y0) * t;
|
||||
parser.viewbox_tr_ = t;
|
||||
}
|
||||
else if (width == 0 || height == 0 || has_percent_width || has_percent_height)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue