From 378b19b53d4dd8abe5d0baa52a626b2c9076bebb Mon Sep 17 00:00:00 2001 From: Jiri Drbalek Date: Fri, 2 Nov 2018 16:27:26 +0000 Subject: [PATCH] Vector patterns with Cairo --- include/mapnik/cairo/cairo_context.hpp | 71 +++++++------ .../mapnik/cairo/render_polygon_pattern.hpp | 99 +++++++++++++++---- 2 files changed, 121 insertions(+), 49 deletions(-) diff --git a/include/mapnik/cairo/cairo_context.hpp b/include/mapnik/cairo/cairo_context.hpp index c15f87cd7..82122497e 100644 --- a/include/mapnik/cairo/cairo_context.hpp +++ b/include/mapnik/cairo/cairo_context.hpp @@ -121,6 +121,30 @@ private: cairo_face_cache cache_; }; +struct cairo_closer +{ + void operator() (cairo_t * obj) + { + if (obj) cairo_destroy(obj); + } +}; + +struct cairo_surface_closer +{ + void operator() (cairo_surface_t * surface) + { + if (surface) cairo_surface_destroy(surface); + } +}; + +using cairo_ptr = std::shared_ptr; +using cairo_surface_ptr = std::shared_ptr; + +inline cairo_ptr create_context(cairo_surface_ptr const& surface) +{ + return cairo_ptr(cairo_create(&*surface),cairo_closer()); +} + class cairo_pattern : private util::noncopyable { public: @@ -131,9 +155,15 @@ public: const unsigned int *in_end = in_ptr + pixels; unsigned int *out_ptr; - surface_ = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, static_cast(data.width()), static_cast(data.height())); + surface_ = cairo_surface_ptr( + cairo_image_surface_create( + CAIRO_FORMAT_ARGB32, + static_cast(data.width()), + static_cast(data.height())), + cairo_surface_closer()); - out_ptr = reinterpret_cast(cairo_image_surface_get_data(surface_)); + out_ptr = reinterpret_cast( + cairo_image_surface_get_data(surface_.get())); while (in_ptr < in_end) { @@ -150,13 +180,18 @@ public: *out_ptr++ = (a << 24) | (r << 16) | (g << 8) | b; } // mark the surface as dirty as we've modified it behind cairo's back - cairo_surface_mark_dirty(surface_); - pattern_ = cairo_pattern_create_for_surface(surface_); + cairo_surface_mark_dirty(surface_.get()); + pattern_ = cairo_pattern_create_for_surface(surface_.get()); + } + + cairo_pattern(cairo_surface_ptr const& surface) : + surface_(surface), + pattern_(cairo_pattern_create_for_surface(surface_.get())) + { } ~cairo_pattern() { - if (surface_) cairo_surface_destroy(surface_); if (pattern_) cairo_pattern_destroy(pattern_); } @@ -190,7 +225,7 @@ public: } private: - cairo_surface_t * surface_; + cairo_surface_ptr surface_; cairo_pattern_t * pattern_; }; @@ -255,30 +290,6 @@ private: }; -struct cairo_closer -{ - void operator() (cairo_t * obj) - { - if (obj) cairo_destroy(obj); - } -}; - -struct cairo_surface_closer -{ - void operator() (cairo_surface_t * surface) - { - if (surface) cairo_surface_destroy(surface); - } -}; - -using cairo_ptr = std::shared_ptr; -using cairo_surface_ptr = std::shared_ptr; - -inline cairo_ptr create_context(cairo_surface_ptr const& surface) -{ - return cairo_ptr(cairo_create(&*surface),cairo_closer()); -} - class cairo_context : private util::noncopyable { public: diff --git a/include/mapnik/cairo/render_polygon_pattern.hpp b/include/mapnik/cairo/render_polygon_pattern.hpp index e49b3ab11..1151b2538 100644 --- a/include/mapnik/cairo/render_polygon_pattern.hpp +++ b/include/mapnik/cairo/render_polygon_pattern.hpp @@ -27,40 +27,92 @@ #include #include #include -#include #include #include -#include +#include #include namespace mapnik { struct cairo_renderer_process_visitor_p { - cairo_renderer_process_visitor_p(agg::trans_affine & image_tr) - : image_tr_(image_tr) + cairo_renderer_process_visitor_p(agg::trans_affine const& image_tr, + double opacity) + : image_tr_(image_tr), + opacity_(opacity) {} - image_rgba8 operator() (marker_null const&) + cairo_surface_ptr operator()(marker_svg const & marker) const { - return image_rgba8(); + box2d bbox(marker.bounding_box()); + agg::trans_affine tr(transform(bbox)); + + double width = std::max(1.0, std::round(bbox.width())); + double height = std::max(1.0, std::round(bbox.height())); + cairo_rectangle_t extent { 0, 0, width, height }; + cairo_surface_ptr surface( + cairo_recording_surface_create( + CAIRO_CONTENT_COLOR_ALPHA, &extent), + cairo_surface_closer()); + + cairo_ptr cairo = create_context(surface); + cairo_context context(cairo); + + svg_storage_type & svg = *marker.get_data(); + svg_attribute_type const& svg_attributes = svg.attributes(); + svg::vertex_stl_adapter stl_storage( + svg.source()); + svg::svg_path_adapter svg_path(stl_storage); + + render_vector_marker(context, svg_path, svg_attributes, + bbox, tr, opacity_); + + return surface; } - image_rgba8 operator() (marker_svg const& marker) + cairo_surface_ptr operator()(marker_rgba8 const& marker) const { - mapnik::box2d const& bbox_image = marker.get_data()->bounding_box() * image_tr_; - mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height()); - render_pattern(marker, image_tr_, 1.0, image); - return image; + box2d bbox(marker.bounding_box()); + agg::trans_affine tr(transform(bbox)); + + cairo_rectangle_t extent { 0, 0, bbox.width(), bbox.height() }; + cairo_surface_ptr surface( + cairo_recording_surface_create( + CAIRO_CONTENT_COLOR_ALPHA, &extent), + cairo_surface_closer()); + + cairo_ptr cairo = create_context(surface); + cairo_context context(cairo); + + context.add_image(tr, marker.get_data(), opacity_); + + return surface; } - image_rgba8 operator() (marker_rgba8 const& marker) + cairo_surface_ptr operator() (marker_null const&) const { - return marker.get_data(); + cairo_surface_ptr surface( + cairo_recording_surface_create( + CAIRO_CONTENT_COLOR_ALPHA, nullptr), + cairo_surface_closer()); + cairo_ptr cairo = create_context(surface); + cairo_context context(cairo); + return surface; } - private: - agg::trans_affine & image_tr_; +private: + agg::trans_affine transform(box2d & bbox) const + { + bbox *= image_tr_; + coord c = bbox.center(); + agg::trans_affine mtx = agg::trans_affine_translation( + 0.5 * bbox.width() - c.x, + 0.5 * bbox.height() - c.y); + return image_tr_ * mtx; + } + + agg::trans_affine const& image_tr_; + const double opacity_; }; struct cairo_pattern_base @@ -121,10 +173,19 @@ struct cairo_polygon_pattern : cairo_pattern_base cairo_save_restore guard(context); context.set_operator(comp_op); - image_rgba8 pattern_img(util::apply_visitor(cairo_renderer_process_visitor_p(image_tr), marker_)); - coord offset(pattern_offset(sym_, feature_, prj_trans_, common_, - pattern_img.width(), pattern_img.height())); - cairo_pattern pattern(pattern_img, opacity); + cairo_renderer_process_visitor_p visitor(image_tr, opacity); + cairo_surface_ptr surface(util::apply_visitor(visitor, this->marker_)); + + coord offset(0, 0); + + cairo_rectangle_t pattern_surface_extent; + if (cairo_recording_surface_get_extents(surface.get(), &pattern_surface_extent)) + { + offset = pattern_offset(sym_, feature_, prj_trans_, common_, + pattern_surface_extent.width, pattern_surface_extent.height); + } + + cairo_pattern pattern(surface); pattern.set_extend(CAIRO_EXTEND_REPEAT); pattern.set_origin(-offset.x, -offset.y); context.set_pattern(pattern);