diff --git a/SConstruct b/SConstruct index bfcf006a9..7586d7647 100644 --- a/SConstruct +++ b/SConstruct @@ -49,7 +49,7 @@ SCONF_TEMP_DIR = '.sconf_temp' # auto-search directories for boost libs/headers BOOST_SEARCH_PREFIXES = ['/usr/local','/opt/local','/sw','/usr',] BOOST_MIN_VERSION = '1.47' -CAIROMM_MIN_VERSION = '1.8.0' +#CAIROMM_MIN_VERSION = '1.8.0' DEFAULT_LINK_PRIORITY = ['internal','other','frameworks','user','system'] @@ -60,8 +60,8 @@ pretty_dep_names = { 'ogr':'OGR-enabled GDAL C++ Library | configured using gdal-config program | try setting GDAL_CONFIG SCons option | more info: https://github.com/mapnik/mapnik/wiki//OGR', 'geos_c':'GEOS Simple Geometry Specification C Library | configured with GEOS_LIB & GEOS_INCLUDE | more info: https://github.com/mapnik/mapnik/wiki//GEOS', 'cairo':'Cairo C library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option', - 'cairomm':'Cairomm C++ bindings to Cairo library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option', - 'cairomm-version':'Cairomm version is too old (so cairo renderer will not be built), you need at least %s' % CAIROMM_MIN_VERSION, + #'cairomm':'Cairomm C++ bindings to Cairo library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option', + #'cairomm-version':'Cairomm version is too old (so cairo renderer will not be built), you need at least %s' % CAIROMM_MIN_VERSION, 'pycairo':'Python bindings to Cairo library | configured using pkg-config | try setting PKG_CONFIG_PATH SCons option', 'proj':'Proj.4 C Projections library | configure with PROJ_LIBS & PROJ_INCLUDES | more info: http://trac.osgeo.org/proj/', 'pg':'Postgres C Library requiered for PostGIS plugin | configure with pg_config program | more info: https://github.com/mapnik/mapnik/wiki//PostGIS', @@ -333,8 +333,8 @@ opts.AddVariables( # Note: cairo, cairomm, and pycairo all optional but configured automatically through pkg-config # Therefore, we use a single boolean for whether to attempt to build cairo support. BoolVariable('CAIRO', 'Attempt to build with Cairo rendering support', 'True'), - PathVariable('CAIRO_INCLUDES', 'Search path for cairo/cairomm include files', '',PathVariable.PathAccept), - PathVariable('CAIRO_LIBS', 'Search path for cairo/cairomm library files','',PathVariable.PathAccept), + PathVariable('CAIRO_INCLUDES', 'Search path for cairo include files', '',PathVariable.PathAccept), + PathVariable('CAIRO_LIBS', 'Search path for cairo library files','',PathVariable.PathAccept), ('GDAL_CONFIG', 'The path to the gdal-config executable for finding gdal and ogr details.', 'gdal-config'), ('PG_CONFIG', 'The path to the pg_config executable.', 'pg_config'), PathVariable('OCCI_INCLUDES', 'Search path for OCCI include files', '/usr/lib/oracle/10.2.0.3/client/include', PathVariable.PathAccept), @@ -1277,17 +1277,17 @@ if not preconfigured: c_inc = os.path.dirname(c_inc) env["CAIROMM_CPPPATHS"].extend( [ - os.path.join(c_inc,'include/cairomm-1.0'), - os.path.join(c_inc,'lib/cairomm-1.0/include'), + #os.path.join(c_inc,'include/cairomm-1.0'), + #os.path.join(c_inc,'lib/cairomm-1.0/include'), os.path.join(c_inc,'include/cairo'), - os.path.join(c_inc,'include/sigc++-2.0'), - os.path.join(c_inc,'lib/sigc++-2.0/include'), + #os.path.join(c_inc,'include/sigc++-2.0'), + #os.path.join(c_inc,'lib/sigc++-2.0/include'), os.path.join(c_inc,'include/pixman-1'), #os.path.join(c_inc,'include/freetype2'), #os.path.join(c_inc,'include/libpng'), ] ) - env["CAIROMM_LINKFLAGS"] = ['cairo','cairomm-1.0'] + env["CAIROMM_LINKFLAGS"] = ['cairo'] if env['RUNTIME_LINK'] == 'static': env["CAIROMM_LINKFLAGS"].extend( ['sigc-2.0','pixman-1','expat','fontconfig','iconv'] @@ -1299,40 +1299,40 @@ if not preconfigured: env['HAS_CAIRO'] = False env['SKIPPED_DEPS'].append('pkg-config') env['SKIPPED_DEPS'].append('cairo') - env['SKIPPED_DEPS'].append('cairomm') + #env['SKIPPED_DEPS'].append('cairomm') elif not conf.CheckPKG('cairo'): env['HAS_CAIRO'] = False env['SKIPPED_DEPS'].append('cairo') - elif not conf.CheckPKG('cairomm-1.0'): - env['HAS_CAIRO'] = False - env['SKIPPED_DEPS'].append('cairomm') - elif not conf.CheckPKGVersion('cairomm-1.0',CAIROMM_MIN_VERSION): - env['HAS_CAIRO'] = False - env['SKIPPED_DEPS'].append('cairomm-version') - else: - print 'Checking for cairo/cairomm lib and include paths... ', - cmd = 'pkg-config --libs --cflags cairomm-1.0' - if env['RUNTIME_LINK'] == 'static': - cmd += ' --static' - cairo_env = env.Clone() - try: - cairo_env.ParseConfig(cmd) - for lib in cairo_env['LIBS']: - if not lib in env['LIBS']: - env["CAIROMM_LINKFLAGS"].append(lib) - for lpath in cairo_env['LIBPATH']: - if not lpath in env['LIBPATH']: - env["CAIROMM_LIBPATHS"].append(lpath) - for inc in cairo_env['CPPPATH']: - if not inc in env['CPPPATH']: - env["CAIROMM_CPPPATHS"].append(inc) - env['HAS_CAIRO'] = True - print 'yes' - except OSError,e: - color_print(1,'no') - env['SKIPPED_DEPS'].append('cairo') - env['SKIPPED_DEPS'].append('cairomm') - color_print(1,'pkg-config reported: %s' % e) + #elif not conf.CheckPKG('cairomm-1.0'): + # env['HAS_CAIRO'] = False + # env['SKIPPED_DEPS'].append('cairomm') + #elif not conf.CheckPKGVersion('cairomm-1.0',CAIROMM_MIN_VERSION): + # env['HAS_CAIRO'] = False + # env['SKIPPED_DEPS'].append('cairomm-version') + #else: + # print 'Checking for cairo/cairomm lib and include paths... ', + # cmd = 'pkg-config --libs --cflags cairomm-1.0' + # if env['RUNTIME_LINK'] == 'static': + # cmd += ' --static' + # cairo_env = env.Clone() + # try: + # cairo_env.ParseConfig(cmd) + # for lib in cairo_env['LIBS']: + # if not lib in env['LIBS']: + # env["CAIROMM_LINKFLAGS"].append(lib) + # for lpath in cairo_env['LIBPATH']: + # if not lpath in env['LIBPATH']: + # env["CAIROMM_LIBPATHS"].append(lpath) + # for inc in cairo_env['CPPPATH']: + # if not inc in env['CPPPATH']: + # env["CAIROMM_CPPPATHS"].append(inc) + # env['HAS_CAIRO'] = True + # print 'yes' + # except OSError,e: + # color_print(1,'no') + # env['SKIPPED_DEPS'].append('cairo') + # env['SKIPPED_DEPS'].append('cairomm') + # color_print(1,'pkg-config reported: %s' % e) else: color_print(4,'Not building with cairo support, pass CAIRO=True to enable') diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 58ae16ba8..1b8b8b85d 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -46,7 +46,7 @@ extern "C" // cairo #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) -#include +#include #include #endif @@ -158,17 +158,16 @@ void blend (image_32 & im, unsigned x, unsigned y, image_32 const& im2, float op im.set_rectangle_alpha2(im2.data(),x,y,opacity); } - void composite(image_32 & dst, image_32 & src, mapnik::composite_mode_e mode, float opacity) { mapnik::composite(dst.data(),src.data(),mode,opacity,0,0,false); } #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) -boost::shared_ptr from_cairo(PycairoSurface* surface) +boost::shared_ptr from_cairo(PycairoSurface* py_surface) { - Cairo::RefPtr s(new Cairo::ImageSurface(surface->surface)); - boost::shared_ptr image_ptr = boost::make_shared(s); + mapnik::cairo_surface_ptr surface(py_surface->surface, mapnik::cairo_surface_closer()); + boost::shared_ptr image_ptr = boost::make_shared(surface); return image_ptr; } #endif diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index d6f310685..8a0e0f58d 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -163,92 +163,92 @@ void render_layer2(const mapnik::Map& map, #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) void render3(const mapnik::Map& map, - PycairoSurface* surface, + PycairoSurface* py_surface, double scale_factor = 1.0, unsigned offset_x = 0, unsigned offset_y = 0) { python_unblock_auto_block b; - Cairo::RefPtr s(new Cairo::Surface(surface->surface)); - mapnik::cairo_renderer ren(map,s,scale_factor,offset_x,offset_y); + mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer()); + mapnik::cairo_renderer ren(map,surface,scale_factor,offset_x,offset_y); ren.apply(); } -void render4(const mapnik::Map& map, PycairoSurface* surface) +void render4(const mapnik::Map& map, PycairoSurface* py_surface) { python_unblock_auto_block b; - Cairo::RefPtr s(new Cairo::Surface(surface->surface)); - mapnik::cairo_renderer ren(map,s); + mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer()); + mapnik::cairo_renderer ren(map,surface); ren.apply(); } void render5(const mapnik::Map& map, - PycairoContext* context, + PycairoContext* py_context, double scale_factor = 1.0, unsigned offset_x = 0, unsigned offset_y = 0) { python_unblock_auto_block b; - Cairo::RefPtr c(new Cairo::Context(context->ctx)); - mapnik::cairo_renderer ren(map,c,scale_factor,offset_x, offset_y); + mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer()); + mapnik::cairo_renderer ren(map,context,scale_factor,offset_x, offset_y); ren.apply(); } -void render6(const mapnik::Map& map, PycairoContext* context) +void render6(const mapnik::Map& map, PycairoContext* py_context) { python_unblock_auto_block b; - Cairo::RefPtr c(new Cairo::Context(context->ctx)); - mapnik::cairo_renderer ren(map,c); + mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer()); + mapnik::cairo_renderer ren(map,context); ren.apply(); } void render_with_detector2( const mapnik::Map& map, - PycairoContext* context, + PycairoContext* py_context, boost::shared_ptr detector) { python_unblock_auto_block b; - Cairo::RefPtr c(new Cairo::Context(context->ctx)); - mapnik::cairo_renderer ren(map,c,detector); + mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer()); + mapnik::cairo_renderer ren(map,context,detector); ren.apply(); } void render_with_detector3( const mapnik::Map& map, - PycairoContext* context, + PycairoContext* py_context, boost::shared_ptr detector, double scale_factor = 1.0, unsigned offset_x = 0u, unsigned offset_y = 0u) { python_unblock_auto_block b; - Cairo::RefPtr c(new Cairo::Context(context->ctx)); - mapnik::cairo_renderer ren(map,c,detector,scale_factor,offset_x,offset_y); + mapnik::cairo_ptr context(py_context->ctx, mapnik::cairo_closer()); + mapnik::cairo_renderer ren(map,context,detector,scale_factor,offset_x,offset_y); ren.apply(); } void render_with_detector4( const mapnik::Map& map, - PycairoSurface* surface, + PycairoSurface* py_surface, boost::shared_ptr detector) { python_unblock_auto_block b; - Cairo::RefPtr s(new Cairo::Surface(surface->surface)); - mapnik::cairo_renderer ren(map,s,detector); + mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer()); + mapnik::cairo_renderer ren(map, surface, detector); ren.apply(); } void render_with_detector5( const mapnik::Map& map, - PycairoSurface* surface, + PycairoSurface* py_surface, boost::shared_ptr detector, double scale_factor = 1.0, unsigned offset_x = 0u, unsigned offset_y = 0u) { python_unblock_auto_block b; - Cairo::RefPtr s(new Cairo::Surface(surface->surface)); - mapnik::cairo_renderer ren(map,s,detector,scale_factor,offset_x,offset_y); + mapnik::cairo_surface_ptr surface(cairo_surface_reference(py_surface->surface), mapnik::cairo_surface_closer()); + mapnik::cairo_renderer ren(map, surface, detector, scale_factor, offset_x, offset_y); ren.apply(); } diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index 7d27d7b25..6dddf397e 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -37,7 +37,6 @@ #ifdef HAVE_CAIRO // cairo #include -#include #endif #include "mapwidget.hpp" @@ -567,12 +566,10 @@ void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix) { #ifdef HAVE_CAIRO - Cairo::RefPtr image_surface = - Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, map.width(),map.height()); - - mapnik::cairo_renderer png_render(map, image_surface, scaling_factor); - png_render.apply(); - + mapnik::cairo_surface_ptr image_surface(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,map.width(),map.height()), + mapnik::cairo_surface_closer()); + mapnik::cairo_renderer renderer(map, image_surface, scaling_factor); + renderer.apply(); image_32 buf(image_surface); QImage image((uchar*)buf.raw_data(),buf.width(),buf.height(),QImage::Format_ARGB32); pix = QPixmap::fromImage(image.rgbSwapped()); diff --git a/demo/viewer/styles_model.cpp b/demo/viewer/styles_model.cpp index 875d97dbe..236e0808e 100644 --- a/demo/viewer/styles_model.cpp +++ b/demo/viewer/styles_model.cpp @@ -21,6 +21,8 @@ #include "styles_model.hpp" #include #include +#include +#include // boost #include @@ -162,6 +164,18 @@ struct symbolizer_info : public boost::static_visitor return QString("ShieldSymbolizer"); } + QString operator() (mapnik::markers_symbolizer const& sym) const + { + boost::ignore_unused_variable_warning(sym); + return QString("MarkersSymbolizer"); + } + + QString operator() (mapnik::building_symbolizer const& sym) const + { + boost::ignore_unused_variable_warning(sym); + return QString("BuildingSymbolizer"); + } + template QString operator() (T const& ) const { @@ -223,7 +237,7 @@ class symbolizer_node { public: symbolizer_node(mapnik::symbolizer const & sym) - : sym_(sym) {} + : sym_(sym) {} ~symbolizer_node(){} QString name() const diff --git a/include/mapnik/cairo_context.hpp b/include/mapnik/cairo_context.hpp new file mode 100644 index 000000000..3d35fea64 --- /dev/null +++ b/include/mapnik/cairo_context.hpp @@ -0,0 +1,425 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2013 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + + +#ifndef MAPNIK_CAIRO_CONTEXT_HPP +#define MAPNIK_CAIRO_CONTEXT_HPP + +// mapnik +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +// boost +#include +#include +// cairo +#include +#include +// stl +#include +// agg +#include "agg_basics.h" + +namespace mapnik { + +typedef cairo_status_t ErrorStatus; + +/// Throws the appropriate exception, if exceptions are enabled. +inline void throw_exception(ErrorStatus status) +{ + throw std::runtime_error("cairo: fixme"); +} + +//We inline this because it is called so often. +inline void check_status_and_throw_exception(ErrorStatus status) +{ + if(status != CAIRO_STATUS_SUCCESS) + throw_exception(status); +} + +template +void check_object_status_and_throw_exception(const T& object) +{ + check_status_and_throw_exception(object.get_status()); +} + +class cairo_face : private mapnik::noncopyable +{ +public: + cairo_face(boost::shared_ptr const& engine, face_ptr const& face) + : face_(face) + { + static cairo_user_data_key_t key; + c_face_ = cairo_ft_font_face_create_for_ft_face(face->get_face(), FT_LOAD_NO_HINTING); + cairo_font_face_set_user_data(c_face_, &key, new handle(engine, face), destroy); + } + ~cairo_face() + { + if (c_face_) cairo_font_face_destroy(c_face_); + } + + cairo_font_face_t * face() const + { + return c_face_; + } + +private: + class handle + { + public: + handle(boost::shared_ptr const& engine, face_ptr const& face) + : engine_(engine), face_(face) {} + + private: + boost::shared_ptr engine_; + face_ptr face_; + }; + + static void destroy(void *data) + { + handle *h = static_cast(data); + delete h; + } + +private: + face_ptr face_; + cairo_font_face_t *c_face_; +}; + +typedef boost::shared_ptr cairo_face_ptr; + +class cairo_face_manager : private mapnik::noncopyable +{ +public: + cairo_face_manager(boost::shared_ptr engine); + cairo_face_ptr get_face(face_ptr face); + +private: + typedef std::map cairo_face_cache; + boost::shared_ptr font_engine_; + cairo_face_cache cache_; +}; + +class cairo_pattern : private mapnik::noncopyable +{ +public: + cairo_pattern(image_data_32 const& data) + { + int pixels = data.width() * data.height(); + const unsigned int *in_ptr = data.getData(); + const unsigned int *in_end = in_ptr + pixels; + unsigned int *out_ptr; + + surface_ = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, data.width(), data.height()); + + out_ptr = reinterpret_cast(cairo_image_surface_get_data(surface_)); + + while (in_ptr < in_end) + { + unsigned int in = *in_ptr++; + unsigned int r = (in >> 0) & 0xff; + unsigned int g = (in >> 8) & 0xff; + unsigned int b = (in >> 16) & 0xff; + unsigned int a = (in >> 24) & 0xff; + + //r = r * a / 255; + //g = g * a / 255; + //b = b * a / 255; + + *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_pattern() + { + if (surface_) cairo_surface_destroy(surface_); + if (pattern_) cairo_pattern_destroy(pattern_); + } + + void set_matrix(cairo_matrix_t const& matrix) + { + cairo_pattern_set_matrix(pattern_, &matrix); + } + + void set_origin(double x, double y) + { + cairo_matrix_t matrix; + cairo_pattern_get_matrix(pattern_,&matrix); + matrix.x0 = -x; + matrix.y0 = -y; + cairo_pattern_set_matrix(pattern_,&matrix); + } + + void set_extend(cairo_extend_t extend) + { + cairo_pattern_set_extend(pattern_, extend); + } + + void set_filter(cairo_filter_t filter) + { + cairo_pattern_set_filter(pattern_, filter); + } + + cairo_pattern_t * pattern() const + { + return pattern_; + } + +private: + cairo_surface_t * surface_; + cairo_pattern_t * pattern_; +}; + + +class cairo_gradient : private mapnik::noncopyable +{ +public: + cairo_gradient(const mapnik::gradient &grad, double opacity=1.0) + { + double x1,x2,y1,y2,rad; + grad.get_control_points(x1,y1,x2,y2,rad); + if (grad.get_gradient_type() == LINEAR) + { + pattern_ = cairo_pattern_create_linear(x1, y1, x2, y2); + } + else if (grad.get_gradient_type() == RADIAL) + { + pattern_ = cairo_pattern_create_radial(x1, y1, 0, x2, y2, rad); + } + + units_ = grad.get_units(); + + BOOST_FOREACH ( mapnik::stop_pair const& st, grad.get_stop_array() ) + { + mapnik::color const& stop_color = st.second; + double r= static_cast (stop_color.red())/255.0; + double g= static_cast (stop_color.green())/255.0; + double b= static_cast (stop_color.blue())/255.0; + double a= static_cast (stop_color.alpha())/255.0; + cairo_pattern_add_color_stop_rgba(pattern_,st.first, r, g, b, a*opacity); + } + + double m[6]; + agg::trans_affine tr = grad.get_transform(); + tr.invert(); + tr.store_to(m); + cairo_matrix_t matrix; + cairo_matrix_init(&matrix,m[0],m[1],m[2],m[3],m[4],m[5]); + cairo_pattern_set_matrix(pattern_, &matrix); + } + + ~cairo_gradient() + { + if (pattern_) + cairo_pattern_destroy(pattern_); + } + + + cairo_pattern_t * gradient() const + { + return pattern_; + } + + gradient_unit_e units() const + { + return units_; + } + +private: + cairo_pattern_t * pattern_; + gradient_unit_e units_; + +}; + +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); + } +}; + +typedef boost::shared_ptr cairo_ptr; +typedef boost::shared_ptr cairo_surface_ptr; + +inline cairo_ptr create_context(cairo_surface_ptr const& surface) +{ + return cairo_ptr(cairo_create(&*surface),cairo_closer()); +} + +class cairo_context : private mapnik::noncopyable +{ +public: + + cairo_context(cairo_ptr const& cairo); + + inline ErrorStatus get_status() const + { + return cairo_status(cairo_.get()); + } + + void clip(); + void show_page(); + void set_color(color const &color, double opacity = 1.0); + void set_color(double r, double g, double b, double opacity = 1.0); + void set_operator(composite_mode_e comp_op); + void set_line_join(line_join_e join); + void set_line_cap(line_cap_e cap); + void set_miter_limit(double limit); + void set_line_width(double width); + void set_dash(dash_array const &dashes, double scale_factor); + void set_fill_rule(cairo_fill_rule_t fill_rule); + void move_to(double x, double y); + void curve_to(double ct1_x, double ct1_y, double ct2_x, double ct2_y, double end_x, double end_y); + void close_path(); + void line_to(double x, double y); + void rectangle(double x, double y, double w, double h); + void stroke(); + void fill(); + void paint(); + void set_pattern(cairo_pattern const& pattern); + void set_gradient(cairo_gradient const& pattern, const box2d &bbox); + void add_image(double x, double y, image_data_32 & data, double opacity = 1.0); + void add_image(agg::trans_affine const& tr, image_data_32 & data, double opacity = 1.0); + void set_font_face(cairo_face_manager & manager, face_ptr face); + void set_font_matrix(cairo_matrix_t const& matrix); + void set_matrix(cairo_matrix_t const& matrix); + void transform(cairo_matrix_t const& matrix); + void translate(double x, double y); + void save(); + void restore(); + void show_glyph(unsigned long index, double x, double y); + void glyph_path(unsigned long index, double x, double y); + void add_text(text_path const& path, + cairo_face_manager & manager, + face_manager & font_manager, + double scale_factor = 1.0); + + template + void add_path(T& path, unsigned start_index = 0) + { + double x, y; + path.rewind(start_index); + for (unsigned cm = path.vertex(&x, &y); cm != SEG_END; cm = path.vertex(&x, &y)) + { + if (cm == SEG_MOVETO) + { + move_to(x, y); + } + else if (cm == SEG_LINETO) + { + line_to(x, y); + } + else if (cm == SEG_CLOSE) + { + close_path(); + } + } + } + + template + void add_agg_path(T& path, unsigned start_index = 0) + { + double x=0; + double y=0; + + path.rewind(start_index); + + for (unsigned cm = path.vertex(&x, &y); !agg::is_stop(cm); cm = path.vertex(&x, &y)) + { + if (agg::is_move_to(cm)) + { + move_to(x, y); + } + else if (agg::is_drawing(cm)) + { + if (agg::is_curve3(cm)) + { + double end_x=0; + double end_y=0; + + MAPNIK_LOG_WARN(cairo_renderer) << "Curve 3 not implemented"; + + path.vertex(&end_x, &end_y); + + curve_to(x,y,x,y,end_x,end_y); + } + else if (agg::is_curve4(cm)) + { + double ct2_x=0; + double ct2_y=0; + double end_x=0; + double end_y=0; + + path.vertex(&ct2_x, &ct2_y); + path.vertex(&end_x, &end_y); + + curve_to(x,y,ct2_x,ct2_y,end_x,end_y); + } + else if (agg::is_line_to(cm)) + { + line_to(x, y); + } + else + { + MAPNIK_LOG_WARN(cairo_renderer) << "Unimplemented drawing command: " << cm; + move_to(x, y); + } + } + else if (agg::is_close(cm)) + { + close_path(); + } + else + { + MAPNIK_LOG_WARN(cairo_renderer) << "Unimplemented path command: " << cm; + } + } + } + +private: + cairo_ptr cairo_; +}; + + +} + + +#endif // MAPNIK_CAIRO_CONTEXT_HPP diff --git a/include/mapnik/cairo_renderer.hpp b/include/mapnik/cairo_renderer.hpp index e10ea484a..b1208e64e 100644 --- a/include/mapnik/cairo_renderer.hpp +++ b/include/mapnik/cairo_renderer.hpp @@ -33,10 +33,10 @@ #include #include // for all symbolizers #include +#include // cairo -#include -#include +#include // boost #include @@ -53,27 +53,11 @@ namespace mapnik { class marker; -class cairo_face; - -typedef boost::shared_ptr cairo_face_ptr; - -class cairo_face_manager : private mapnik::noncopyable -{ -public: - cairo_face_manager(boost::shared_ptr engine); - cairo_face_ptr get_face(face_ptr face); - -private: - typedef std::map cairo_face_cache; - boost::shared_ptr font_engine_; - cairo_face_cache cache_; -}; - class MAPNIK_DECL cairo_renderer_base : private mapnik::noncopyable { protected: - cairo_renderer_base(Map const& m, Cairo::RefPtr const& context, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); - cairo_renderer_base(Map const& m, Cairo::RefPtr const& context, boost::shared_ptr detector, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); + cairo_renderer_base(Map const& m, cairo_ptr const& cairo, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); + cairo_renderer_base(Map const& m, cairo_ptr const& cairo, boost::shared_ptr detector, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); public: ~cairo_renderer_base(); void start_map_processing(Map const& map); @@ -132,9 +116,9 @@ public: void render_box(box2d const& b); protected: - Map const& m_; - Cairo::RefPtr context_; + //Cairo::RefPtr context_; + cairo_context context_; unsigned width_; unsigned height_; double scale_factor_; @@ -152,8 +136,8 @@ class MAPNIK_DECL cairo_renderer : public feature_style_processor const& surface, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); - cairo_renderer(Map const& m, Cairo::RefPtr const& surface, boost::shared_ptr detector, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); + cairo_renderer(Map const& m, T const& obj, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); + cairo_renderer(Map const& m, T const& obj, boost::shared_ptr detector, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); void end_map_processing(Map const& map); }; } diff --git a/include/mapnik/expression.hpp b/include/mapnik/expression.hpp index c1894ae01..8672074ee 100644 --- a/include/mapnik/expression.hpp +++ b/include/mapnik/expression.hpp @@ -45,7 +45,6 @@ typedef std::set expression_set; MAPNIK_DECL expression_ptr parse_expression (std::string const& wkt, std::string const& encoding = "UTF8"); MAPNIK_DECL expression_ptr parse_expression (std::string const& wkt, mapnik::expression_grammar const& g); - } #endif // MAPNIK_EXPRESSION_HPP diff --git a/include/mapnik/graphics.hpp b/include/mapnik/graphics.hpp index 659f4fbca..1c559b6fe 100644 --- a/include/mapnik/graphics.hpp +++ b/include/mapnik/graphics.hpp @@ -37,7 +37,7 @@ // cairo #ifdef HAVE_CAIRO -#include +#include #endif // boost @@ -58,7 +58,7 @@ public: image_32(int width,int height); image_32(image_32 const& rhs); #ifdef HAVE_CAIRO - image_32(Cairo::RefPtr rhs); + explicit image_32(cairo_surface_ptr const& surface); #endif ~image_32(); @@ -184,9 +184,9 @@ public: #endif } } - + void composite_pixel(unsigned op, int x,int y,unsigned c, unsigned cover, double opacity); - + inline unsigned width() const { return width_; diff --git a/include/mapnik/params.hpp b/include/mapnik/params.hpp index 79e0c9cd9..9013bd891 100644 --- a/include/mapnik/params.hpp +++ b/include/mapnik/params.hpp @@ -26,7 +26,7 @@ // boost #include #include - +#include // mapnik #include @@ -40,6 +40,31 @@ typedef boost::variant value_ typedef std::pair parameter; typedef std::map param_map; +// TODO - rewrite to avoid usage of lexical_cast +template +struct value_extractor_visitor : public boost::static_visitor<> +{ + value_extractor_visitor(boost::optional & var) + :var_(var) {} + + void operator () (T val) const + { + var_ = val; + } + + template + void operator () (T1 val) const + { + try + { + var_ = boost::lexical_cast(val); + } + catch (boost::bad_lexical_cast & ) {} + } + + boost::optional & var_; +}; + class parameters : public param_map { public: diff --git a/src/build.py b/src/build.py index aa164f3e4..379e809da 100644 --- a/src/build.py +++ b/src/build.py @@ -17,7 +17,7 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA # -# +# import os @@ -204,6 +204,7 @@ if env['HAS_CAIRO']: libmapnik_cxxflags.append('-DHAVE_CAIRO') lib_env.PrependUnique(CPPPATH=copy(env['CAIROMM_CPPPATHS'])) source.insert(0,'cairo_renderer.cpp') + source.insert(0,'cairo_context.cpp') if env['JPEG']: source += Split( diff --git a/src/cairo_context.cpp b/src/cairo_context.cpp new file mode 100644 index 000000000..523ce6454 --- /dev/null +++ b/src/cairo_context.cpp @@ -0,0 +1,451 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2013 Artem Pavlenko + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + *****************************************************************************/ + +#include + +namespace mapnik { + +cairo_context::cairo_context(cairo_ptr const& cairo) + : cairo_(cairo) +{} + +void cairo_context::clip() +{ + cairo_clip(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::show_page() +{ + cairo_show_page(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_color(color const &color, double opacity) +{ + set_color(color.red()/255.0, color.green()/255.0, color.blue()/255.0, color.alpha() * opacity / 255.0); +} + +void cairo_context::set_color(double r, double g, double b, double opacity) +{ + cairo_set_source_rgb(cairo_.get(), r, g, b); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_operator(composite_mode_e comp_op) +{ + switch (comp_op) + { + case clear: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_CLEAR); + break; + case src: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_SOURCE); + break; + case dst: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_DEST); + break; + case src_over: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_OVER); + break; + case dst_over: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_DEST_OVER); + break; + case src_in: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_IN); + break; + case dst_in: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_DEST_IN); + break; + case src_out: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_OUT); + break; + case dst_out: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_DEST_OUT); + break; + case src_atop: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_ATOP); + break; + case dst_atop: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_DEST_ATOP); + break; + case _xor: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_XOR); + break; + case plus: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_ADD); + break; +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0) + case multiply: + cairo_set_operator(cairo_.get(), CAIRO_OPERATOR_MULTIPLY); + break; + case screen: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_SCREEN); + break; + case overlay: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_OVERLAY); + break; + case darken: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_DARKEN); + break; + case lighten: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_LIGHTEN); + break; + case color_dodge: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_COLOR_DODGE); + break; + case color_burn: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_COLOR_BURN); + break; + case hard_light: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_HARD_LIGHT); + break; + case soft_light: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_SOFT_LIGHT); + break; + case difference: + cairo_set_operator(cairo_.get(),CAIRO_OPERATOR_DIFFERENCE); + break; + case exclusion: + cairo_set_operator(cairo_.get(), CAIRO_OPERATOR_EXCLUSION); + break; +#else +#warning building against cairo older that 1.10.0, some compositing options are disabled + case multiply: + case screen: + case overlay: + case darken: + case lighten: + case color_dodge: + case color_burn: + case hard_light: + case soft_light: + case difference: + case exclusion: + break; +#endif + case contrast: + case minus: + case invert: + case invert_rgb: + case grain_merge: + case grain_extract: + case hue: + case saturation: + case _color: + case _value: + //case colorize_alpha: + break; + } + // + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_line_join(line_join_e join) +{ + if (join == MITER_JOIN) + cairo_set_line_join(cairo_.get(), CAIRO_LINE_JOIN_MITER); + else if (join == MITER_REVERT_JOIN) + cairo_set_line_join(cairo_.get(), CAIRO_LINE_JOIN_MITER); + else if (join == ROUND_JOIN) + cairo_set_line_join(cairo_.get(), CAIRO_LINE_JOIN_ROUND); + else + cairo_set_line_join(cairo_.get(), CAIRO_LINE_JOIN_BEVEL); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_line_cap(line_cap_e cap) +{ + if (cap == BUTT_CAP) + cairo_set_line_cap(cairo_.get(), CAIRO_LINE_CAP_BUTT); + else if (cap == SQUARE_CAP) + cairo_set_line_cap(cairo_.get(), CAIRO_LINE_CAP_SQUARE); + else + cairo_set_line_cap(cairo_.get(), CAIRO_LINE_CAP_ROUND); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_miter_limit(double limit) +{ + cairo_set_miter_limit(cairo_.get(), limit); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_line_width(double width) +{ + cairo_set_line_width(cairo_.get(), width); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_dash(dash_array const &dashes, double scale_factor) +{ + std::valarray d(dashes.size() * 2); + dash_array::const_iterator itr = dashes.begin(); + dash_array::const_iterator end = dashes.end(); + int index = 0; + + for (; itr != end; ++itr) + { + d[index++] = itr->first * scale_factor; + d[index++] = itr->second * scale_factor; + } + + cairo_set_dash(cairo_.get() , &d[0], dashes.size(), 0/*offset*/); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_fill_rule(cairo_fill_rule_t fill_rule) +{ + cairo_set_fill_rule(cairo_.get(),fill_rule); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::move_to(double x, double y) +{ +#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 6, 0) + if (x < -32767.0) x = -32767.0; + else if (x > 32767.0) x = 32767.0; + if (y < -32767.0) y = -32767.0; + else if (y > 32767.0) y = 32767.0; +#endif + cairo_move_to(cairo_.get(), x, y); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::curve_to(double ct1_x, double ct1_y, double ct2_x, double ct2_y, double end_x, double end_y) +{ + cairo_curve_to(cairo_.get(), ct1_x,ct1_y,ct2_x,ct2_y,end_x,end_y); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::close_path() +{ + cairo_close_path(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::line_to(double x, double y) +{ +#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 6, 0) + if (x < -32767.0) x = -32767.0; + else if (x > 32767.0) x = 32767.0; + if (y < -32767.0) y = -32767.0; + else if (y > 32767.0) y = 32767.0; +#endif + cairo_line_to(cairo_.get(), x, y); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::rectangle(double x, double y, double w, double h) +{ + cairo_rectangle(cairo_.get(), x, y, w, h); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::stroke() +{ + cairo_stroke(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::fill() +{ + cairo_fill(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::paint() +{ + cairo_paint(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_pattern(cairo_pattern const& pattern) +{ + cairo_set_source(cairo_.get(), pattern.pattern()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_gradient(cairo_gradient const& pattern, const box2d &bbox) +{ + cairo_pattern_t * gradient = pattern.gradient(); + double bx1=bbox.minx(); + double by1=bbox.miny(); + double bx2=bbox.maxx(); + double by2=bbox.maxy(); + if (pattern.units() != USER_SPACE_ON_USE) + { + if (pattern.units() == OBJECT_BOUNDING_BOX) + { + cairo_path_extents(cairo_.get(), &bx1, &by1, &bx2, &by2); + } + cairo_matrix_t cairo_matrix; + cairo_pattern_get_matrix(gradient, &cairo_matrix); + cairo_matrix_scale(&cairo_matrix,1.0/(bx2-bx1),1.0/(by2-by1)); + cairo_matrix_translate(&cairo_matrix, -bx1,-by1); + cairo_pattern_set_matrix(gradient, &cairo_matrix); + } + cairo_set_source(cairo_.get(), const_cast(gradient)); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::add_image(double x, double y, image_data_32 & data, double opacity) +{ + cairo_pattern pattern(data); + pattern.set_origin(x, y); + cairo_save(cairo_.get()); + cairo_set_source(cairo_.get(), const_cast(pattern.pattern())); + cairo_paint_with_alpha(cairo_.get(), opacity); + cairo_restore(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::add_image(agg::trans_affine const& tr, image_data_32 & data, double opacity) +{ + cairo_pattern pattern(data); + if (!tr.is_identity()) + { + double m[6]; + tr.store_to(m); + cairo_matrix_t cairo_matrix; + cairo_matrix_init(&cairo_matrix,m[0],m[1],m[2],m[3],m[4],m[5]); + cairo_matrix_invert(&cairo_matrix); + pattern.set_matrix(cairo_matrix); + } + cairo_save(cairo_.get()); + cairo_set_source(cairo_.get(), const_cast(pattern.pattern())); + cairo_paint_with_alpha(cairo_.get(), opacity); + cairo_restore(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_font_face(cairo_face_manager & manager, face_ptr face) +{ + cairo_set_font_face(cairo_.get(), manager.get_face(face)->face()); +} + +void cairo_context::set_font_matrix(cairo_matrix_t const& matrix) +{ + cairo_set_font_matrix(cairo_.get(), &matrix); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::set_matrix(cairo_matrix_t const& matrix) +{ + cairo_set_matrix(cairo_.get(), &matrix); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::transform(cairo_matrix_t const& matrix) +{ + cairo_transform(cairo_.get(), &matrix); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::translate(double x, double y) +{ + cairo_translate(cairo_.get(), x, y); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::save() +{ + cairo_save(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::restore() +{ + cairo_restore(cairo_.get()); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::show_glyph(unsigned long index, double x, double y) +{ + cairo_glyph_t glyph; + glyph.index = index; + glyph.x = x; + glyph.y = y; + + cairo_show_glyphs(cairo_.get(), &glyph, 1); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::glyph_path(unsigned long index, double x, double y) +{ + cairo_glyph_t glyph; + glyph.index = index; + glyph.x = x; + glyph.y = y; + + cairo_glyph_path(cairo_.get(), &glyph, 1); + check_object_status_and_throw_exception(*this); +} + +void cairo_context::add_text(text_path const& path, + cairo_face_manager & manager, + face_manager & font_manager, + double scale_factor) +{ + double sx = path.center.x; + double sy = path.center.y; + + path.rewind(); + + for (int iii = 0; iii < path.num_nodes(); iii++) + { + char_info_ptr c; + double x, y, angle; + + path.vertex(&c, &x, &y, &angle); + + face_set_ptr faces = font_manager.get_face_set(c->format->face_name, c->format->fontset); + double text_size = c->format->text_size * scale_factor; + faces->set_character_sizes(text_size); + + glyph_ptr glyph = faces->get_glyph(c->c); + + if (glyph) + { + cairo_matrix_t matrix; + matrix.xx = text_size * cos(angle); + matrix.xy = text_size * sin(angle); + matrix.yx = text_size * -sin(angle); + matrix.yy = text_size * cos(angle); + matrix.x0 = 0; + matrix.y0 = 0; + + set_font_matrix(matrix); + + set_font_face(manager, glyph->get_face()); + + glyph_path(glyph->get_index(), sx + x, sy - y); + set_line_width(2.0 * c->format->halo_radius * scale_factor); + set_line_join(ROUND_JOIN); + set_color(c->format->halo_fill); + stroke(); + set_color(c->format->fill); + show_glyph(glyph->get_index(), sx + x, sy - y); + } + } +} +} diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 667c0ca44..eeccef970 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -53,8 +54,7 @@ #include // cairo -#include -#include +#include #include #include @@ -78,179 +78,21 @@ namespace mapnik { -class cairo_pattern : private mapnik::noncopyable + +struct cairo_save_restore { -public: - cairo_pattern(image_data_32 const& data) + cairo_save_restore(cairo_context & context) + : context_(context) { - int pixels = data.width() * data.height(); - const unsigned int *in_ptr = data.getData(); - const unsigned int *in_end = in_ptr + pixels; - unsigned int *out_ptr; - - surface_ = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, data.width(), data.height()); - - out_ptr = reinterpret_cast(surface_->get_data()); - - while (in_ptr < in_end) - { - unsigned int in = *in_ptr++; - unsigned int r = (in >> 0) & 0xff; - unsigned int g = (in >> 8) & 0xff; - unsigned int b = (in >> 16) & 0xff; - unsigned int a = (in >> 24) & 0xff; - - //r = r * a / 255; - //g = g * a / 255; - //b = b * a / 255; - - *out_ptr++ = (a << 24) | (r << 16) | (g << 8) | b; - } - // mark the surface as dirty as we've modified it behind cairo's back - surface_->mark_dirty(); - pattern_ = Cairo::SurfacePattern::create(surface_); + context_.save(); } - - ~cairo_pattern() + ~cairo_save_restore() { + context_.restore(); } - - void set_matrix(Cairo::Matrix const& matrix) - { - pattern_->set_matrix(matrix); - } - - void set_origin(double x, double y) - { - Cairo::Matrix matrix; - - pattern_->get_matrix(matrix); - - matrix.x0 = -x; - matrix.y0 = -y; - - pattern_->set_matrix(matrix); - } - - void set_extend(Cairo::Extend extend) - { - pattern_->set_extend(extend); - } - - void set_filter(Cairo::Filter filter) - { - pattern_->set_filter(filter); - } - - Cairo::RefPtr const& pattern() const - { - return pattern_; - } - -private: - Cairo::RefPtr surface_; - Cairo::RefPtr pattern_; + cairo_context & context_; }; -class cairo_gradient : private mapnik::noncopyable -{ -public: - cairo_gradient(const mapnik::gradient &grad, double opacity=1.0) - { - double x1,x2,y1,y2,rad; - grad.get_control_points(x1,y1,x2,y2,rad); - if (grad.get_gradient_type() == LINEAR) - { - pattern_ = Cairo::LinearGradient::create(x1, y1, x2, y2); - } - else if (grad.get_gradient_type() == RADIAL) - { - pattern_ = Cairo::RadialGradient::create(x1, y1, 0, x2, y2, rad); - } - - units_ = grad.get_units(); - - BOOST_FOREACH ( mapnik::stop_pair const& st, grad.get_stop_array() ) - { - mapnik::color const& stop_color = st.second; - double r= static_cast (stop_color.red())/255.0; - double g= static_cast (stop_color.green())/255.0; - double b= static_cast (stop_color.blue())/255.0; - double a= static_cast (stop_color.alpha())/255.0; - pattern_->add_color_stop_rgba(st.first, r, g, b, a*opacity); - } - - double m[6]; - agg::trans_affine tr = grad.get_transform(); - tr.invert(); - tr.store_to(m); - pattern_->set_matrix(Cairo::Matrix(m[0],m[1],m[2],m[3],m[4],m[5])); - } - - ~cairo_gradient() - { - } - - - Cairo::RefPtr const& gradient() const - { - return pattern_; - } - - gradient_unit_e units() const - { - return units_; - } - -private: - Cairo::RefPtr pattern_; - gradient_unit_e units_; - -}; - -class cairo_face : private mapnik::noncopyable -{ -public: - cairo_face(boost::shared_ptr const& engine, face_ptr const& face) - : face_(face) - { - static cairo_user_data_key_t key; - cairo_font_face_t *c_face; - - c_face = cairo_ft_font_face_create_for_ft_face(face->get_face(), FT_LOAD_NO_HINTING); - cairo_font_face_set_user_data(c_face, &key, new handle(engine, face), destroy); - - cairo_face_ = Cairo::RefPtr(new Cairo::FontFace(c_face)); - } - - Cairo::RefPtr const& face() const - { - return cairo_face_; - } - -private: - class handle - { - public: - handle(boost::shared_ptr const& engine, face_ptr const& face) - : engine_(engine), face_(face) {} - - private: - boost::shared_ptr engine_; - face_ptr face_; - }; - - static void destroy(void *data) - { - handle *h = static_cast(data); - - delete h; - } - -private: - face_ptr face_; - Cairo::RefPtr cairo_face_; -}; cairo_face_manager::cairo_face_manager(boost::shared_ptr engine) : font_engine_(engine) @@ -275,512 +117,14 @@ cairo_face_ptr cairo_face_manager::get_face(face_ptr face) return entry; } -class cairo_context : private mapnik::noncopyable -{ -public: - cairo_context(Cairo::RefPtr const& context) - : context_(context) - { - context_->save(); - } - - ~cairo_context() - { - context_->restore(); - } - - void set_color(color const &color, double opacity = 1.0) - { - set_color(color.red()/255.0, color.green()/255.0, color.blue()/255.0, color.alpha() * opacity / 255.0); - } - - void set_color(double r, double g, double b, double opacity = 1.0) - { - context_->set_source_rgba(r, g, b, opacity); - } - - void set_operator(composite_mode_e comp_op) - { - switch (comp_op) - { - case clear: - context_->set_operator(Cairo::OPERATOR_CLEAR); - break; - case src: - context_->set_operator(Cairo::OPERATOR_SOURCE); - break; - case dst: - context_->set_operator(Cairo::OPERATOR_DEST); - break; - case src_over: - context_->set_operator(Cairo::OPERATOR_OVER); - break; - case dst_over: - context_->set_operator(Cairo::OPERATOR_DEST_OVER); - break; - case src_in: - context_->set_operator(Cairo::OPERATOR_IN); - break; - case dst_in: - context_->set_operator(Cairo::OPERATOR_DEST_IN); - break; - case src_out: - context_->set_operator(Cairo::OPERATOR_OUT); - break; - case dst_out: - context_->set_operator(Cairo::OPERATOR_DEST_OUT); - break; - case src_atop: - context_->set_operator(Cairo::OPERATOR_ATOP); - break; - case dst_atop: - context_->set_operator(Cairo::OPERATOR_DEST_ATOP); - break; - case _xor: - context_->set_operator(Cairo::OPERATOR_XOR); - break; - case plus: - context_->set_operator(Cairo::OPERATOR_ADD); - break; -#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 10, 0) - case multiply: - context_->set_operator(static_cast(CAIRO_OPERATOR_MULTIPLY)); - break; - case screen: - context_->set_operator(static_cast(CAIRO_OPERATOR_SCREEN)); - break; - case overlay: - context_->set_operator(static_cast(CAIRO_OPERATOR_OVERLAY)); - break; - case darken: - context_->set_operator(static_cast(CAIRO_OPERATOR_DARKEN)); - break; - case lighten: - context_->set_operator(static_cast(CAIRO_OPERATOR_LIGHTEN)); - break; - case color_dodge: - context_->set_operator(static_cast(CAIRO_OPERATOR_COLOR_DODGE)); - break; - case color_burn: - context_->set_operator(static_cast(CAIRO_OPERATOR_COLOR_BURN)); - break; - case hard_light: - context_->set_operator(static_cast(CAIRO_OPERATOR_HARD_LIGHT)); - break; - case soft_light: - context_->set_operator(static_cast(CAIRO_OPERATOR_SOFT_LIGHT)); - break; - case difference: - context_->set_operator(static_cast(CAIRO_OPERATOR_DIFFERENCE)); - break; - case exclusion: - context_->set_operator(static_cast(CAIRO_OPERATOR_EXCLUSION)); - break; -#else -#warning building against cairo older that 1.10.0, some compositing options are disabled - case multiply: - case screen: - case overlay: - case darken: - case lighten: - case color_dodge: - case color_burn: - case hard_light: - case soft_light: - case difference: - case exclusion: - break; -#endif - case contrast: - case minus: - case invert: - case invert_rgb: - case grain_merge: - case grain_extract: - case hue: - case saturation: - case _color: - case _value: - //case colorize_alpha: - break; - } - } - - void set_line_join(line_join_e join) - { - if (join == MITER_JOIN) - context_->set_line_join(Cairo::LINE_JOIN_MITER); - else if (join == MITER_REVERT_JOIN) - context_->set_line_join(Cairo::LINE_JOIN_MITER); - else if (join == ROUND_JOIN) - context_->set_line_join(Cairo::LINE_JOIN_ROUND); - else - context_->set_line_join(Cairo::LINE_JOIN_BEVEL); - } - - void set_line_cap(line_cap_e cap) - { - if (cap == BUTT_CAP) - context_->set_line_cap(Cairo::LINE_CAP_BUTT); - else if (cap == SQUARE_CAP) - context_->set_line_cap(Cairo::LINE_CAP_SQUARE); - else - context_->set_line_cap(Cairo::LINE_CAP_ROUND); - } - - void set_miter_limit(double limit) - { - context_->set_miter_limit(limit); - } - - void set_line_width(double width) - { - context_->set_line_width(width); - } - - void set_dash(dash_array const &dashes, double scale_factor) - { - std::valarray d(dashes.size() * 2); - dash_array::const_iterator itr = dashes.begin(); - dash_array::const_iterator end = dashes.end(); - int index = 0; - - for (; itr != end; ++itr) - { - d[index++] = itr->first * scale_factor; - d[index++] = itr->second * scale_factor; - } - - context_->set_dash(d, 0.0); - } - - void set_fill_rule(Cairo::FillRule fill_rule) - { - context_->set_fill_rule(fill_rule); - } - - void move_to(double x, double y) - { -#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 6, 0) - if (x < -32767.0) x = -32767.0; - else if (x > 32767.0) x = 32767.0; - if (y < -32767.0) y = -32767.0; - else if (y > 32767.0) y = 32767.0; -#endif - - context_->move_to(x, y); - } - - void curve_to(double ct1_x, double ct1_y, double ct2_x, double ct2_y, double end_x, double end_y) - { - context_->curve_to(ct1_x,ct1_y,ct2_x,ct2_y,end_x,end_y); - } - - void close_path() - { - context_->close_path(); - } - - void line_to(double x, double y) - { -#if CAIRO_VERSION < CAIRO_VERSION_ENCODE(1, 6, 0) - if (x < -32767.0) x = -32767.0; - else if (x > 32767.0) x = 32767.0; - if (y < -32767.0) y = -32767.0; - else if (y > 32767.0) y = 32767.0; -#endif - - context_->line_to(x, y); - } - - template - void add_path(T& path, unsigned start_index = 0) - { - double x, y; - - path.rewind(start_index); - - for (unsigned cm = path.vertex(&x, &y); cm != SEG_END; cm = path.vertex(&x, &y)) - { - if (cm == SEG_MOVETO) - { - move_to(x, y); - } - else if (cm == SEG_LINETO) - { - line_to(x, y); - } - else if (cm == SEG_CLOSE) - { - close_path(); - } - } - } - - template - void add_agg_path(T& path, unsigned start_index = 0) - { - double x=0; - double y=0; - - path.rewind(start_index); - - for (unsigned cm = path.vertex(&x, &y); !agg::is_stop(cm); cm = path.vertex(&x, &y)) - { - if (agg::is_move_to(cm)) - { - move_to(x, y); - } - else if (agg::is_drawing(cm)) - { - if (agg::is_curve3(cm)) - { - double end_x=0; - double end_y=0; - - MAPNIK_LOG_WARN(cairo_renderer) << "Curve 3 not implemented"; - - path.vertex(&end_x, &end_y); - - curve_to(x,y,x,y,end_x,end_y); - } - else if (agg::is_curve4(cm)) - { - double ct2_x=0; - double ct2_y=0; - double end_x=0; - double end_y=0; - - path.vertex(&ct2_x, &ct2_y); - path.vertex(&end_x, &end_y); - - curve_to(x,y,ct2_x,ct2_y,end_x,end_y); - } - else if (agg::is_line_to(cm)) - { - line_to(x, y); - } - else - { - MAPNIK_LOG_WARN(cairo_renderer) << "Unimplemented drawing command: " << cm; - move_to(x, y); - } - } - else if (agg::is_close(cm)) - { - close_path(); - } - else - { - MAPNIK_LOG_WARN(cairo_renderer) << "Unimplemented path command: " << cm; - } - } - } - - void rectangle(double x, double y, double w, double h) - { - context_->rectangle(x, y, w, h); - } - - void stroke() - { - context_->stroke(); - } - - void fill() - { - context_->fill(); - } - - void paint() - { - context_->paint(); - } - - void set_pattern(cairo_pattern const& pattern) - { - context_->set_source(pattern.pattern()); - } - - void set_gradient(cairo_gradient const& pattern, const box2d &bbox) - { - Cairo::RefPtr p = pattern.gradient(); - - double bx1=bbox.minx(); - double by1=bbox.miny(); - double bx2=bbox.maxx(); - double by2=bbox.maxy(); - if (pattern.units() != USER_SPACE_ON_USE) - { - if (pattern.units() == OBJECT_BOUNDING_BOX) - { - context_->get_path_extents (bx1, by1, bx2, by2); - } - Cairo::Matrix m = p->get_matrix(); - m.scale(1.0/(bx2-bx1),1.0/(by2-by1)); - m.translate(-bx1,-by1); - p->set_matrix(m); - } - - context_->set_source(p); - } - - void add_image(double x, double y, image_data_32 & data, double opacity = 1.0) - { - cairo_pattern pattern(data); - - pattern.set_origin(x, y); - - context_->save(); - context_->set_source(pattern.pattern()); - context_->paint_with_alpha(opacity); - context_->restore(); - } - - void add_image(agg::trans_affine const& tr, image_data_32 & data, double opacity = 1.0) - { - cairo_pattern pattern(data); - if (!tr.is_identity()) - { - double m[6]; - tr.store_to(m); - Cairo::Matrix cairo_matrix(m[0],m[1],m[2],m[3],m[4],m[5]); - cairo_matrix.invert(); - pattern.set_matrix(cairo_matrix); - } - context_->save(); - context_->set_source(pattern.pattern()); - context_->paint_with_alpha(opacity); - context_->restore(); - } - - - void set_font_face(cairo_face_manager & manager, face_ptr face) - { - context_->set_font_face(manager.get_face(face)->face()); - } - - void set_font_matrix(Cairo::Matrix const& matrix) - { - context_->set_font_matrix(matrix); - } - - void set_matrix(Cairo::Matrix const& matrix) - { - context_->set_matrix(matrix); - } - - void transform(Cairo::Matrix const& matrix) - { - context_->transform(matrix); - } - - void translate(double x, double y) - { - context_->translate(x,y); - } - - void save() - { - context_->save(); - } - - void restore() - { - context_->restore(); - } - - void show_glyph(unsigned long index, double x, double y) - { - Cairo::Glyph glyph; - - glyph.index = index; - glyph.x = x; - glyph.y = y; - - cairo_show_glyphs(context_->cobj(), &glyph, 1); - if (context_->get_status() != CAIRO_STATUS_SUCCESS) - { - throw std::runtime_error("cairo: show_glyph"); - } - } - - void glyph_path(unsigned long index, double x, double y) - { - Cairo::Glyph glyph; - - glyph.index = index; - glyph.x = x; - glyph.y = y; - - cairo_glyph_path(context_->cobj(), &glyph, 1); - if (context_->get_status() != CAIRO_STATUS_SUCCESS) - { - throw std::runtime_error("cairo: glyph_path"); - } - } - - void add_text(text_path const& path, - cairo_face_manager & manager, - face_manager &font_manager, - double scale_factor = 1.0) - { - double sx = path.center.x; - double sy = path.center.y; - - path.rewind(); - - for (int iii = 0; iii < path.num_nodes(); iii++) - { - char_info_ptr c; - double x, y, angle; - - path.vertex(&c, &x, &y, &angle); - - face_set_ptr faces = font_manager.get_face_set(c->format->face_name, c->format->fontset); - double text_size = c->format->text_size * scale_factor; - faces->set_character_sizes(text_size); - - glyph_ptr glyph = faces->get_glyph(c->c); - - if (glyph) - { - Cairo::Matrix matrix; - - matrix.xx = text_size * cos(angle); - matrix.xy = text_size * sin(angle); - matrix.yx = text_size * -sin(angle); - matrix.yy = text_size * cos(angle); - matrix.x0 = 0; - matrix.y0 = 0; - - set_font_matrix(matrix); - - set_font_face(manager, glyph->get_face()); - - glyph_path(glyph->get_index(), sx + x, sy - y); - set_line_width(2.0 * c->format->halo_radius * scale_factor); - set_line_join(ROUND_JOIN); - set_color(c->format->halo_fill); - stroke(); - set_color(c->format->fill); - show_glyph(glyph->get_index(), sx + x, sy - y); - } - } - } - - -private: - Cairo::RefPtr context_; -}; cairo_renderer_base::cairo_renderer_base(Map const& m, - Cairo::RefPtr const& context, + cairo_ptr const& cairo, double scale_factor, unsigned offset_x, unsigned offset_y) : m_(m), - context_(context), + context_(cairo), width_(m.width()), height_(m.height()), scale_factor_(scale_factor), @@ -796,13 +140,13 @@ cairo_renderer_base::cairo_renderer_base(Map const& m, } cairo_renderer_base::cairo_renderer_base(Map const& m, - Cairo::RefPtr const& context, + cairo_ptr const& cairo, boost::shared_ptr detector, double scale_factor, unsigned offset_x, unsigned offset_y) : m_(m), - context_(context), + context_(cairo), width_(m.width()), height_(m.height()), scale_factor_(scale_factor), @@ -816,24 +160,24 @@ cairo_renderer_base::cairo_renderer_base(Map const& m, } template <> -cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& context, double scale_factor, unsigned offset_x, unsigned offset_y) +cairo_renderer::cairo_renderer(Map const& m, cairo_ptr const& cairo, double scale_factor, unsigned offset_x, unsigned offset_y) : feature_style_processor(m,scale_factor), - cairo_renderer_base(m,context,scale_factor,offset_x,offset_y) {} + cairo_renderer_base(m,cairo,scale_factor,offset_x,offset_y) {} template <> -cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& surface, double scale_factor, unsigned offset_x, unsigned offset_y) +cairo_renderer::cairo_renderer(Map const& m, cairo_surface_ptr const& surface, double scale_factor, unsigned offset_x, unsigned offset_y) : feature_style_processor(m,scale_factor), - cairo_renderer_base(m,Cairo::Context::create(surface),scale_factor,offset_x,offset_y) {} + cairo_renderer_base(m,create_context(surface),scale_factor,offset_x,offset_y) {} template <> -cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& context, boost::shared_ptr detector, double scale_factor, unsigned offset_x, unsigned offset_y) +cairo_renderer::cairo_renderer(Map const& m, cairo_ptr const& cairo, boost::shared_ptr detector, double scale_factor, unsigned offset_x, unsigned offset_y) : feature_style_processor(m,scale_factor), - cairo_renderer_base(m,context,detector,scale_factor,offset_x,offset_y) {} + cairo_renderer_base(m,cairo,detector,scale_factor,offset_x,offset_y) {} template <> -cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& surface, boost::shared_ptr detector, double scale_factor, unsigned offset_x, unsigned offset_y) +cairo_renderer::cairo_renderer(Map const& m, cairo_surface_ptr const& surface, boost::shared_ptr detector, double scale_factor, unsigned offset_x, unsigned offset_y) : feature_style_processor(m,scale_factor), - cairo_renderer_base(m,Cairo::Context::create(surface),detector,scale_factor,offset_x,offset_y) {} + cairo_renderer_base(m,create_context(surface),detector,scale_factor,offset_x,offset_y) {} cairo_renderer_base::~cairo_renderer_base() {} @@ -843,8 +187,8 @@ void cairo_renderer_base::start_map_processing(Map const& map) #if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 6, 0) box2d bounds = t_.forward(t_.extent()); - context_->rectangle(bounds.minx(), bounds.miny(), bounds.maxx(), bounds.maxy()); - context_->clip(); + context_.rectangle(bounds.minx(), bounds.miny(), bounds.maxx(), bounds.maxy()); + context_.clip(); #else #warning building against cairo older that 1.6.0, map clipping is disabled #endif @@ -852,24 +196,24 @@ void cairo_renderer_base::start_map_processing(Map const& map) boost::optional bg = m_.background(); if (bg) { - cairo_context context(context_); - context.set_color(*bg); - context.paint(); + cairo_save_restore guard(context_); + context_.set_color(*bg); + context_.paint(); } } template <> -void cairo_renderer::end_map_processing(Map const& ) +void cairo_renderer::end_map_processing(Map const& ) { MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: End map processing"; } template <> -void cairo_renderer::end_map_processing(Map const& ) +void cairo_renderer::end_map_processing(Map const& ) { MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: End map processing"; - context_->show_page(); + context_.show_page(); } void cairo_renderer_base::start_layer_processing(layer const& lay, box2d const& query_extent) @@ -904,9 +248,9 @@ void cairo_renderer_base::process(polygon_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - cairo_context context(context_); - context.set_operator(sym.comp_op()); - context.set_color(sym.get_fill(), sym.get_opacity()); + cairo_save_restore guard(context_); + context_.set_operator(sym.comp_op()); + context_.set_color(sym.get_fill(), sym.get_opacity()); agg::trans_affine tr; evaluate_transform(tr, feature, sym.get_transform()); @@ -914,7 +258,7 @@ void cairo_renderer_base::process(polygon_symbolizer const& sym, typedef boost::mpl::vector conv_types; vertex_converter, cairo_context, polygon_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(query_extent_,context,sym,t_,prj_trans,tr,1.0); + converter(query_extent_,context_,sym,t_,prj_trans,tr,1.0); if (prj_trans.equal() && sym.clip()) converter.set(); //optional clip (default: true) converter.set(); //always transform @@ -930,7 +274,7 @@ void cairo_renderer_base::process(polygon_symbolizer const& sym, } } // fill polygon - context.fill(); + context_.fill(); } void cairo_renderer_base::process(building_symbolizer const& sym, @@ -938,9 +282,8 @@ void cairo_renderer_base::process(building_symbolizer const& sym, proj_transform const& prj_trans) { typedef coord_transform path_type; - - cairo_context context(context_); - context.set_operator(sym.comp_op()); + cairo_save_restore guard(context_); + context_.set_operator(sym.comp_op()); color const& fill = sym.get_fill(); double height = 0.0; expression_ptr height_expr = sym.height(); @@ -991,10 +334,10 @@ void cairo_renderer_base::process(building_symbolizer const& sym, faces->line_to(itr->get<0>(), itr->get<1>() + height); path_type faces_path(t_, *faces, prj_trans); - context.set_color(fill.red() * 0.8 / 255.0, fill.green() * 0.8 / 255.0, + context_.set_color(fill.red() * 0.8 / 255.0, fill.green() * 0.8 / 255.0, fill.blue() * 0.8 / 255.0, fill.alpha() * sym.get_opacity() / 255.0); - context.add_path(faces_path); - context.fill(); + context_.add_path(faces_path); + context_.fill(); frame->move_to(itr->get<0>(), itr->get<1>()); frame->line_to(itr->get<0>(), itr->get<1>() + height); @@ -1017,16 +360,16 @@ void cairo_renderer_base::process(building_symbolizer const& sym, } path_type path(t_, *frame, prj_trans); - context.set_color(fill.red() * 0.8 / 255.0, fill.green() * 0.8/255.0, + context_.set_color(fill.red() * 0.8 / 255.0, fill.green() * 0.8/255.0, fill.blue() * 0.8 / 255.0, fill.alpha() * sym.get_opacity() / 255.0); - context.set_line_width(scale_factor_); - context.add_path(path); - context.stroke(); + context_.set_line_width(scale_factor_); + context_.add_path(path); + context_.stroke(); path_type roof_path(t_, *roof, prj_trans); - context.set_color(fill, sym.get_opacity()); - context.add_path(roof_path); - context.fill(); + context_.set_color(fill, sym.get_opacity()); + context_.add_path(roof_path); + context_.fill(); } } } @@ -1038,18 +381,17 @@ void cairo_renderer_base::process(line_symbolizer const& sym, typedef boost::mpl::vector conv_types; - cairo_context context(context_); + cairo_save_restore guard(context_); mapnik::stroke const& stroke_ = sym.get_stroke(); - context.set_operator(sym.comp_op()); - - context.set_color(stroke_.get_color(), stroke_.get_opacity()); - context.set_line_join(stroke_.get_line_join()); - context.set_line_cap(stroke_.get_line_cap()); - context.set_miter_limit(stroke_.get_miterlimit()); - context.set_line_width(stroke_.get_width() * scale_factor_); + context_.set_operator(sym.comp_op()); + context_.set_color(stroke_.get_color(), stroke_.get_opacity()); + context_.set_line_join(stroke_.get_line_join()); + context_.set_line_cap(stroke_.get_line_cap()); + context_.set_miter_limit(stroke_.get_miterlimit()); + context_.set_line_width(stroke_.get_width() * scale_factor_); if (stroke_.has_dash()) { - context.set_dash(stroke_.get_dash_array(), scale_factor_); + context_.set_dash(stroke_.get_dash_array(), scale_factor_); } agg::trans_affine tr; @@ -1068,7 +410,7 @@ void cairo_renderer_base::process(line_symbolizer const& sym, } vertex_converter, cairo_context, line_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(clipping_extent,context,sym,t_,prj_trans,tr,scale_factor_); + converter(clipping_extent,context_,sym,t_,prj_trans,tr,scale_factor_); if (sym.clip()) converter.set(); // optional clip (default: true) converter.set(); // always transform @@ -1085,19 +427,18 @@ void cairo_renderer_base::process(line_symbolizer const& sym, } } // stroke - context.stroke(); + context_.stroke(); } void cairo_renderer_base::render_box(box2d const& b) { - cairo_context context(context_); - context.move_to(b.minx(), b.miny()); - context.line_to(b.minx(), b.maxy()); - context.line_to(b.maxx(), b.maxy()); - context.line_to(b.maxx(), b.miny()); - context.close_path(); - - context.stroke(); + cairo_save_restore guard(context_); + context_.move_to(b.minx(), b.miny()); + context_.line_to(b.minx(), b.maxy()); + context_.line_to(b.maxx(), b.maxy()); + context_.line_to(b.maxx(), b.miny()); + context_.close_path(); + context_.stroke(); } void render_vector_marker(cairo_context & context, pixel_position const& pos, mapnik::svg_storage_type & vmarker, @@ -1124,9 +465,7 @@ void render_vector_marker(cairo_context & context, pixel_position const& pos, ma mapnik::svg::path_attributes const& attr = attributes[i]; if (!attr.visibility_flag) continue; - - context.save(); - + cairo_save_restore guard(context); transform = attr.transform; transform *= mtx; @@ -1137,7 +476,9 @@ void render_vector_marker(cairo_context & context, pixel_position const& pos, ma { double m[6]; transform.store_to(m); - context.transform(Cairo::Matrix(m[0],m[1],m[2],m[3],m[4],m[5])); + cairo_matrix_t matrix; + cairo_matrix_init(&matrix,m[0],m[1],m[2],m[3],m[4],m[5]); + context.transform(matrix); } vertex_stl_adapter stl_storage(vmarker.source()); @@ -1148,11 +489,11 @@ void render_vector_marker(cairo_context & context, pixel_position const& pos, ma context.add_agg_path(svg_path,attr.index); if (attr.even_odd_flag) { - context.set_fill_rule(Cairo::FILL_RULE_EVEN_ODD); + context.set_fill_rule(CAIRO_FILL_RULE_EVEN_ODD); } else { - context.set_fill_rule(Cairo::FILL_RULE_WINDING); + context.set_fill_rule(CAIRO_FILL_RULE_WINDING); } if(attr.fill_gradient.get_gradient_type() != NO_GRADIENT) { @@ -1195,8 +536,6 @@ void render_vector_marker(cairo_context & context, pixel_position const& pos, ma context.stroke(); } } - - context.restore(); } } @@ -1204,15 +543,14 @@ void render_vector_marker(cairo_context & context, pixel_position const& pos, ma void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& marker, const agg::trans_affine & tr, double opacity, bool recenter) { - cairo_context context(context_); - + cairo_save_restore guard(context_); if (marker.is_vector()) { mapnik::svg_path_ptr vmarker = *marker.get_vector_data(); if (vmarker) { agg::pod_bvector const & attributes = vmarker->attributes(); - render_vector_marker(context, pos, *vmarker, attributes, tr, opacity, recenter); + render_vector_marker(context_, pos, *vmarker, attributes, tr, opacity, recenter); } } else if (marker.is_bitmap()) @@ -1225,7 +563,7 @@ void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& matrix *= agg::trans_affine_translation( boost::math::iround(pos.x - cx), boost::math::iround(pos.y - cy)); - context.add_image(matrix, **marker.get_bitmap_data(), opacity); + context_.add_image(matrix, **marker.get_bitmap_data(), opacity); } } @@ -1298,8 +636,9 @@ void cairo_renderer_base::process(shield_symbolizer const& sym, width_, height_, scale_factor_, t_, font_manager_, *detector_, query_extent_); - cairo_context context(context_); - context.set_operator(sym.comp_op()); + + cairo_save_restore guard(context_); + context_.set_operator(sym.comp_op()); while (helper.next()) { @@ -1320,7 +659,7 @@ void cairo_renderer_base::process(shield_symbolizer const& sym, marker_tr, sym.get_opacity()); - context.add_text(placements[ii], face_manager_, font_manager_, scale_factor_); + context_.add_text(placements[ii], face_manager_, font_manager_, scale_factor_); } } } @@ -1339,13 +678,13 @@ void cairo_renderer_base::process(line_pattern_symbolizer const& sym, unsigned width((*marker)->width()); unsigned height((*marker)->height()); - cairo_context context(context_); - context.set_operator(sym.comp_op()); + cairo_save_restore guard(context_); + context_.set_operator(sym.comp_op()); cairo_pattern pattern(**((*marker)->get_bitmap_data())); - pattern.set_extend(Cairo::EXTEND_REPEAT); - pattern.set_filter(Cairo::FILTER_BILINEAR); - context.set_line_width(height * scale_factor_); + pattern.set_extend(CAIRO_EXTEND_REPEAT); + pattern.set_filter(CAIRO_FILTER_BILINEAR); + context_.set_line_width(height * scale_factor_); for (unsigned i = 0; i < feature.num_geometries(); ++i) { @@ -1374,7 +713,7 @@ void cairo_renderer_base::process(line_pattern_symbolizer const& sym, double angle = atan2(dy, dx); double offset = fmod(length, width); - Cairo::Matrix matrix; + cairo_matrix_t matrix; cairo_matrix_init_identity(&matrix); cairo_matrix_translate(&matrix,x0,y0); cairo_matrix_rotate(&matrix,angle); @@ -1383,11 +722,11 @@ void cairo_renderer_base::process(line_pattern_symbolizer const& sym, pattern.set_matrix(matrix); - context.set_pattern(pattern); + context_.set_pattern(pattern); - context.move_to(x0, y0); - context.line_to(x, y); - context.stroke(); + context_.move_to(x0, y0); + context_.line_to(x, y); + context_.stroke(); length = length + hypot(x - x0, y - y0); } @@ -1406,8 +745,8 @@ void cairo_renderer_base::process(polygon_pattern_symbolizer const& sym, typedef agg::conv_clip_polygon clipped_geometry_type; typedef coord_transform path_type; - cairo_context context(context_); - context.set_operator(sym.comp_op()); + cairo_save_restore guard(context_); + context_.set_operator(sym.comp_op()); std::string filename = path_processor_type::evaluate( *sym.get_filename(), feature); boost::optional marker = mapnik::marker_cache::instance().find(filename,true); @@ -1415,9 +754,9 @@ void cairo_renderer_base::process(polygon_pattern_symbolizer const& sym, cairo_pattern pattern(**((*marker)->get_bitmap_data())); - pattern.set_extend(Cairo::EXTEND_REPEAT); + pattern.set_extend(CAIRO_EXTEND_REPEAT); - context.set_pattern(pattern); + context_.set_pattern(pattern); //pattern_alignment_e align = sym.get_alignment(); //unsigned offset_x=0; @@ -1444,7 +783,7 @@ void cairo_renderer_base::process(polygon_pattern_symbolizer const& sym, typedef boost::mpl::vector conv_types; vertex_converter, cairo_context, polygon_pattern_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(query_extent_,context,sym,t_,prj_trans,tr, scale_factor_); + converter(query_extent_,context_,sym,t_,prj_trans,tr, scale_factor_); if (prj_trans.equal() && sym.clip()) converter.set(); //optional clip (default: true) converter.set(); //always transform @@ -1460,7 +799,7 @@ void cairo_renderer_base::process(polygon_pattern_symbolizer const& sym, } } // fill polygon - context.fill(); + context_.fill(); } void cairo_renderer_base::process(raster_symbolizer const& sym, @@ -1529,9 +868,9 @@ void cairo_renderer_base::process(raster_symbolizer const& sym, filter_radius); } } - cairo_context context(context_); - context.set_operator(sym.comp_op()); - context.add_image(start_x, start_y, target.data_, sym.get_opacity()); + cairo_save_restore guard(context_); + context_.set_operator(sym.comp_op()); + context_.add_image(start_x, start_y, target.data_, sym.get_opacity()); } } } @@ -1725,8 +1064,8 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, { typedef boost::mpl::vector conv_types; - cairo_context context(context_); - context.set_operator(sym.comp_op()); + cairo_save_restore guard(context_); + context_.set_operator(sym.comp_op()); agg::trans_affine tr = agg::trans_affine_scaling(scale_factor_); @@ -1770,7 +1109,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, evaluate_transform(marker_tr, feature, sym.get_image_transform()); box2d new_bbox = marker_ellipse.bounding_box(); - dispatch_type dispatch(context, marker_ellipse, result?attributes:(*stock_vector_marker)->attributes(), + dispatch_type dispatch(context_, marker_ellipse, result?attributes:(*stock_vector_marker)->attributes(), *detector_, sym, new_bbox, marker_tr, scale_factor_); vertex_converter, dispatch_type, markers_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> @@ -1795,7 +1134,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, svg_attributes_type attributes; bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); - dispatch_type dispatch(context, **stock_vector_marker, result?attributes:(*stock_vector_marker)->attributes(), + dispatch_type dispatch(context_, **stock_vector_marker, result?attributes:(*stock_vector_marker)->attributes(), *detector_, sym, bbox, tr, scale_factor_); vertex_converter, dispatch_type, markers_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> @@ -1824,7 +1163,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, boost::optional marker = (*mark)->get_bitmap_data(); if ( marker ) { - dispatch_type dispatch(context, *marker, + dispatch_type dispatch(context_, *marker, *detector_, sym, bbox, tr, scale_factor_); vertex_converter, dispatch_type, markers_symbolizer, @@ -1861,21 +1200,21 @@ void cairo_renderer_base::process(text_symbolizer const& sym, scale_factor_, t_, font_manager_, *detector_, query_extent_); - cairo_context context(context_); - context.set_operator(sym.comp_op()); + cairo_save_restore guard(context_); + context_.set_operator(sym.comp_op()); while (helper.next()) { placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { - context.add_text(placements[ii], face_manager_, font_manager_, scale_factor_); + context_.add_text(placements[ii], face_manager_, font_manager_, scale_factor_); } } } -template class cairo_renderer; -template class cairo_renderer; +template class cairo_renderer; +template class cairo_renderer; } #endif // HAVE_CAIRO diff --git a/src/feature_style_processor.cpp b/src/feature_style_processor.cpp index fe0918871..9deb275ab 100644 --- a/src/feature_style_processor.cpp +++ b/src/feature_style_processor.cpp @@ -28,8 +28,7 @@ #include #if defined(HAVE_CAIRO) -#include -#include +#include #include #endif @@ -41,8 +40,8 @@ namespace mapnik { #if defined(HAVE_CAIRO) -template class feature_style_processor >; -template class feature_style_processor >; +template class feature_style_processor >; +template class feature_style_processor >; #endif #if defined(SVG_RENDERER) diff --git a/src/graphics.cpp b/src/graphics.cpp index 0a73eb47f..06dfce493 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -31,14 +31,14 @@ #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" -// cairo -#ifdef HAVE_CAIRO -#include -#endif - // boost #include +// cairo +#ifdef HAVE_CAIRO +#include +#endif + namespace mapnik { image_32::image_32(int width,int height) @@ -54,22 +54,22 @@ image_32::image_32(const image_32& rhs) painted_(rhs.painted_) {} #ifdef HAVE_CAIRO -image_32::image_32(Cairo::RefPtr rhs) - :width_(rhs->get_width()), - height_(rhs->get_height()), - data_(rhs->get_width(),rhs->get_height()) +image_32::image_32(cairo_surface_ptr const& surface) + :width_(cairo_image_surface_get_width(&*surface)), + height_(cairo_image_surface_get_height(&*surface)), + data_(width_, height_) { painted_ = true; - if (rhs->get_format() != Cairo::FORMAT_ARGB32) + if ( cairo_image_surface_get_format(&*surface) != CAIRO_FORMAT_ARGB32) { MAPNIK_LOG_WARN(graphics) << "Unable to convert this Cairo format"; - return; // throw exception ?? + throw; } - int stride = rhs->get_stride() / 4; + int stride = cairo_image_surface_get_stride(&*surface) / 4; boost::scoped_array out_row(new unsigned int[width_]); - const unsigned int *in_row = (const unsigned int *)rhs->get_data(); + const unsigned int *in_row = (const unsigned int *)cairo_image_surface_get_data(&*surface); for (unsigned int row = 0; row < height_; row++, in_row += stride) { @@ -142,42 +142,39 @@ void image_32::set_color_to_alpha(const color& c) void image_32::set_alpha(float opacity) { + for (unsigned int y = 0; y < height_; ++y) { - for (unsigned int y = 0; y < height_; ++y) + unsigned int* row_to = data_.getRow(y); + for (unsigned int x = 0; x < width_; ++x) { - unsigned int* row_to = data_.getRow(y); - for (unsigned int x = 0; x < width_; ++x) - { - unsigned rgba = row_to[x]; + unsigned rgba = row_to[x]; #ifdef MAPNIK_BIG_ENDIAN - unsigned a0 = (rgba & 0xff); - unsigned a1 = int( (rgba & 0xff) * opacity ); + unsigned a0 = (rgba & 0xff); + unsigned a1 = int( (rgba & 0xff) * opacity ); - if (a0 == a1) continue; + if (a0 == a1) continue; - unsigned r = (rgba >> 24) & 0xff; - unsigned g = (rgba >> 16 ) & 0xff; - unsigned b = (rgba >> 8) & 0xff; + unsigned r = (rgba >> 24) & 0xff; + unsigned g = (rgba >> 16 ) & 0xff; + unsigned b = (rgba >> 8) & 0xff; - row_to[x] = (a1) | (b << 8) | (g << 16) | (r << 24) ; + row_to[x] = (a1) | (b << 8) | (g << 16) | (r << 24) ; #else - unsigned a0 = (rgba >> 24) & 0xff; - unsigned a1 = int( ((rgba >> 24) & 0xff) * opacity ); - //unsigned a1 = opacity; - if (a0 == a1) continue; + unsigned a0 = (rgba >> 24) & 0xff; + unsigned a1 = int( ((rgba >> 24) & 0xff) * opacity ); + //unsigned a1 = opacity; + if (a0 == a1) continue; - unsigned r = rgba & 0xff; - unsigned g = (rgba >> 8 ) & 0xff; - unsigned b = (rgba >> 16) & 0xff; + unsigned r = rgba & 0xff; + unsigned g = (rgba >> 8 ) & 0xff; + unsigned b = (rgba >> 16) & 0xff; - row_to[x] = (a1 << 24)| (b << 16) | (g << 8) | (r) ; + row_to[x] = (a1 << 24)| (b << 16) | (g << 8) | (r) ; #endif - } } } - } void image_32::set_background(const color& c) @@ -211,7 +208,7 @@ void image_32::composite_pixel(unsigned op, int x,int y, unsigned c, unsigned co typedef color_type::value_type value_type; typedef agg::order_rgba order_type; typedef agg::comp_op_adaptor_rgba blender_type; - + if (checkBounds(x,y)) { unsigned rgba = data_(x,y); @@ -219,8 +216,8 @@ void image_32::composite_pixel(unsigned op, int x,int y, unsigned c, unsigned co unsigned cb = (c >> 16 ) & 0xff; unsigned cg = (c >> 8) & 0xff; unsigned cr = (c & 0xff); - blender_type::blend_pix(op, (value_type*)&rgba, cr, cg, cb, ca, cover); - data_(x,y) = rgba; + blender_type::blend_pix(op, (value_type*)&rgba, cr, cg, cb, ca, cover); + data_(x,y) = rgba; } } diff --git a/src/image_util.cpp b/src/image_util.cpp index 6b3c87df1..024ce13c4 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -43,7 +43,17 @@ extern "C" #ifdef HAVE_CAIRO #include -#include +#include +#ifdef CAIRO_HAS_PDF_SURFACE +#include +#endif // CAIRO_HAS_PDF_SURFACE +#ifdef CAIRO_HAS_PS_SURFACE +#include +#endif // CAIRO_HAS_PS_SURFACE +#ifdef CAIRO_HAS_SVG_SURFACE +#include +#endif // CAIRO_HAS_SVG_SURFACE + #endif // boost @@ -384,37 +394,37 @@ void save_to_cairo_file(mapnik::Map const& map, std::ofstream file (filename.c_str(), std::ios::out|std::ios::trunc|std::ios::binary); if (file) { - Cairo::RefPtr surface; + cairo_surface_ptr surface; unsigned width = map.width(); unsigned height = map.height(); if (type == "pdf") { -#if defined(CAIRO_HAS_PDF_SURFACE) - surface = Cairo::PdfSurface::create(filename,width,height); +#ifdef CAIRO_HAS_PDF_SURFACE + surface = cairo_surface_ptr(cairo_pdf_surface_create(filename.c_str(),width,height),cairo_surface_closer()); #else throw ImageWriterException("PDFSurface not supported in the cairo backend"); #endif } -#if defined(CAIRO_HAS_SVG_SURFACE) +#ifdef CAIRO_HAS_SVG_SURFACE else if (type == "svg") { - surface = Cairo::SvgSurface::create(filename,width,height); + surface = cairo_surface_ptr(cairo_svg_surface_create(filename.c_str(),width,height),cairo_surface_closer()); } #endif -#if defined(CAIRO_HAS_PS_SURFACE) +#ifdef CAIRO_HAS_PS_SURFACE else if (type == "ps") { - surface = Cairo::PsSurface::create(filename,width,height); + surface = cairo_surface_ptr(cairo_ps_surface_create(filename.c_str(),width,height),cairo_surface_closer()); } #endif -#if defined(CAIRO_HAS_IMAGE_SURFACE) +#ifdef CAIRO_HAS_IMAGE_SURFACE else if (type == "ARGB32") { - surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32,width,height); + surface = cairo_surface_ptr(cairo_image_surface_create(CAIRO_FORMAT_ARGB32,width,height),cairo_surface_closer()); } else if (type == "RGB24") { - surface = Cairo::ImageSurface::create(Cairo::FORMAT_RGB24,width,height); + surface = cairo_surface_ptr(cairo_image_surface_create(CAIRO_FORMAT_RGB24,width,height),cairo_surface_closer()); } #endif else @@ -422,7 +432,7 @@ void save_to_cairo_file(mapnik::Map const& map, throw ImageWriterException("unknown file type: " + type); } - Cairo::RefPtr context = Cairo::Context::create(surface); + //cairo_t * ctx = cairo_create(surface); // TODO - expose as user option /* @@ -432,15 +442,14 @@ void save_to_cairo_file(mapnik::Map const& map, } */ - - mapnik::cairo_renderer ren(map, context, scale_factor); + mapnik::cairo_renderer ren(map, create_context(surface), scale_factor); ren.apply(); if (type == "ARGB32" || type == "RGB24") { - surface->write_to_png(filename); + cairo_surface_write_to_png(&*surface, filename.c_str()); } - surface->finish(); + cairo_surface_finish(&*surface); } } diff --git a/src/params.cpp b/src/params.cpp index 74ef19fbb..964750dd8 100644 --- a/src/params.cpp +++ b/src/params.cpp @@ -36,48 +36,23 @@ namespace mapnik { namespace params_detail { - // TODO - rewrite to avoid usage of lexical_cast - template - struct value_extractor_visitor : public boost::static_visitor<> +template +struct converter +{ + typedef boost::optional return_type; + static return_type extract(parameters const& params, + std::string const& name, + boost::optional const& default_opt_value) { - value_extractor_visitor(boost::optional & var) - :var_(var) {} - - void operator () (T val) const + boost::optional result(default_opt_value); + parameters::const_iterator itr = params.find(name); + if (itr != params.end()) { - var_ = val; + boost::apply_visitor(value_extractor_visitor(result),itr->second); } - - template - void operator () (T1 val) const - { - try - { - var_ = boost::lexical_cast(val); - } - catch (boost::bad_lexical_cast & ) {} - } - - boost::optional & var_; - }; - - template - struct converter - { - typedef boost::optional return_type; - static return_type extract(parameters const& params, - std::string const& name, - boost::optional const& default_opt_value) - { - boost::optional result(default_opt_value); - parameters::const_iterator itr = params.find(name); - if (itr != params.end()) - { - boost::apply_visitor(value_extractor_visitor(result),itr->second); - } - return result; - } - }; + return result; + } +}; } // end namespace params_detail // parameters