From 5f4711a019a6cff7adbc6256e8c35dc777754876 Mon Sep 17 00:00:00 2001 From: Artem Pavlenko Date: Wed, 23 Nov 2022 15:53:08 +0000 Subject: [PATCH] SVG - refactor and minimise internal group usage [WIP] [skip ci] --- include/mapnik/svg/svg_converter.hpp | 2 ++ include/mapnik/svg/svg_renderer_agg.hpp | 38 ++++++++++++++++--------- src/marker_helpers.cpp | 1 + src/svg/svg_parser.cpp | 15 +++++----- 4 files changed, 35 insertions(+), 21 deletions(-) diff --git a/include/mapnik/svg/svg_converter.hpp b/include/mapnik/svg/svg_converter.hpp index 5b093fdab..e351c88b9 100644 --- a/include/mapnik/svg/svg_converter.hpp +++ b/include/mapnik/svg/svg_converter.hpp @@ -65,6 +65,8 @@ class svg_converter : util::noncopyable svg_height_(0.0) {} + void set_opacity(double opacity) { svg_group_.opacity = opacity; } + void begin_group() { current_group_->elements.emplace_back(group {cur_attr().opacity, {}, current_group_}); diff --git a/include/mapnik/svg/svg_renderer_agg.hpp b/include/mapnik/svg/svg_renderer_agg.hpp index 386484531..dc9decd33 100644 --- a/include/mapnik/svg/svg_renderer_agg.hpp +++ b/include/mapnik/svg/svg_renderer_agg.hpp @@ -145,10 +145,27 @@ class renderer_agg : util::noncopyable box2d const& symbol_bbox) { - for (auto const& elem : svg_group_.elements) + double adjusted_opacity = opacity * svg_group_.opacity; // adjust top level opacity + if (adjusted_opacity < 1.0) { - mapbox::util::apply_visitor(group_renderer - (*this, ras, sl, ren, mtx, opacity, symbol_bbox, true), elem); + mapnik::image_rgba8 im(ren.width(), ren.height(), true, true); + agg::rendering_buffer buf(im.bytes(), im.width(), im.height(), im.row_size()); + PixelFormat pixf(buf); + Renderer ren_g(pixf); + for (auto const& elem : svg_group_.elements) + { + mapbox::util::apply_visitor(group_renderer + (*this, ras, sl, ren_g, mtx, symbol_bbox), elem); + } + ren.blend_from(ren_g.ren(), 0, 0, 0, unsigned(adjusted_opacity * 255)); + } + else + { + for (auto const& elem : svg_group_.elements) + { + mapbox::util::apply_visitor(group_renderer + (*this, ras, sl, ren, mtx, symbol_bbox), elem); + } } } @@ -158,17 +175,13 @@ class renderer_agg : util::noncopyable group_renderer(renderer_agg& renderer, Rasterizer & ras, Scanline& sl, Renderer& ren, agg::trans_affine const& mtx, - double opacity, - box2d const& symbol_bbox, - bool first = false) + box2d const& symbol_bbox) : renderer_(renderer), ras_(ras), sl_(sl), ren_(ren), mtx_(mtx), - opacity_(opacity), - symbol_bbox_(symbol_bbox), - first_(first) + symbol_bbox_(symbol_bbox) {} void render_gradient(Rasterizer& ras, @@ -281,7 +294,6 @@ class renderer_agg : util::noncopyable void operator() (group const& g) const { double opacity = g.opacity; - if (first_) opacity *= opacity_; // adjust top level opacity if (opacity < 1.0) { mapnik::image_rgba8 im(ren_.width(), ren_.height(), true, true); @@ -291,7 +303,7 @@ class renderer_agg : util::noncopyable for (auto const& elem : g.elements) { mapbox::util::apply_visitor( - group_renderer(renderer_, ras_, sl_, ren, mtx_, opacity_, symbol_bbox_), elem); + group_renderer(renderer_, ras_, sl_, ren, mtx_, symbol_bbox_), elem); } ren_.blend_from(ren.ren(), 0, 0, 0, unsigned(opacity * 255)); } @@ -300,7 +312,7 @@ class renderer_agg : util::noncopyable for (auto const& elem : g.elements) { mapbox::util::apply_visitor( - group_renderer(renderer_, ras_, sl_, ren_, mtx_, opacity_, symbol_bbox_), elem); + group_renderer(renderer_, ras_, sl_, ren_, mtx_, symbol_bbox_), elem); } } } @@ -463,9 +475,7 @@ class renderer_agg : util::noncopyable Scanline& sl_; Renderer& ren_; agg::trans_affine const& mtx_; - double opacity_; box2d const& symbol_bbox_; - bool first_; }; #if defined(GRID_RENDERER) diff --git a/src/marker_helpers.cpp b/src/marker_helpers.cpp index eeac80a21..575be957d 100644 --- a/src/marker_helpers.cpp +++ b/src/marker_helpers.cpp @@ -189,6 +189,7 @@ bool push_explicit_style(svg::group const& src, auto stroke_width = get_optional(sym, keys::stroke_width, feature, vars); auto stroke_opacity = get_optional(sym, keys::stroke_opacity, feature, vars); bool success = false; + dst.opacity = src.opacity; if (fill_color || fill_opacity || stroke_color || stroke_width || stroke_opacity) { for (auto const& elem : src.elements) diff --git a/src/svg/svg_parser.cpp b/src/svg/svg_parser.cpp index e43587f83..00352b0a8 100644 --- a/src/svg/svg_parser.cpp +++ b/src/svg/svg_parser.cpp @@ -548,7 +548,9 @@ void traverse_tree(svg_parser& parser, rapidxml::xml_node const* node) if (parser.css_style_) process_css(parser, node); parse_attr(parser, node); + if (parser.path_.cur_attr().opacity < 1.0) parser.path_.begin_group(); parse_use(parser, node); + if (parser.path_.cur_attr().opacity < 1.0) parser.path_.end_group(); parser.path_.pop_attr(); break; default: @@ -622,11 +624,10 @@ void end_element(svg_parser& parser, rapidxml::xml_node const* node) } else if (name == "svg"_case) { - parser.path_.end_group(); - if (node->first_node() != nullptr) - { - parser.path_.pop_attr(); - } + //if (node->first_node() != nullptr) + //{ + //parser.path_.pop_attr(); + //} } else if (name == "defs"_case) { @@ -675,10 +676,10 @@ void parse_element(svg_parser& parser, char const* name, rapidxml::xml_node