This is an automated email from the git hooks/post-receive script. sebastic pushed a commit to branch master in repository mapnik.
commit f4e16e9c89f476958f042cd5499fb3074e97c113 Author: Bas Couwenberg <sebas...@xs4all.nl> Date: Sun Sep 20 11:57:30 2015 +0200 Imported Upstream version 3.0.5+ds --- .gitignore | 1 + CHANGELOG.md | 21 + benchmark/data/polygon_rendering_clip.xml | 2 +- benchmark/data/polygon_rendering_no_clip.xml | 2 +- benchmark/data/roads.xml | 2 +- benchmark/test_array_allocation.cpp | 29 +- benchmark/test_expression_parse.cpp | 2 +- benchmark/test_numeric_cast_vs_static_cast.cpp | 7 +- benchmark/test_offset_converter.cpp | 5 +- benchmark/test_polygon_clipping.cpp | 9 +- benchmark/test_polygon_clipping_rendering.cpp | 11 +- benchmark/test_proj_transform1.cpp | 10 +- benchmark/test_rendering.cpp | 5 +- benchmark/test_rendering_shared_map.cpp | 5 +- benchmark/test_utf_encoding.cpp | 8 +- include/mapnik/csv/csv_grammar.hpp | 2 +- include/mapnik/debug.hpp | 447 +++++++++++---------- include/mapnik/image.hpp | 31 +- include/mapnik/image_filter.hpp | 13 +- include/mapnik/image_filter_types.hpp | 15 +- include/mapnik/image_impl.hpp | 39 +- include/mapnik/json/topojson_grammar_impl.hpp | 2 +- include/mapnik/json/topojson_utils.hpp | 6 - include/mapnik/json/topology.hpp | 5 +- .../renderer_common/process_markers_symbolizer.hpp | 6 +- .../renderer_common/process_polygon_symbolizer.hpp | 2 +- include/mapnik/text/placement_finder.hpp | 2 +- include/mapnik/util/singleton.hpp | 4 +- include/mapnik/version.hpp | 3 +- plugins/input/csv/build.py | 79 ++-- plugins/input/csv/csv_datasource.cpp | 98 +++-- plugins/input/csv/csv_datasource.hpp | 4 +- plugins/input/csv/csv_featureset.cpp | 22 +- plugins/input/csv/csv_featureset.hpp | 14 +- plugins/input/csv/csv_utils.hpp | 8 +- plugins/input/topojson/topojson_datasource.cpp | 13 +- src/agg/process_line_pattern_symbolizer.cpp | 4 +- src/agg/process_polygon_pattern_symbolizer.cpp | 4 +- src/cairo/process_line_pattern_symbolizer.cpp | 2 +- src/cairo/process_polygon_pattern_symbolizer.cpp | 2 +- src/debug.cpp | 50 +-- src/grid/process_line_pattern_symbolizer.cpp | 2 +- src/grid/process_polygon_pattern_symbolizer.cpp | 2 +- src/image.cpp | 39 +- src/svg/svg_parser.cpp | 5 + src/text/placement_finder.cpp | 2 + src/text/symbolizer_helpers.cpp | 16 +- src/unicode.cpp | 2 +- test/standalone/csv_test.cpp | 1 + test/unit/imaging/image.cpp | 106 ++++- test/unit/imaging/image_filter.cpp | 92 ++++- test/unit/imaging/image_io_test.cpp | 5 + 52 files changed, 767 insertions(+), 501 deletions(-) diff --git a/.gitignore b/.gitignore index 9b10ae8..816bc0e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ *.a *.swp *.dylib +mapnik-gyp plugins/input/*.input plugins/input/templates/*.input demo/c++/rundemo diff --git a/CHANGELOG.md b/CHANGELOG.md index fb40544..538d4ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,27 @@ Released: YYYY XX, 2015 (Packaged from xxxx) +## 3.0.5 + +Released: September 16, 2015 + +(Packaged from 165c704) + +#### Summary + +- `scale-hsla` image filter: parameters are no longer limited by interval \[0, 1\] (https://github.com/mapnik/mapnik/pull/3054) +- Windows: Fixed SVG file loading from unicode paths +- `colorize-alpha` image filter: fixed normalization of color components (https://github.com/mapnik/mapnik/pull/3058) +- `colorize-alpha` image filter: added support for transparent colors (https://github.com/mapnik/mapnik/pull/3061) +- Enable reading optional `MAPNIK_LOG_FORMAT` environment variable(https://github.com/mapnik/mapnik/commit/6d1ffc8a93008b8c0a89d87d68b59afb2cb3757f) +- CSV.input uses memory mapped file by default on *nix. +- Updated bundled fonts to the latest version +- Topojson.input - fixed geometry_index logic which was causing missing features +- Fixed SVG file loading from unicode paths (https://github.com/mapnik/node-mapnik/issues/517) +- CSV.input - improved support for LF/CR/CRLF line endings on all platforms (https://github.com/mapnik/mapnik/issues/3065) +- Revive `zero allocation image interface` and add unit tests +- Benchmark: use return values of test runner. + ## 3.0.4 Released: August 26, 2015 diff --git a/benchmark/data/polygon_rendering_clip.xml b/benchmark/data/polygon_rendering_clip.xml index 98f0ec6..97847de 100644 --- a/benchmark/data/polygon_rendering_clip.xml +++ b/benchmark/data/polygon_rendering_clip.xml @@ -7,7 +7,7 @@ <Layer name="world" srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"> <StyleName>style</StyleName> <Datasource> - <Parameter name="file">../../tests/data/shp/world_merc.shp</Parameter> + <Parameter name="file">../../test/data/shp/world_merc.shp</Parameter> <Parameter name="type">shape</Parameter> </Datasource> </Layer> diff --git a/benchmark/data/polygon_rendering_no_clip.xml b/benchmark/data/polygon_rendering_no_clip.xml index 8d478e0..36570f1 100644 --- a/benchmark/data/polygon_rendering_no_clip.xml +++ b/benchmark/data/polygon_rendering_no_clip.xml @@ -7,7 +7,7 @@ <Layer name="world" srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"> <StyleName>style</StyleName> <Datasource> - <Parameter name="file">../../tests/data/shp/world_merc.shp</Parameter> + <Parameter name="file">../../test/data/shp/world_merc.shp</Parameter> <Parameter name="type">shape</Parameter> </Datasource> </Layer> diff --git a/benchmark/data/roads.xml b/benchmark/data/roads.xml index bc0ad52..0ca938f 100644 --- a/benchmark/data/roads.xml +++ b/benchmark/data/roads.xml @@ -2,7 +2,7 @@ <!DOCTYPE Map[]> <Map srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over" - font-directory="../../fonts/dejavu-fonts-ttf-2.34/ttf/DejaVuSans.ttf" + font-directory="../../fonts/dejavu-fonts-ttf-2.35/ttf/DejaVuSans.ttf" background-color="#dfd8c9"> <Style name="marking" filter-mode="first"> diff --git a/benchmark/test_array_allocation.cpp b/benchmark/test_array_allocation.cpp index 05da7ae..fda9bb6 100644 --- a/benchmark/test_array_allocation.cpp +++ b/benchmark/test_array_allocation.cpp @@ -386,61 +386,62 @@ public: int main(int argc, char** argv) { + int return_value = 0; mapnik::parameters params; benchmark::handle_args(argc,argv,params); { test4 test_runner4(params); - run(test_runner4,"calloc"); + return_value = return_value | run(test_runner4,"calloc"); } { test1 test_runner(params); - run(test_runner,"malloc/memcpy"); + return_value = return_value | run(test_runner,"malloc/memcpy"); } { test1b test_runner(params); - run(test_runner,"malloc/memset"); + return_value = return_value | run(test_runner,"malloc/memset"); } { test1c test_runner(params); - run(test_runner,"operator new/std::fill"); + return_value = return_value | run(test_runner,"operator new/std::fill"); } { test2 test_runner(params); - run(test_runner,"operator new/memcpy"); + return_value = return_value | run(test_runner,"operator new/memcpy"); } { test3 test_runner(params); - run(test_runner,"vector(N)"); + return_value = return_value | run(test_runner,"vector(N)"); } { test3b test_runner(params); - run(test_runner,"vector/resize"); + return_value = return_value | run(test_runner,"vector/resize"); } { test3c test_runner(params); - run(test_runner,"vector/assign"); + return_value = return_value | run(test_runner,"vector/assign"); } { test3d test_runner(params); - run(test_runner,"deque(N)"); + return_value = return_value | run(test_runner,"deque(N)"); } { test5 test_runner(params); - run(test_runner,"std::string range"); + return_value = return_value | run(test_runner,"std::string range"); } { test5b test_runner(params); - run(test_runner,"std::string &[0]"); + return_value = return_value | run(test_runner,"std::string &[0]"); } { test6 test_runner(params); - run(test_runner,"valarray"); + return_value = return_value | run(test_runner,"valarray"); } #if BOOST_VERSION >= 105400 { test7 test_runner(params); - run(test_runner,"static_vector"); + return_value = return_value | run(test_runner,"static_vector"); } #endif - return 0; + return return_value; } diff --git a/benchmark/test_expression_parse.cpp b/benchmark/test_expression_parse.cpp index 704a69c..7e39922 100644 --- a/benchmark/test_expression_parse.cpp +++ b/benchmark/test_expression_parse.cpp @@ -37,5 +37,5 @@ int main(int argc, char** argv) mapnik::parameters params; benchmark::handle_args(argc,argv,params); test test_runner(params); - run(test_runner,"expr parsing"); + return run(test_runner,"expr parsing"); } diff --git a/benchmark/test_numeric_cast_vs_static_cast.cpp b/benchmark/test_numeric_cast_vs_static_cast.cpp index 52865ac..8ea6e6b 100644 --- a/benchmark/test_numeric_cast_vs_static_cast.cpp +++ b/benchmark/test_numeric_cast_vs_static_cast.cpp @@ -75,13 +75,14 @@ int main(int argc, char** argv) { mapnik::parameters params; benchmark::handle_args(argc,argv,params); + int return_value = 0; { test_static test_runner(params); - run(test_runner,"static_cast"); + return_value = return_value | run(test_runner,"static_cast"); } { test_numeric test_runner(params); - run(test_runner,"numeric_cast"); + return_value = return_value | run(test_runner,"numeric_cast"); } - return 0; + return return_value; } diff --git a/benchmark/test_offset_converter.cpp b/benchmark/test_offset_converter.cpp index 4bd3175..c0d25da 100644 --- a/benchmark/test_offset_converter.cpp +++ b/benchmark/test_offset_converter.cpp @@ -93,9 +93,10 @@ int main(int argc, char** argv) { mapnik::parameters params; benchmark::handle_args(argc,argv,params); + int return_value = 0; { test_offset test_runner(params); - run(test_runner,"offset_test"); + return_value = run(test_runner,"offset_test"); } - return 0; + return return_value; } diff --git a/benchmark/test_polygon_clipping.cpp b/benchmark/test_polygon_clipping.cpp index 0005fc9..b189a04 100644 --- a/benchmark/test_polygon_clipping.cpp +++ b/benchmark/test_polygon_clipping.cpp @@ -528,19 +528,20 @@ int main(int argc, char** argv) throw std::runtime_error("could not open: '" + filename_ + "'"); std::string wkt_in( (std::istreambuf_iterator<char>(in) ), (std::istreambuf_iterator<char>()) ); + int return_value = 0; { test1 test_runner(params,wkt_in,clipping_box); - run(test_runner,"clipping polygon with agg"); + return_value = return_value | run(test_runner,"clipping polygon with agg"); } { test3 test_runner(params,wkt_in,clipping_box); - run(test_runner,"clipping polygon with boost"); + return_value = return_value | run(test_runner,"clipping polygon with boost"); } /* { test4 test_runner(params,wkt_in,clipping_box); - run(test_runner,"clipping polygon with clipper_tree"); + return_value = return_value | run(test_runner,"clipping polygon with clipper_tree"); } */ - return 0; + return return_value; } diff --git a/benchmark/test_polygon_clipping_rendering.cpp b/benchmark/test_polygon_clipping_rendering.cpp index 88f20d5..ab23459 100644 --- a/benchmark/test_polygon_clipping_rendering.cpp +++ b/benchmark/test_polygon_clipping_rendering.cpp @@ -51,29 +51,30 @@ int main(int argc, char** argv) mapnik::box2d<double> z1(-20037508.3428,-8317435.0606,20037508.3428,18399242.7298); // bbox for 16/10491/22911.png mapnik::box2d<double> z16(-13622912.929097254,6026906.8062295765,-13621689.93664469,6028129.79868214); + int return_value = 0; { test test_runner(params, "benchmark/data/polygon_rendering_clip.xml", z1); - run(test_runner,"polygon clip render z1"); + return_value = return_value | run(test_runner,"polygon clip render z1"); } { test test_runner(params, "benchmark/data/polygon_rendering_no_clip.xml", z1); - run(test_runner,"polygon noclip render z1"); + return_value = return_value | run(test_runner,"polygon noclip render z1"); } { test test_runner(params, "benchmark/data/polygon_rendering_clip.xml", z16); - run(test_runner,"polygon clip render z16"); + return_value = return_value | run(test_runner,"polygon clip render z16"); } { test test_runner(params, "benchmark/data/polygon_rendering_no_clip.xml", z16); - run(test_runner,"polygon noclip render z16"); + return_value = return_value | run(test_runner,"polygon noclip render z16"); } - return 0; + return return_value; } diff --git a/benchmark/test_proj_transform1.cpp b/benchmark/test_proj_transform1.cpp index b98a497..451c51a 100644 --- a/benchmark/test_proj_transform1.cpp +++ b/benchmark/test_proj_transform1.cpp @@ -67,32 +67,34 @@ int main(int argc, char** argv) std::string to_str("+init=epsg:3857"); std::string from_str2("+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs"); std::string to_str2("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0.0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs +over"); + int return_value = 0; test test_runner(params, from_str, to_str, from, to, true); - run(test_runner,"lonlat->merc epsg"); + return_value = return_value | run(test_runner,"lonlat->merc epsg"); test test_runner2(params, from_str2, to_str2, from, to, true); - run(test_runner2,"lonlat->merc literal"); + return_value = return_value | run(test_runner2,"lonlat->merc literal"); test test_runner3(params, to_str, from_str, to, from, true); - run(test_runner3,"merc->lonlat epsg"); + return_value = return_value | run(test_runner3,"merc->lonlat epsg"); test test_runner4(params, to_str2, from_str2, to, from, true); - return run(test_runner4,"merc->lonlat literal"); + return_value = return_value | run(test_runner4,"merc->lonlat literal"); + return return_value; } diff --git a/benchmark/test_rendering.cpp b/benchmark/test_rendering.cpp index 30e80be..593307b 100644 --- a/benchmark/test_rendering.cpp +++ b/benchmark/test_rendering.cpp @@ -88,6 +88,7 @@ public: int main(int argc, char** argv) { + int return_value = 0; try { mapnik::parameters params; @@ -102,7 +103,7 @@ int main(int argc, char** argv) mapnik::datasource_cache::instance().register_datasources("./plugins/input/"); { test test_runner(params); - run(test_runner,*name); + return_value = run(test_runner,*name); } } catch (std::exception const& ex) @@ -110,5 +111,5 @@ int main(int argc, char** argv) std::clog << ex.what() << "\n"; return -1; } - return 0; + return return_value; } diff --git a/benchmark/test_rendering_shared_map.cpp b/benchmark/test_rendering_shared_map.cpp index 0b57053..75631f7 100644 --- a/benchmark/test_rendering_shared_map.cpp +++ b/benchmark/test_rendering_shared_map.cpp @@ -145,6 +145,7 @@ public: int main(int argc, char** argv) { + int return_value = 0; try { mapnik::parameters params; @@ -159,7 +160,7 @@ int main(int argc, char** argv) mapnik::datasource_cache::instance().register_datasources("./plugins/input/"); { test test_runner(params); - run(test_runner,*name); + return_value = run(test_runner,*name); } } catch (std::exception const& ex) @@ -167,5 +168,5 @@ int main(int argc, char** argv) std::clog << ex.what() << "\n"; return -1; } - return 0; + return return_value; } diff --git a/benchmark/test_utf_encoding.cpp b/benchmark/test_utf_encoding.cpp index 100cbd6..a4ba10a 100644 --- a/benchmark/test_utf_encoding.cpp +++ b/benchmark/test_utf_encoding.cpp @@ -97,14 +97,16 @@ int main(int argc, char** argv) { mapnik::parameters params; benchmark::handle_args(argc,argv,params); + int return_value = 0; #ifndef __linux__ test test_runner(params); - run(test_runner,"utf encode std::codecvt"); + return_value = return_value | run(test_runner,"utf encode std::codecvt"); #else std::clog << "skipping 'utf encode std::codecvt' test since <codecvt> is not supported on __linux__\n"; #endif test2 test_runner2(params); - run(test_runner2,"utf encode boost::locale"); + return_value = return_value | run(test_runner2,"utf encode boost::locale"); test3 test_runner3(params); - return run(test_runner3,"utf encode ICU"); + return_value = return_value | run(test_runner3,"utf encode ICU"); + return return_value; } diff --git a/include/mapnik/csv/csv_grammar.hpp b/include/mapnik/csv/csv_grammar.hpp index 195542b..2bd0f52 100644 --- a/include/mapnik/csv/csv_grammar.hpp +++ b/include/mapnik/csv/csv_grammar.hpp @@ -64,7 +64,7 @@ struct csv_line_grammar : qi::grammar<Iterator, csv_line(std::string const&), qi line = column(_r1) % char_(_r1) ; - column = quoted | *(char_ - (lit(_r1) /*| eol*/)) + column = -omit[char_("\n\r")] >> quoted | *(char_ - (lit(_r1) /*| eol*/)) ; quoted = omit[char_("\"'")[_a = _1]] > text(_a) > -lit(_a) ; diff --git a/include/mapnik/debug.hpp b/include/mapnik/debug.hpp index aaccb4f..cf5e5b9 100644 --- a/include/mapnik/debug.hpp +++ b/include/mapnik/debug.hpp @@ -37,293 +37,294 @@ #include <unordered_map> #ifdef MAPNIK_THREADSAFE #include <mutex> +#include <atomic> #endif namespace mapnik { - /* - Global logger class that holds the configuration of severity, format - and file/console redirection. - */ - class MAPNIK_DECL logger : + +// Global logger class that holds the configuration of severity, format +// and file/console redirection. + +class MAPNIK_DECL logger : public singleton<logger,CreateStatic>, private util::noncopyable +{ +public: + enum severity_type { - public: - enum severity_type - { - debug = 0, - warn = 1, - error = 2, - none = 3 - }; + debug = 0, + warn = 1, + error = 2, + none = 3 + }; - using severity_map = std::unordered_map<std::string, severity_type>; + using severity_map = std::unordered_map<std::string, severity_type>; - // global security level - static severity_type get_severity() - { - return severity_level_; - } + // global security level + static severity_type get_severity() + { + return severity_level_; + } - static void set_severity(severity_type const& severity_level) + static void set_severity(severity_type severity_level) + { +//#ifdef MAPNIK_THREADSAFE +// std::lock_guard<std::mutex> lock(severity_mutex_); +//#endif + severity_level_ = severity_level; + } + + // per object security levels + static severity_type get_object_severity(std::string const& object_name) + { + severity_map::iterator it = object_severity_level_.find(object_name); + if (object_name.empty() || it == object_severity_level_.end()) { -#ifdef MAPNIK_THREADSAFE - std::lock_guard<std::mutex> lock(severity_mutex_); -#endif - - severity_level_ = severity_level; + return severity_level_; } - - // per object security levels - static severity_type get_object_severity(std::string const& object_name) + else { - severity_map::iterator it = object_severity_level_.find(object_name); - if (object_name.empty() || it == object_severity_level_.end()) - { - return severity_level_; - } - else - { - return it->second; - } + return it->second; } + } - static void set_object_severity(std::string const& object_name, - severity_type const& security_level) + static void set_object_severity(std::string const& object_name, + severity_type const& security_level) + { + if (!object_name.empty()) { #ifdef MAPNIK_THREADSAFE std::lock_guard<std::mutex> lock(severity_mutex_); #endif - if (! object_name.empty()) - { - object_severity_level_[object_name] = security_level; - } + object_severity_level_[object_name] = security_level; } + } - static void clear_object_severity() - { + static void clear_object_severity() + { #ifdef MAPNIK_THREADSAFE - std::lock_guard<std::mutex> lock(severity_mutex_); + std::lock_guard<std::mutex> lock(severity_mutex_); #endif - object_severity_level_.clear(); - } + object_severity_level_.clear(); + } - // format - static std::string get_format() - { - return format_; - } + // format + static std::string const& get_format() + { + return format_; + } - static void set_format(std::string const& format) - { + static void set_format(std::string const& format) + { #ifdef MAPNIK_THREADSAFE - std::lock_guard<std::mutex> lock(format_mutex_); + std::lock_guard<std::mutex> lock(format_mutex_); #endif - format_ = format; - } + format_ = format; + } - // interpolate the format string for output - static std::string str(); + // interpolate the format string for output + static std::string str(); - // output - static void use_file(std::string const& filepath); - static void use_console(); + // output + static void use_file(std::string const& filepath); + static void use_console(); - private: - static severity_type severity_level_; - static severity_map object_severity_level_; - static bool severity_env_check_; - - static std::string format_; - static bool format_env_check_; - - static std::ofstream file_output_; - static std::string file_name_; - static std::streambuf* saved_buf_; +private: + static severity_map object_severity_level_; + static std::string format_; + static std::ofstream file_output_; + static std::string file_name_; + static std::streambuf* saved_buf_; #ifdef MAPNIK_THREADSAFE - static std::mutex severity_mutex_; - static std::mutex format_mutex_; + static std::atomic<severity_type> severity_level_; + static std::atomic<bool> severity_env_check_; + static std::atomic<bool> format_env_check_; + static std::mutex severity_mutex_; + static std::mutex format_mutex_; +#else + static severity_type severity_level_; + static bool severity_env_check_; + static bool format_env_check_; #endif - }; +}; - namespace detail { +namespace detail { - /* - Default sink, it regulates access to clog - */ - template<class Ch, class Tr, class A> - class clog_sink - { - public: - using stream_buffer = std::basic_ostringstream<Ch, Tr, A>; +// Default sink, it regulates access to clog - void operator()(logger::severity_type const& /*severity*/, stream_buffer const& s) - { +template<class Ch, class Tr, class A> +class clog_sink +{ +public: + using stream_buffer = std::basic_ostringstream<Ch, Tr, A>; + + void operator()(logger::severity_type const& /*severity*/, stream_buffer const& s) + { #ifdef MAPNIK_THREADSAFE - static std::mutex mutex; - std::lock_guard<std::mutex> lock(mutex); + static std::mutex mutex; + std::lock_guard<std::mutex> lock(mutex); #endif - std::clog << logger::str() << " " << s.str() << std::endl; - } - }; - - - /* - Base log class, should not log anything when no MAPNIK_LOG is defined - - This is used for debug/warn reporting that should not output - anything when not compiling for speed. - */ - template<template <class Ch, class Tr, class A> class OutputPolicy, - logger::severity_type Severity, - class Ch = char, - class Tr = std::char_traits<Ch>, - class A = std::allocator<Ch> > - class base_log : public util::noncopyable - { - public: - using output_policy = OutputPolicy<Ch, Tr, A>; - - base_log() {} + std::clog << logger::str() << " " << s.str() << std::endl; + } +}; + +// Base log class, should not log anything when no MAPNIK_LOG is defined +// +// This is used for debug/warn reporting that should not output +// anything when not compiling for speed. + +template<template <class Ch, class Tr, class A> class OutputPolicy, + logger::severity_type Severity, + class Ch = char, + class Tr = std::char_traits<Ch>, + class A = std::allocator<Ch> > +class base_log : public util::noncopyable +{ +public: + using output_policy = OutputPolicy<Ch, Tr, A>; + + base_log() {} #ifdef MAPNIK_LOG - base_log(const char* object_name) - { - if (object_name != nullptr) - { - object_name_ = object_name; - } - } + base_log(const char* object_name) + { + if (object_name != nullptr) + { + object_name_ = object_name; + } + } #else - base_log(const char* /*object_name*/) - { - } + base_log(const char* /*object_name*/) + { + } #endif - ~base_log() - { + ~base_log() + { #ifdef MAPNIK_LOG - if (check_severity()) - { - output_policy()(Severity, streambuf_); - } + if (check_severity()) + { + output_policy()(Severity, streambuf_); + } #endif - } + } - template<class T> + template<class T> #ifdef MAPNIK_LOG - base_log &operator<<(T const& x) - { + base_log &operator<<(T const& x) + { - streambuf_ << x; - return *this; - } + streambuf_ << x; + return *this; + } #else - base_log &operator<<(T const& /*x*/) - { + base_log &operator<<(T const& /*x*/) + { - return *this; - } + return *this; + } #endif - private: +private: #ifdef MAPNIK_LOG - inline bool check_severity() - { - return Severity >= logger::get_object_severity(object_name_); - } + inline bool check_severity() + { + return Severity >= logger::get_object_severity(object_name_); + } - typename output_policy::stream_buffer streambuf_; - std::string object_name_; + typename output_policy::stream_buffer streambuf_; + std::string object_name_; #endif - }; +}; + + + +//Base log class that always log, regardless of MAPNIK_LOG. +//This is used for error reporting that should always log something +template<template <class Ch, class Tr, class A> class OutputPolicy, + logger::severity_type Severity, + class Ch = char, + class Tr = std::char_traits<Ch>, + class A = std::allocator<Ch> > +class base_log_always : public util::noncopyable +{ +public: + using output_policy = OutputPolicy<Ch, Tr, A>; - /* - Base log class that always log, regardless of MAPNIK_LOG. + base_log_always() {} - This is used for error reporting that should always log something - */ - template<template <class Ch, class Tr, class A> class OutputPolicy, - logger::severity_type Severity, - class Ch = char, - class Tr = std::char_traits<Ch>, - class A = std::allocator<Ch> > - class base_log_always : public util::noncopyable + base_log_always(const char* object_name) + { + if (object_name != nullptr) { - public: - using output_policy = OutputPolicy<Ch, Tr, A>; - - base_log_always() {} - - base_log_always(const char* object_name) - { - if (object_name != nullptr) - { - object_name_ = object_name; - } - } - - ~base_log_always() - { - if (check_severity()) - { - output_policy()(Severity, streambuf_); - } - } - - template<class T> - base_log_always &operator<<(T const& x) - { - streambuf_ << x; - return *this; - } - - private: - inline bool check_severity() - { - return Severity >= logger::get_object_severity(object_name_); - } - - typename output_policy::stream_buffer streambuf_; - std::string object_name_; - }; - - - using base_log_debug = base_log<clog_sink, logger::debug>; - using base_log_warn = base_log<clog_sink, logger::warn>; - using base_log_error = base_log_always<clog_sink, logger::error>; - - } // namespace detail - - - // real interfaces - class MAPNIK_DECL warn : public detail::base_log_warn { - public: - warn() : detail::base_log_warn() {} - warn(const char* object_name) : detail::base_log_warn(object_name) {} - }; + object_name_ = object_name; + } + } - class MAPNIK_DECL debug : public detail::base_log_debug { - public: - debug() : detail::base_log_debug() {} - debug(const char* object_name) : detail::base_log_debug(object_name) {} - }; + ~base_log_always() + { + if (check_severity()) + { + output_policy()(Severity, streambuf_); + } + } - class MAPNIK_DECL error : public detail::base_log_error { - public: - error() : detail::base_log_error() {} - error(const char* object_name) : detail::base_log_error(object_name) {} - }; + template<class T> + base_log_always &operator<<(T const& x) + { + streambuf_ << x; + return *this; + } - // logging helpers - #define MAPNIK_LOG_DEBUG(s) mapnik::debug(#s) - #define MAPNIK_LOG_WARN(s) mapnik::warn(#s) - #define MAPNIK_LOG_ERROR(s) mapnik::error(#s) +private: + inline bool check_severity() + { + return Severity >= logger::get_object_severity(object_name_); + } + + typename output_policy::stream_buffer streambuf_; + std::string object_name_; +}; + + +using base_log_debug = base_log<clog_sink, logger::debug>; +using base_log_warn = base_log<clog_sink, logger::warn>; +using base_log_error = base_log_always<clog_sink, logger::error>; + +} // namespace detail + + +// real interfaces +class MAPNIK_DECL warn : public detail::base_log_warn +{ +public: + warn() : detail::base_log_warn() {} + warn(const char* object_name) : detail::base_log_warn(object_name) {} +}; + +class MAPNIK_DECL debug : public detail::base_log_debug +{ +public: + debug() : detail::base_log_debug() {} + debug(const char* object_name) : detail::base_log_debug(object_name) {} +}; + +class MAPNIK_DECL error : public detail::base_log_error +{ +public: + error() : detail::base_log_error() {} + error(const char* object_name) : detail::base_log_error(object_name) {} +}; + +// logging helpers +#define MAPNIK_LOG_DEBUG(s) mapnik::debug(#s) +#define MAPNIK_LOG_WARN(s) mapnik::warn(#s) +#define MAPNIK_LOG_ERROR(s) mapnik::error(#s) } #endif // MAPNIK_DEBUG_HPP diff --git a/include/mapnik/image.hpp b/include/mapnik/image.hpp index ec8b1f8..9ebdfc3 100644 --- a/include/mapnik/image.hpp +++ b/include/mapnik/image.hpp @@ -34,24 +34,20 @@ namespace detail { struct MAPNIK_DECL buffer { explicit buffer(std::size_t size); + explicit buffer(unsigned char* data, std::size_t size); buffer(buffer && rhs) noexcept; buffer(buffer const& rhs); ~buffer(); - buffer& operator=(buffer rhs); - inline bool operator!() const - { - return (data_ == nullptr)? true : false; - } - - void swap(buffer & rhs); - unsigned char* data(); - unsigned char const* data() const; - std::size_t size() const; + inline bool operator!() const {return (data_ == nullptr)? true : false;} + inline unsigned char* data() {return data_;} + inline unsigned char const* data() const {return data_;} + inline std::size_t size() const {return size_;} private: + void swap(buffer & rhs); std::size_t size_; unsigned char* data_; - + bool owns_; }; template <std::size_t max_size> @@ -76,6 +72,8 @@ class image public: using pixel = T; using pixel_type = typename T::type; + using iterator = pixel_type*; + using const_iterator = pixel_type const*; static constexpr image_dtype dtype = T::id; static constexpr std::size_t pixel_size = sizeof(pixel_type); private: @@ -93,6 +91,11 @@ public: bool initialize = true, bool premultiplied = false, bool painted = false); + image(int width, + int height, + unsigned char* data, + bool premultiplied = false, + bool painted = false); image(image<T> const& rhs); image(image<T> && rhs) noexcept; image<T>& operator=(image<T> rhs); @@ -109,6 +112,12 @@ public: void set(pixel_type const& t); pixel_type const* data() const; pixel_type* data(); + // simple iterator inteface + const_iterator begin() const; + const_iterator end() const; + iterator begin(); + iterator end(); + // unsigned char const* bytes() const; unsigned char* bytes(); pixel_type const* get_row(std::size_t row) const; diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp index d6ed0cd..3b188a3 100644 --- a/include/mapnik/image_filter.hpp +++ b/include/mapnik/image_filter.hpp @@ -505,6 +505,7 @@ void apply_filter(Src & src, colorize_alpha const& op) uint8_t & a = get_color(src_it[x], alpha_t()); if ( a > 0) { + a = (c.alpha() * a + 255) >> 8; r = (c.red() * a + 255) >> 8; g = (c.green() * a + 255) >> 8; b = (c.blue() * a + 255) >> 8; @@ -528,10 +529,10 @@ void apply_filter(Src & src, colorize_alpha const& op) { stop_offset = offset; } - grad_lut.add_color(stop_offset, agg::rgba(c.red()/256.0, - c.green()/256.0, - c.blue()/256.0, - c.alpha()/256.0)); + grad_lut.add_color(stop_offset, agg::rgba(c.red()/255.0, + c.green()/255.0, + c.blue()/255.0, + c.alpha()/255.0)); offset += step; } if (grad_lut.build_lut()) @@ -549,12 +550,10 @@ void apply_filter(Src & src, colorize_alpha const& op) if ( a > 0) { agg::rgba8 c = grad_lut[a]; + a = (c.a * a + 255) >> 8; r = (c.r * a + 255) >> 8; g = (c.g * a + 255) >> 8; b = (c.b * a + 255) >> 8; - if (r>a) r=a; - if (g>a) g=a; - if (b>a) b=a; #if 0 // rainbow r = 0; diff --git a/include/mapnik/image_filter_types.hpp b/include/mapnik/image_filter_types.hpp index 67e03da..7e04df8 100644 --- a/include/mapnik/image_filter_types.hpp +++ b/include/mapnik/image_filter_types.hpp @@ -116,19 +116,8 @@ struct scale_hsla : image_filter_base l0(_l0), l1(_l1), a0(_a0), - a1(_a1) { - if (h0 < 0 || h0 > 1 || - h1 < 0 || h1 > 1 || - s0 < 0 || s0 > 1 || - s1 < 0 || s1 > 1 || - l0 < 0 || l0 > 1 || - l1 < 0 || l1 > 1 || - a0 < 0 || a0 > 1 || - a1 < 0 || a1 > 1) - { - throw std::runtime_error("scale-hsla values must be between 0 and 1"); - } - } + a1(_a1) { } + inline bool is_identity() const { return (h0 == 0 && h1 == 1 && diff --git a/include/mapnik/image_impl.hpp b/include/mapnik/image_impl.hpp index 5a84f9e..732e7eb 100644 --- a/include/mapnik/image_impl.hpp +++ b/include/mapnik/image_impl.hpp @@ -78,6 +78,16 @@ image<T>::image() {} template <typename T> +image<T>::image(int width, int height, unsigned char* data, bool premultiplied, bool painted) + : dimensions_(width, height), + buffer_(data, width * height * sizeof(pixel_size)), + pData_(reinterpret_cast<pixel_type*>(buffer_.data())), + offset_(0.0), + scaling_(1.0), + premultiplied_alpha_(premultiplied), + painted_(painted) {} + +template <typename T> image<T>::image(int width, int height, bool initialize, bool premultiplied, bool painted) : dimensions_(width, height), buffer_(dimensions_.width() * dimensions_.height() * pixel_size), @@ -101,18 +111,17 @@ image<T>::image(image<T> const& rhs) offset_(rhs.offset_), scaling_(rhs.scaling_), premultiplied_alpha_(rhs.premultiplied_alpha_), - painted_(rhs.painted_) -{} + painted_(rhs.painted_) {} template <typename T> image<T>::image(image<T> && rhs) noexcept : dimensions_(std::move(rhs.dimensions_)), - buffer_(std::move(rhs.buffer_)), - pData_(reinterpret_cast<pixel_type*>(buffer_.data())), - offset_(rhs.offset_), - scaling_(rhs.scaling_), - premultiplied_alpha_(rhs.premultiplied_alpha_), - painted_(rhs.painted_) + buffer_(std::move(rhs.buffer_)), + pData_(reinterpret_cast<pixel_type*>(buffer_.data())), + offset_(rhs.offset_), + scaling_(rhs.scaling_), + premultiplied_alpha_(rhs.premultiplied_alpha_), + painted_(rhs.painted_) { rhs.dimensions_ = { 0, 0 }; rhs.pData_ = nullptr; @@ -216,6 +225,20 @@ inline unsigned char* image<T>::bytes() return buffer_.data(); } +// iterator interface +template <typename T> +inline typename image<T>::iterator image<T>::begin() { return pData_; } + +template <typename T> +inline typename image<T>::iterator image<T>::end() { return pData_ + dimensions_.width() * dimensions_.height(); } + +template <typename T> +inline typename image<T>::const_iterator image<T>::begin() const { return pData_; } + +template <typename T> +inline typename image<T>::const_iterator image<T>::end() const{ return pData_ + dimensions_.width() * dimensions_.height(); } + + template <typename T> inline typename image<T>::pixel_type const* image<T>::get_row(std::size_t row) const { diff --git a/include/mapnik/json/topojson_grammar_impl.hpp b/include/mapnik/json/topojson_grammar_impl.hpp index f20fbf9..90e3f1a 100644 --- a/include/mapnik/json/topojson_grammar_impl.hpp +++ b/include/mapnik/json/topojson_grammar_impl.hpp @@ -73,7 +73,7 @@ topojson_grammar<Iterator, ErrorHandler>::topojson_grammar() // topo json topology = lit('{') >> lit("\"type\"") >> lit(':') >> lit("\"Topology\"") - >> ( (lit(',') >> objects) ^ ( lit(',') >> arcs) ^ (lit(',') >> transform) ^ (lit(',') >> bbox)) + >> ( (lit(',') >> objects ) ^ ( lit(',') >> arcs) ^ (lit(',') >> transform) ^ (lit(',') >> bbox)) >> lit('}') ; diff --git a/include/mapnik/json/topojson_utils.hpp b/include/mapnik/json/topojson_utils.hpp index 5558bde..be6a83a 100644 --- a/include/mapnik/json/topojson_utils.hpp +++ b/include/mapnik/json/topojson_utils.hpp @@ -238,12 +238,6 @@ struct bounding_box_visitor } return bbox; } - - box2d<double> operator() (mapnik::topojson::invalid const&) const - { - return box2d<double>(); - } - private: topology const& topo_; std::size_t num_arcs_; diff --git a/include/mapnik/json/topology.hpp b/include/mapnik/json/topology.hpp index 3cfc2d3..48453df 100644 --- a/include/mapnik/json/topology.hpp +++ b/include/mapnik/json/topology.hpp @@ -86,10 +86,7 @@ struct multi_polygon boost::optional<properties> props; }; -struct invalid {}; - -using geometry = util::variant<invalid, - point, +using geometry = util::variant<point, linestring, polygon, multi_point, diff --git a/include/mapnik/renderer_common/process_markers_symbolizer.hpp b/include/mapnik/renderer_common/process_markers_symbolizer.hpp index 16e18ec..f67715b 100644 --- a/include/mapnik/renderer_common/process_markers_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_markers_symbolizer.hpp @@ -115,7 +115,7 @@ struct render_marker_symbolizer_visitor feature_, common_.vars_, common_.scale_factor_); - if (clip) // optional clip (default: true) + if (clip) { geometry::geometry_types type = geometry::geometry_type(feature_.get_geometry()); if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon) @@ -161,7 +161,7 @@ struct render_marker_symbolizer_visitor feature_, common_.vars_, common_.scale_factor_); - if (clip) // optional clip (default: true) + if (clip) { geometry::geometry_types type = geometry::geometry_type(feature_.get_geometry()); if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon) @@ -220,7 +220,7 @@ struct render_marker_symbolizer_visitor common_.vars_, common_.scale_factor_); - if (clip) // optional clip (default: true) + if (clip) { geometry::geometry_types type = geometry::geometry_type(feature_.get_geometry()); if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon) diff --git a/include/mapnik/renderer_common/process_polygon_symbolizer.hpp b/include/mapnik/renderer_common/process_polygon_symbolizer.hpp index 99f1243..6fd2524 100644 --- a/include/mapnik/renderer_common/process_polygon_symbolizer.hpp +++ b/include/mapnik/renderer_common/process_polygon_symbolizer.hpp @@ -54,7 +54,7 @@ void render_polygon_symbolizer(polygon_symbolizer const &sym, vertex_converter_type converter(clip_box, sym, common.t_, prj_trans, tr, feature,common.vars_,common.scale_factor_); - if (prj_trans.equal() && clip) converter.template set<clip_poly_tag>(); //optional clip (default: true) + if (prj_trans.equal() && clip) converter.template set<clip_poly_tag>(); converter.template set<transform_tag>(); //always transform converter.template set<affine_transform_tag>(); if (simplify_tolerance > 0.0) converter.template set<simplify_tag>(); // optional simplify converter diff --git a/include/mapnik/text/placement_finder.hpp b/include/mapnik/text/placement_finder.hpp index 8bb63a7..f35a5d5 100644 --- a/include/mapnik/text/placement_finder.hpp +++ b/include/mapnik/text/placement_finder.hpp @@ -91,7 +91,7 @@ private: face_manager_freetype &font_manager_; placements_list placements_; - + std::vector<text_layout_ptr> processed_layouts_; //ShieldSymbolizer bool has_marker_; marker_info_ptr marker_; diff --git a/include/mapnik/util/singleton.hpp b/include/mapnik/util/singleton.hpp index e77b25b..94f8bf1 100644 --- a/include/mapnik/util/singleton.hpp +++ b/include/mapnik/util/singleton.hpp @@ -80,7 +80,7 @@ template <typename T, #endif friend class CreatePolicy<T>; static std::atomic<T*> pInstance_; - static bool destroyed_; + static std::atomic<bool> destroyed_; singleton(const singleton &rhs); singleton& operator=(const singleton&); @@ -135,7 +135,7 @@ template <typename T, template <typename T, template <typename U> class CreatePolicy> std::atomic<T*> singleton<T,CreatePolicy>::pInstance_; template <typename T, - template <typename U> class CreatePolicy> bool singleton<T,CreatePolicy>::destroyed_ = false; + template <typename U> class CreatePolicy> std::atomic<bool> singleton<T,CreatePolicy>::destroyed_(false); } #endif // MAPNIK_UTIL_SINGLETON_HPP diff --git a/include/mapnik/version.hpp b/include/mapnik/version.hpp index 642932b..161b708 100644 --- a/include/mapnik/version.hpp +++ b/include/mapnik/version.hpp @@ -27,9 +27,8 @@ #define MAPNIK_MAJOR_VERSION 3 #define MAPNIK_MINOR_VERSION 0 -#define MAPNIK_PATCH_VERSION 4 +#define MAPNIK_PATCH_VERSION 5 -// translates to 300003 #define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION) #ifndef MAPNIK_STRINGIFY diff --git a/plugins/input/csv/build.py b/plugins/input/csv/build.py index c2beb24..2694109 100644 --- a/plugins/input/csv/build.py +++ b/plugins/input/csv/build.py @@ -21,48 +21,57 @@ Import ('env') -Import ('plugin_base') +can_build = False -PLUGIN_NAME = 'csv' +if env.get('BOOST_LIB_VERSION_FROM_HEADER'): + boost_version_from_header = int(env['BOOST_LIB_VERSION_FROM_HEADER'].split('_')[1]) + if boost_version_from_header >= 56: + can_build = True -plugin_env = plugin_base.Clone() +if not can_build: + print 'WARNING: skipping building the optional topojson datasource plugin which requires boost >= 1.56' +else: + Import ('plugin_base') -plugin_sources = Split( - """ - %(PLUGIN_NAME)s_datasource.cpp - %(PLUGIN_NAME)s_featureset.cpp - %(PLUGIN_NAME)s_inline_featureset.cpp - """ % locals() -) + PLUGIN_NAME = 'csv' -# Link Library to Dependencies -libraries = [] -libraries.append('boost_system%s' % env['BOOST_APPEND']) -libraries.append(env['ICU_LIB_NAME']) -libraries.append('mapnik-json') -libraries.append('mapnik-wkt') + plugin_env = plugin_base.Clone() -if env['PLUGIN_LINKING'] == 'shared': - libraries.append(env['MAPNIK_NAME']) + plugin_sources = Split( + """ + %(PLUGIN_NAME)s_datasource.cpp + %(PLUGIN_NAME)s_featureset.cpp + %(PLUGIN_NAME)s_inline_featureset.cpp + """ % locals() + ) - TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME, - SHLIBPREFIX='', - SHLIBSUFFIX='.input', - source=plugin_sources, - LIBS=libraries) + # Link Library to Dependencies + libraries = [] + libraries.append('boost_system%s' % env['BOOST_APPEND']) + libraries.append(env['ICU_LIB_NAME']) + libraries.append('mapnik-json') + libraries.append('mapnik-wkt') - # if the plugin links to libmapnik ensure it is built first - Depends(TARGET, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME'])) - Depends(TARGET, env.subst('../../../src/json/libmapnik-json${LIBSUFFIX}')) - Depends(TARGET, env.subst('../../../src/wkt/libmapnik-wkt${LIBSUFFIX}')) + if env['PLUGIN_LINKING'] == 'shared': + libraries.append(env['MAPNIK_NAME']) - if 'uninstall' not in COMMAND_LINE_TARGETS: - env.Install(env['MAPNIK_INPUT_PLUGINS_DEST'], TARGET) - env.Alias('install', env['MAPNIK_INPUT_PLUGINS_DEST']) + TARGET = plugin_env.SharedLibrary('../%s' % PLUGIN_NAME, + SHLIBPREFIX='', + SHLIBSUFFIX='.input', + source=plugin_sources, + LIBS=libraries) -plugin_obj = { - 'LIBS': libraries, - 'SOURCES': plugin_sources, -} + # if the plugin links to libmapnik ensure it is built first + Depends(TARGET, env.subst('../../../src/%s' % env['MAPNIK_LIB_NAME'])) + Depends(TARGET, env.subst('../../../src/json/libmapnik-json${LIBSUFFIX}')) + Depends(TARGET, env.subst('../../../src/wkt/libmapnik-wkt${LIBSUFFIX}')) -Return('plugin_obj') + if 'uninstall' not in COMMAND_LINE_TARGETS: + env.Install(env['MAPNIK_INPUT_PLUGINS_DEST'], TARGET) + env.Alias('install', env['MAPNIK_INPUT_PLUGINS_DEST']) + + plugin_obj = { + 'LIBS': libraries, + 'SOURCES': plugin_sources, + } + Return('plugin_obj') diff --git a/plugins/input/csv/csv_datasource.cpp b/plugins/input/csv/csv_datasource.cpp index a727524..8b15fc9 100644 --- a/plugins/input/csv/csv_datasource.cpp +++ b/plugins/input/csv/csv_datasource.cpp @@ -37,6 +37,13 @@ #include <mapnik/util/trim.hpp> #include <mapnik/util/geometry_to_ds_type.hpp> #include <mapnik/value_types.hpp> + +#ifdef CSV_MEMORY_MAPPED_FILE +#include <boost/interprocess/mapped_region.hpp> +#include <boost/interprocess/streams/bufferstream.hpp> +#include <mapnik/mapped_memory_cache.hpp> +#endif + // stl #include <sstream> #include <fstream> @@ -102,17 +109,36 @@ csv_datasource::csv_datasource(parameters const& params) } else { -#if defined (_WINDOWS) +#if defined (CSV_MEMORY_MAPPED_FILE) + using file_source_type = boost::interprocess::ibufferstream; + file_source_type in; + mapnik::mapped_region_ptr mapped_region; + boost::optional<mapnik::mapped_region_ptr> memory = + mapnik::mapped_memory_cache::instance().find(filename_, true); + if (memory) + { + mapped_region = *memory; + in.buffer(static_cast<char*>(mapped_region->get_address()),mapped_region->get_size()); + } + else + { + throw std::runtime_error("could not create file mapping for " + filename_); + } +#elif defined (_WINDOWS) std::ifstream in(mapnik::utf8_to_utf16(filename_),std::ios_base::in | std::ios_base::binary); + if (!in.is_open()) + { + throw mapnik::datasource_exception("CSV Plugin: could not open: '" + filename_ + "'"); + } #else std::ifstream in(filename_.c_str(),std::ios_base::in | std::ios_base::binary); -#endif if (!in.is_open()) { throw mapnik::datasource_exception("CSV Plugin: could not open: '" + filename_ + "'"); } +#endif parse_csv(in, escape_, separator_, quote_); - in.close(); + //in.close(); no need to call close, rely on dtor } } @@ -135,7 +161,6 @@ void csv_datasource::parse_csv(T & stream, // get first line std::string csv_line; std::getline(stream,csv_line,stream.widen(newline)); - // if user has not passed a separator manually // then attempt to detect by reading first line @@ -236,22 +261,22 @@ void csv_datasource::parse_csv(T & stream, [ & ](std::string const& header){ ctx_->push(header); }); mapnik::transcoder tr(desc_.get_encoding()); + auto pos = stream.tellg(); // handle rare case of a single line of data and user-provided headers // where a lack of a newline will mean that std::getline returns false bool is_first_row = false; if (!has_newline) { - stream >> csv_line; + stream.setstate(std::ios::failbit); + pos = 0; if (!csv_line.empty()) { is_first_row = true; } } - std::vector<item_type> boxes; - auto pos = stream.tellg(); - while (std::getline(stream, csv_line, stream.widen(newline)) || is_first_row) + while (is_first_row || std::getline(stream, csv_line, stream.widen(newline))) { if ((row_limit_ > 0) && (line_number++ > row_limit_)) { @@ -463,42 +488,23 @@ mapnik::layer_descriptor csv_datasource::get_descriptor() const return desc_; } -boost::optional<mapnik::datasource_geometry_t> csv_datasource::get_geometry_type() const +template <typename T> +boost::optional<mapnik::datasource_geometry_t> csv_datasource::get_geometry_type_impl(T & stream) const { boost::optional<mapnik::datasource_geometry_t> result; int multi_type = 0; auto itr = tree_->qbegin(boost::geometry::index::intersects(extent_)); auto end = tree_->qend(); - mapnik::context_ptr ctx = std::make_shared<mapnik::context_type>(); for (std::size_t count = 0; itr !=end && count < 5; ++itr, ++count) { csv_datasource::item_type const& item = *itr; std::size_t file_offset = item.second.first; std::size_t size = item.second.second; - - std::string str; - if (inline_string_.empty()) - { -#if defined (_WINDOWS) - std::ifstream in(mapnik::utf8_to_utf16(filename_),std::ios_base::in | std::ios_base::binary); -#else - std::ifstream in(filename_.c_str(),std::ios_base::in | std::ios_base::binary); -#endif - if (!in.is_open()) - { - throw mapnik::datasource_exception("CSV Plugin: could not open: '" + filename_ + "'"); - } - in.seekg(file_offset); - std::vector<char> record; - record.resize(size); - in.read(record.data(), size); - str = std::string(record.begin(), record.end()); - } - else - { - str = inline_string_.substr(file_offset, size); - } - + stream.seekg(file_offset); + std::vector<char> record; + record.resize(size); + stream.read(record.data(), size); + std::string str(record.begin(), record.end()); try { auto values = csv_utils::parse_line(str, separator_); @@ -524,6 +530,28 @@ boost::optional<mapnik::datasource_geometry_t> csv_datasource::get_geometry_type return result; } +boost::optional<mapnik::datasource_geometry_t> csv_datasource::get_geometry_type() const +{ + if (inline_string_.empty()) + { +#if defined (_WINDOWS) + std::ifstream in(mapnik::utf8_to_utf16(filename_),std::ios_base::in | std::ios_base::binary); +#else + std::ifstream in(filename_.c_str(),std::ios_base::in | std::ios_base::binary); +#endif + if (!in.is_open()) + { + throw mapnik::datasource_exception("CSV Plugin: could not open: '" + filename_ + "'"); + } + return get_geometry_type_impl(in); + } + else + { + std::stringstream in(inline_string_); + return get_geometry_type_impl(in); + } +} + mapnik::featureset_ptr csv_datasource::features(mapnik::query const& q) const { @@ -550,9 +578,9 @@ mapnik::featureset_ptr csv_datasource::features(mapnik::query const& q) const mapnik::box2d<double> const& box = q.get_bbox(); if (extent_.intersects(box)) { - csv_featureset::array_type index_array; if (tree_) { + csv_featureset::array_type index_array; tree_->query(boost::geometry::index::intersects(box),std::back_inserter(index_array)); std::sort(index_array.begin(),index_array.end(), [] (item_type const& item0, item_type const& item1) diff --git a/plugins/input/csv/csv_datasource.hpp b/plugins/input/csv/csv_datasource.hpp index 0c8864b..06b5daf 100644 --- a/plugins/input/csv/csv_datasource.hpp +++ b/plugins/input/csv/csv_datasource.hpp @@ -45,7 +45,6 @@ #include <boost/version.hpp> #include <boost/geometry/index/rtree.hpp> #pragma GCC diagnostic pop - // stl #include <vector> #include <deque> @@ -96,6 +95,9 @@ public: std::string const& quote); private: + template <typename T> + boost::optional<mapnik::datasource_geometry_t> get_geometry_type_impl(T & stream) const; + mapnik::layer_descriptor desc_; mapnik::box2d<double> extent_; std::string filename_; diff --git a/plugins/input/csv/csv_featureset.cpp b/plugins/input/csv/csv_featureset.cpp index 4a9e74a..acda58e 100644 --- a/plugins/input/csv/csv_featureset.cpp +++ b/plugins/input/csv/csv_featureset.cpp @@ -34,7 +34,9 @@ csv_featureset::csv_featureset(std::string const& filename, detail::geometry_column_locator const& locator, std::string const& separator, std::vector<std::string> const& headers, mapnik::context_ptr const& ctx, array_type && index_array) : -#ifdef _WINDOWS +#if defined(CSV_MEMORY_MAPPED_FILE) + // +#elif defined( _WINDOWS) file_(_wfopen(mapnik::utf8_to_utf16(filename).c_str(), L"rb"), std::fclose), #else file_(std::fopen(filename.c_str(),"rb"), std::fclose), @@ -48,7 +50,20 @@ csv_featureset::csv_featureset(std::string const& filename, detail::geometry_col locator_(locator), tr_("utf8") { +#if defined (CSV_MEMORY_MAPPED_FILE) + boost::optional<mapnik::mapped_region_ptr> memory = + mapnik::mapped_memory_cache::instance().find(filename, true); + if (memory) + { + mapped_region_ = *memory; + } + else + { + throw std::runtime_error("could not create file mapping for " + filename); + } +#else if (!file_) throw std::runtime_error("Can't open " + filename); +#endif } csv_featureset::~csv_featureset() {} @@ -74,12 +89,17 @@ mapnik::feature_ptr csv_featureset::next() csv_datasource::item_type const& item = *index_itr_++; std::size_t file_offset = item.second.first; std::size_t size = item.second.second; +#if defined(CSV_MEMORY_MAPPED_FILE) + char const* start = (char const*)mapped_region_->get_address() + file_offset; + char const* end = start + size; +#else std::fseek(file_.get(), file_offset, SEEK_SET); std::vector<char> record; record.resize(size); std::fread(record.data(), size, 1, file_.get()); auto const* start = record.data(); auto const* end = start + record.size(); +#endif return parse_feature(start, end); } return mapnik::feature_ptr(); diff --git a/plugins/input/csv/csv_featureset.hpp b/plugins/input/csv/csv_featureset.hpp index 1fc2103..59afa1d 100644 --- a/plugins/input/csv/csv_featureset.hpp +++ b/plugins/input/csv/csv_featureset.hpp @@ -30,9 +30,15 @@ #include <deque> #include <cstdio> +#ifdef CSV_MEMORY_MAPPED_FILE +#include <boost/interprocess/mapped_region.hpp> +#include <boost/interprocess/streams/bufferstream.hpp> +#include <mapnik/mapped_memory_cache.hpp> +#endif + class csv_featureset : public mapnik::Featureset { - using file_ptr = std::unique_ptr<std::FILE, int (*)(std::FILE *)>; + using locator_type = detail::geometry_column_locator; public: using array_type = std::deque<csv_datasource::item_type>; @@ -46,7 +52,13 @@ public: mapnik::feature_ptr next(); private: mapnik::feature_ptr parse_feature(char const* beg, char const* end); +#if defined (CSV_MEMORY_MAPPED_FILE) + using file_source_type = boost::interprocess::ibufferstream; + mapnik::mapped_region_ptr mapped_region_; +#else + using file_ptr = std::unique_ptr<std::FILE, int (*)(std::FILE *)>; file_ptr file_; +#endif std::string const& separator_; std::vector<std::string> const& headers_; const array_type index_array_; diff --git a/plugins/input/csv/csv_utils.hpp b/plugins/input/csv/csv_utils.hpp index b2981ce..b84e92d 100644 --- a/plugins/input/csv/csv_utils.hpp +++ b/plugins/input/csv/csv_utils.hpp @@ -44,6 +44,10 @@ #include <cstdio> #include <algorithm> +#ifndef _WINDOWS +#define CSV_MEMORY_MAPPED_FILE +#endif + namespace csv_utils { @@ -141,7 +145,9 @@ std::tuple<char,bool> autodect_newline(T & stream, std::size_t file_length) // autodetect newlines char newline = '\n'; bool has_newline = false; - for (std::size_t lidx = 0; lidx < file_length && lidx < 4000; ++lidx) + static std::size_t const max_size = 4000; + std::size_t size = std::min(file_length, max_size); + for (std::size_t lidx = 0; lidx < size; ++lidx) { char c = static_cast<char>(stream.get()); if (c == '\r') diff --git a/plugins/input/topojson/topojson_datasource.cpp b/plugins/input/topojson/topojson_datasource.cpp index 225a767..f9ba8ec 100644 --- a/plugins/input/topojson/topojson_datasource.cpp +++ b/plugins/input/topojson/topojson_datasource.cpp @@ -109,10 +109,6 @@ struct geometry_type_visitor { return static_cast<int>(mapnik::datasource_geometry_t::Polygon); } - int operator() (mapnik::topojson::invalid const&) const - { - return -1; - } }; struct collect_attributes_visitor @@ -121,8 +117,6 @@ struct collect_attributes_visitor collect_attributes_visitor(mapnik::layer_descriptor & desc): desc_(desc) {} - void operator() (mapnik::topojson::invalid const&) {} - template <typename GeomType> void operator() (GeomType const& g) { @@ -203,14 +197,15 @@ void topojson_datasource::parse_topojson(T const& buffer) values.reserve(topo_.geometries.size()); std::size_t geometry_index = 0; - + bool first = true; for (auto const& geom : topo_.geometries) { mapnik::box2d<double> box = mapnik::util::apply_visitor(mapnik::topojson::bounding_box_visitor(topo_), geom); if (box.valid()) { - if (geometry_index == 0) + if (first) { + first = false; extent_ = box; collect_attributes_visitor assessor(desc_); mapnik::util::apply_visitor( std::ref(assessor), geom); @@ -220,8 +215,8 @@ void topojson_datasource::parse_topojson(T const& buffer) extent_.expand_to_include(box); } values.emplace_back(box, geometry_index); - ++geometry_index; } + ++geometry_index; } // packing algorithm diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp index a6be6b1..17ec5bb 100644 --- a/src/agg/process_line_pattern_symbolizer.cpp +++ b/src/agg/process_line_pattern_symbolizer.cpp @@ -134,7 +134,7 @@ struct agg_renderer_process_visitor_l vertex_converter_type converter(clip_box,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); - if (clip) converter.set<clip_line_tag>(); //optional clip (default: true) + if (clip) converter.set<clip_line_tag>(); converter.set<transform_tag>(); //always transform if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset @@ -204,7 +204,7 @@ struct agg_renderer_process_visitor_l vertex_converter_type converter(clip_box,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); - if (clip) converter.set<clip_line_tag>(); //optional clip (default: true) + if (clip) converter.set<clip_line_tag>(); converter.set<transform_tag>(); //always transform if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index 386adee..fb00b2a 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -165,7 +165,7 @@ struct agg_renderer_process_visitor_p vertex_converter_type converter(clip_box,sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); - if (prj_trans_.equal() && clip) converter.set<clip_poly_tag>(); //optional clip (default: true) + if (prj_trans_.equal() && clip) converter.set<clip_poly_tag>(); converter.set<transform_tag>(); //always transform converter.set<affine_transform_tag>(); // optional affine transform if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter @@ -264,7 +264,7 @@ struct agg_renderer_process_visitor_p vertex_converter_type converter(clip_box, sym_,common_.t_,prj_trans_,tr,feature_,common_.vars_,common_.scale_factor_); - if (prj_trans_.equal() && clip) converter.set<clip_poly_tag>(); //optional clip (default: true) + if (prj_trans_.equal() && clip) converter.set<clip_poly_tag>(); converter.set<transform_tag>(); //always transform converter.set<affine_transform_tag>(); // optional affine transform if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter diff --git a/src/cairo/process_line_pattern_symbolizer.cpp b/src/cairo/process_line_pattern_symbolizer.cpp index 4ec6357..7aa85ab 100644 --- a/src/cairo/process_line_pattern_symbolizer.cpp +++ b/src/cairo/process_line_pattern_symbolizer.cpp @@ -150,7 +150,7 @@ void cairo_renderer<T>::process(line_pattern_symbolizer const& sym, vertex_converter_type converter(clipping_extent,sym, common_.t_, prj_trans, tr, feature, common_.vars_, common_.scale_factor_); - if (clip) converter.set<clip_line_tag>(); // optional clip (default: true) + if (clip) converter.set<clip_line_tag>(); converter.set<transform_tag>(); // always transform if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset converter.set<affine_transform_tag>(); // optional affine transform diff --git a/src/cairo/process_polygon_pattern_symbolizer.cpp b/src/cairo/process_polygon_pattern_symbolizer.cpp index 760a425..aa7b0ca 100644 --- a/src/cairo/process_polygon_pattern_symbolizer.cpp +++ b/src/cairo/process_polygon_pattern_symbolizer.cpp @@ -132,7 +132,7 @@ void cairo_renderer<T>::process(polygon_pattern_symbolizer const& sym, smooth_tag>; vertex_converter_type converter(clip_box,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); - if (prj_trans.equal() && clip) converter.set<clip_poly_tag>(); //optional clip (default: true) + if (prj_trans.equal() && clip) converter.set<clip_poly_tag>(); converter.set<transform_tag>(); //always transform converter.set<affine_transform_tag>(); if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter diff --git a/src/debug.cpp b/src/debug.cpp index 1a90df5..f41f84c 100644 --- a/src/debug.cpp +++ b/src/debug.cpp @@ -27,17 +27,18 @@ #include <ctime> #include <stdexcept> #include <fstream> +#include <cstdlib> #ifndef MAPNIK_LOG_FORMAT - #define MAPNIK_LOG_FORMAT Mapnik LOG> %Y-%m-%d %H:%M:%S: +#define MAPNIK_LOG_FORMAT Mapnik LOG> %Y-%m-%d %H:%M:%S: #endif #ifndef MAPNIK_DEFAULT_LOG_SEVERITY - #ifdef MAPNIK_DEBUG - #define MAPNIK_DEFAULT_LOG_SEVERITY 0 - #else - #define MAPNIK_DEFAULT_LOG_SEVERITY 2 - #endif +#ifdef MAPNIK_DEBUG +#define MAPNIK_DEFAULT_LOG_SEVERITY 0 +#else +#define MAPNIK_DEFAULT_LOG_SEVERITY 2 +#endif #endif namespace mapnik { @@ -52,25 +53,24 @@ std::mutex logger::format_mutex_; // first time checks -bool logger::severity_env_check_ = true; -bool logger::format_env_check_ = true; - +std::atomic<bool> logger::severity_env_check_ {true}; +std::atomic<bool> logger::format_env_check_ {true}; // severity -logger::severity_type logger::severity_level_ = - #if MAPNIK_DEFAULT_LOG_SEVERITY == 0 - logger::debug - #elif MAPNIK_DEFAULT_LOG_SEVERITY == 1 - logger::warn - #elif MAPNIK_DEFAULT_LOG_SEVERITY == 2 - logger::error - #elif MAPNIK_DEFAULT_LOG_SEVERITY == 3 - logger::none - #else - #error "Wrong default log severity level specified!" - #endif -; +std::atomic<logger::severity_type> logger::severity_level_ { +#if MAPNIK_DEFAULT_LOG_SEVERITY == 0 + logger::debug +#elif MAPNIK_DEFAULT_LOG_SEVERITY == 1 + logger::warn +#elif MAPNIK_DEFAULT_LOG_SEVERITY == 2 + logger::error +#elif MAPNIK_DEFAULT_LOG_SEVERITY == 3 + logger::none +#else +#error "Wrong default log severity level specified!" +#endif +}; logger::severity_map logger::object_severity_level_ = logger::severity_map(); @@ -85,13 +85,13 @@ std::string logger::format_ = __xstr__(MAPNIK_LOG_FORMAT); std::string logger::str() { -#if 0 +#ifdef MAPNIK_CHECK_ENV // update the format from getenv if this is the first time if (logger::format_env_check_) { logger::format_env_check_ = false; - const char* log_format = getenv("MAPNIK_LOG_FORMAT"); + const char* log_format = std::getenv("MAPNIK_LOG_FORMAT"); if (log_format != nullptr) { logger::format_ = log_format; @@ -101,7 +101,7 @@ std::string logger::str() char buf[256]; const time_t tm = time(0); - strftime(buf, sizeof(buf), logger::format_.c_str(), localtime(&tm)); + std::strftime(buf, sizeof(buf), logger::format_.c_str(), localtime(&tm)); return buf; } diff --git a/src/grid/process_line_pattern_symbolizer.cpp b/src/grid/process_line_pattern_symbolizer.cpp index d34f6e8..dc370f7 100644 --- a/src/grid/process_line_pattern_symbolizer.cpp +++ b/src/grid/process_line_pattern_symbolizer.cpp @@ -120,7 +120,7 @@ void grid_renderer<T>::process(line_pattern_symbolizer const& sym, simplify_tag,smooth_tag, offset_transform_tag,stroke_tag>; vertex_converter_type converter(clipping_extent,line,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); - if (clip) converter.set<clip_line_tag>(); // optional clip (default: true) + if (clip) converter.set<clip_line_tag>(); converter.set<transform_tag>(); // always transform if (std::fabs(offset) > 0.0) converter.set<offset_transform_tag>(); // parallel offset converter.set<affine_transform_tag>(); // optional affine transform diff --git a/src/grid/process_polygon_pattern_symbolizer.cpp b/src/grid/process_polygon_pattern_symbolizer.cpp index 604c0c2..06408a8 100644 --- a/src/grid/process_polygon_pattern_symbolizer.cpp +++ b/src/grid/process_polygon_pattern_symbolizer.cpp @@ -79,7 +79,7 @@ void grid_renderer<T>::process(polygon_pattern_symbolizer const& sym, using vertex_converter_type = vertex_converter<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag>; vertex_converter_type converter(common_.query_extent_,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); - if (prj_trans.equal() && clip) converter.set<clip_poly_tag>(); //optional clip (default: true) + if (prj_trans.equal() && clip) converter.set<clip_poly_tag>(); converter.set<transform_tag>(); //always transform converter.set<affine_transform_tag>(); if (simplify_tolerance > 0.0) converter.set<simplify_tag>(); // optional simplify converter diff --git a/src/image.cpp b/src/image.cpp index caa0a8f..32c8433 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -36,27 +36,38 @@ namespace detail // BUFFER buffer::buffer(std::size_t size) : size_(size), - data_(static_cast<unsigned char*>(size_ != 0 ? ::operator new(size_) : nullptr)) + data_(static_cast<unsigned char*>(size_ != 0 ? ::operator new(size_) : nullptr)), + owns_(true) {} +buffer::buffer(unsigned char* data, std::size_t size) + : size_(size), + data_(data), + owns_(false) +{} + +// move buffer::buffer(buffer && rhs) noexcept -: size_(std::move(rhs.size_)), - data_(std::move(rhs.data_)) +: size_(rhs.size_), + data_(rhs.data_), + owns_(rhs.owns_) { rhs.size_ = 0; rhs.data_ = nullptr; + rhs.owns_ = false; } - +// copy buffer::buffer(buffer const& rhs) : size_(rhs.size_), - data_(static_cast<unsigned char*>(size_ != 0 ? ::operator new(size_) : nullptr)) + data_(static_cast<unsigned char*>(size_ != 0 ? ::operator new(size_) : nullptr)), + owns_(true) { if (data_) std::copy(rhs.data_, rhs.data_ + rhs.size_, data_); } buffer::~buffer() { - ::operator delete(data_); + if (owns_) ::operator delete(data_); } buffer& buffer::operator=(buffer rhs) @@ -69,21 +80,7 @@ void buffer::swap(buffer & rhs) { std::swap(size_, rhs.size_); std::swap(data_, rhs.data_); -} - -unsigned char* buffer::data() -{ - return data_; -} - -unsigned char const* buffer::data() const -{ - return data_; -} - -std::size_t buffer::size() const -{ - return size_; + std::swap(owns_, rhs.owns_); } template struct MAPNIK_DECL image_dimensions<65535>; diff --git a/src/svg/svg_parser.cpp b/src/svg/svg_parser.cpp index 06c7202..ec1f4d8 100644 --- a/src/svg/svg_parser.cpp +++ b/src/svg/svg_parser.cpp @@ -28,6 +28,7 @@ #include <mapnik/safe_cast.hpp> #include <mapnik/svg/svg_parser_exception.hpp> #include <mapnik/util/file_io.hpp> +#include <mapnik/util/utf_conv_win.hpp> #include "agg_ellipse.h" #include "agg_rounded_rect.h" #include "agg_span_gradient.h" @@ -974,7 +975,11 @@ svg_parser::~svg_parser() {} bool svg_parser::parse(std::string const& filename) { +#ifdef _WINDOWS + std::basic_ifstream<char> stream(mapnik::utf8_to_utf16(filename)); +#else std::basic_ifstream<char> stream(filename.c_str()); +#endif if (!stream) { std::stringstream ss; diff --git a/src/text/placement_finder.cpp b/src/text/placement_finder.cpp index 086501e..04a2907 100644 --- a/src/text/placement_finder.cpp +++ b/src/text/placement_finder.cpp @@ -76,6 +76,8 @@ bool placement_finder::next_position() info_.properties, info_.properties.layout_defaults, info_.properties.format_tree()); + // ensure layouts stay in scope after layouts_.clear() + processed_layouts_.emplace_back(layout); // TODO: why is this call needed? // https://github.com/mapnik/mapnik/issues/2525 text_props_ = evaluate_text_properties(info_.properties,feature_,attr_); diff --git a/src/text/symbolizer_helpers.cpp b/src/text/symbolizer_helpers.cpp index 860359a..1d0fe48 100644 --- a/src/text/symbolizer_helpers.cpp +++ b/src/text/symbolizer_helpers.cpp @@ -76,11 +76,8 @@ template <typename T> struct split_multi_geometries { using container_type = T; - split_multi_geometries(container_type & cont, view_transform const& t, - proj_transform const& prj_trans) - : cont_(cont), - t_(t), - prj_trans_(prj_trans) { } + split_multi_geometries(container_type & cont) + : cont_(cont) { } void operator() (geometry::geometry_empty const&) const {} void operator() (geometry::multi_point<double> const& multi_pt) const @@ -131,8 +128,6 @@ struct split_multi_geometries } container_type & cont_; - view_transform const& t_; - proj_transform const& prj_trans_; }; } // ns detail @@ -182,8 +177,7 @@ struct largest_bbox_first void base_symbolizer_helper::initialize_geometries() const { auto const& geom = feature_.get_geometry(); - util::apply_visitor(detail::split_multi_geometries<geometry_container_type> - (geometries_to_process_, t_, prj_trans_), geom); + util::apply_visitor(detail::split_multi_geometries<geometry_container_type>(geometries_to_process_), geom); if (!geometries_to_process_.empty()) { auto type = geometry::geometry_type(geom); @@ -294,7 +288,7 @@ text_symbolizer_helper::text_symbolizer_helper( value_double simplify_tolerance = mapnik::get<value_double, keys::simplify_tolerance>(sym_, feature_, vars_); value_double smooth = mapnik::get<value_double, keys::smooth>(sym_, feature_, vars_); - if (clip) converter_.template set<clip_line_tag>(); //optional clip (default: true) + if (clip) converter_.template set<clip_line_tag>(); converter_.template set<transform_tag>(); //always transform converter_.template set<affine_transform_tag>(); if (simplify_tolerance > 0.0) converter_.template set<simplify_tag>(); // optional simplify converter @@ -419,7 +413,7 @@ text_symbolizer_helper::text_symbolizer_helper( value_double simplify_tolerance = mapnik::get<value_double, keys::simplify_tolerance>(sym_, feature_, vars_); value_double smooth = mapnik::get<value_double, keys::smooth>(sym_, feature_, vars_); - if (clip) converter_.template set<clip_line_tag>(); //optional clip (default: true) + if (clip) converter_.template set<clip_line_tag>(); converter_.template set<transform_tag>(); //always transform converter_.template set<affine_transform_tag>(); if (simplify_tolerance > 0.0) converter_.template set<simplify_tag>(); // optional simplify converter diff --git a/src/unicode.cpp b/src/unicode.cpp index cf36f55..dac9b29 100644 --- a/src/unicode.cpp +++ b/src/unicode.cpp @@ -39,7 +39,7 @@ transcoder::transcoder (std::string const& encoding) conv_ = ucnv_open(encoding.c_str(),&err); if (!U_SUCCESS(err)) { - // NOT: conv_ should be null on error so no need to call ucnv_close + // NOTE: conv_ should be null on error so no need to call ucnv_close throw std::runtime_error(std::string("could not create converter for ") + encoding); } } diff --git a/test/standalone/csv_test.cpp b/test/standalone/csv_test.cpp index c156929..6535e82 100644 --- a/test/standalone/csv_test.cpp +++ b/test/standalone/csv_test.cpp @@ -612,6 +612,7 @@ TEST_CASE("csv") { require_attributes(all_features(ds)->next(), { attr{"x", 0}, attr{"y", 0}, attr{"name", ustring("data_name")} }); REQUIRE(count_features(all_features(ds)) == r.second); + CHECK(ds->get_geometry_type() == mapnik::datasource_geometry_t::Point); } } // END SECTION diff --git a/test/unit/imaging/image.cpp b/test/unit/imaging/image.cpp index ee70a67..23f02c2 100644 --- a/test/unit/imaging/image.cpp +++ b/test/unit/imaging/image.cpp @@ -10,7 +10,7 @@ TEST_CASE("image class") { SECTION("test gray16") { - + const mapnik::image_gray16 im(4,4); mapnik::image_gray16 im2(im); mapnik::image_gray16 im3(5,5); @@ -20,11 +20,11 @@ SECTION("test gray16") { CHECK_FALSE(im2 == im3); CHECK(im < im3); CHECK_FALSE(im < im2); - + // Check that width is correct CHECK(im.width() == 4); CHECK(im2.width() == 4); - + // Check that height is correct CHECK(im.height() == 4); CHECK(im2.height() == 4); @@ -40,11 +40,11 @@ SECTION("test gray16") { // Check that size is correct CHECK(im.size() == 32); CHECK(im2.size() == 32); - + // Check that row_size is correct CHECK(im.row_size() == 8); CHECK(im2.row_size() == 8); - + // Check that get_premultiplied is correct CHECK_FALSE(im.get_premultiplied()); CHECK_FALSE(im2.get_premultiplied()); @@ -52,7 +52,7 @@ SECTION("test gray16") { // Check that set premultiplied works im2.set_premultiplied(true); CHECK(im2.get_premultiplied()); - + // Check that painted is correct CHECK_FALSE(im.painted()); CHECK_FALSE(im2.painted()); @@ -64,15 +64,15 @@ SECTION("test gray16") { // Check that offset is correct CHECK(im.get_offset() == 0.0); CHECK(im2.get_offset() == 0.0); - + // Check that set offset works im2.set_offset(2.3); CHECK(im2.get_offset() == 2.3); - + // Check that scaling is correct CHECK(im.get_scaling() == 1.0); CHECK(im2.get_scaling() == 1.0); - + // Check that set scaling works im2.set_scaling(1.1); CHECK(im2.get_scaling() == 1.1); @@ -140,7 +140,7 @@ SECTION("test gray16") { CHECK(im2(0,0) == 30); CHECK(im2(0,1) == 514); CHECK(im2(1,1) == 50); - + } // END SECTION SECTION("image_null") @@ -149,11 +149,11 @@ SECTION("image_null") const mapnik::image_null im_null2(2,2); // Actually doesn't really set any size mapnik::image_null im_null3(im_null2); mapnik::image_null im_null4(std::move(im_null3)); - + // All nulls are equal CHECK(im_null == im_null4); CHECK(im_null == im_null2); - + // No null is greater CHECK_FALSE(im_null < im_null4); CHECK_FALSE(im_null < im_null2); @@ -289,5 +289,85 @@ SECTION("Image Buffer") } // END SECTION -} // END TEST CASE +SECTION("Image copy/move") +{ + mapnik::detail::buffer buf(16 * 16 * 4); // large enough to hold 16*16 RGBA image + CHECK(buf.size() == 16 * 16 * 4); + // fill buffer with 0xff + std::fill(buf.data(), buf.data() + buf.size(), 0xff); + + // move buffer + mapnik::detail::buffer buf2(std::move(buf)); + CHECK (buf.size() == 0); + CHECK (buf.data() == nullptr); + + mapnik::image_rgba8 im(16, 16, buf2.data()); // shallow copy + std::size_t count = 0; + for (auto const& pixel : im) + { + // expect rgba(255,255,255,1.0) + CHECK( sizeof(pixel) == sizeof(mapnik::image_rgba8::pixel_type)); + CHECK( pixel == 0xffffffff); + ++count; + } + CHECK( count == im.width() * im.height()); + CHECK( buf2.size() == im.width() * im.height() * sizeof( mapnik::image_rgba8::pixel_type)); + + // mutate buffer + // fill buffer with 0x7f - semi-transparent grey + std::fill(buf2.data(), buf2.data() + buf2.size(), 0x7f); + for (auto const& pixel : im) + { + // expect rgba(127,127,127,0.5) + CHECK( pixel == 0x7f7f7f7f); + } + + // mutate image directly (buf) + for (auto & pixel : im) + { + pixel = mapnik::color(0,255,0).rgba(); // green + } + + // move + mapnik::image_rgba8 im2(std::move(im)); + CHECK (im.data() == nullptr); + CHECK (im.bytes() == nullptr); + CHECK (im.width() == 0); + CHECK (im.height() == 0); + for (auto const& pixel : im2) + { + // expect `green` + CHECK( pixel == mapnik::color(0,255,0).rgba()); + } + + // deep copy + mapnik::image_rgba8 im3(im2); // allocates new internal buffer + for (auto & pixel : im3) + { + // expect `green` + CHECK( pixel == mapnik::color(0,255,0).rgba()); + // mutate + pixel = mapnik::color(255,0,0).rgba(); //red + } + + // im2 (green) + for (auto const& pixel : im2) + { + // expect `green` + CHECK( pixel == mapnik::color(0,255,0).rgba()); + } + + //buf2 still holds green pixels + CHECK(buf2.size() == 16 * 16 * 4); + + unsigned char* itr = buf2.data(); + unsigned char* end = itr + buf2.size(); + count = 0; + for ( ;itr!= end; ++itr) + { + CHECK( *itr == ((count++ % 2 == 0) ? 0 : 0xff)); // green + } +} + +} // END TEST CASE diff --git a/test/unit/imaging/image_filter.cpp b/test/unit/imaging/image_filter.cpp index f07836d..0386409 100644 --- a/test/unit/imaging/image_filter.cpp +++ b/test/unit/imaging/image_filter.cpp @@ -119,15 +119,12 @@ SECTION("test agg stack blur") { } // END SECTION -SECTION("test scale-hsla") { +SECTION("test scale-hsla 1") { mapnik::image_rgba8 im(3,3); mapnik::fill(im,mapnik::color("blue")); mapnik::set_pixel(im, 1, 1, mapnik::color("red")); - // Should throw because a value is greater then 1.0 - REQUIRE_THROWS(mapnik::filter::filter_image(im, "scale-hsla(0.0,1.5,0.0,1.0,0.0,0.5,0.0,0.5)");); - mapnik::filter::filter_image(im, "scale-hsla(0.0,0.5,0.0,1.0,0.0,0.5,0.0,0.5)"); CHECK(im(0,0) == 0x80004000); @@ -142,6 +139,35 @@ SECTION("test scale-hsla") { } // END SECTION +SECTION("test scale-hsla 2") { + + mapnik::image_rgba8 im(3,3); + mapnik::set_pixel(im, 0, 0, mapnik::color(255, 0, 0)); + mapnik::set_pixel(im, 0, 1, mapnik::color(147, 112, 219)); + mapnik::set_pixel(im, 0, 2, mapnik::color(128, 128, 128)); + mapnik::set_pixel(im, 1, 0, mapnik::color(72, 209, 204)); + mapnik::set_pixel(im, 1, 1, mapnik::color(218, 112, 214)); + mapnik::set_pixel(im, 1, 2, mapnik::color(30, 144, 255)); + mapnik::set_pixel(im, 2, 0, mapnik::color(238, 130, 238)); + mapnik::set_pixel(im, 2, 1, mapnik::color(154, 205, 50)); + mapnik::set_pixel(im, 2, 2, mapnik::color(160, 82, 45)); + + // Should not throw on values out of [0, 1] + // https://github.com/mapnik/mapnik/issues/3052 + REQUIRE_NOTHROW(mapnik::filter::filter_image(im, "scale-hsla(0.0,1.5,-1.0,1.0,-1.0,2.0,1.0,1.0)");); + + CHECK(im(0,0) == 0xff0000ff); + CHECK(im(0,1) == 0xffefeff4); + CHECK(im(0,2) == 0xff818181); + CHECK(im(1,0) == 0xffb895a5); + CHECK(im(1,1) == 0xffededf3); + CHECK(im(1,2) == 0xffd75aff); + CHECK(im(2,0) == 0xffffffff); + CHECK(im(2,1) == 0xff649b64); + CHECK(im(2,2) == 0xff2e343b); + +} // END SECTION + SECTION("test emboss") { mapnik::image_rgba8 im(3,3); @@ -310,18 +336,58 @@ SECTION("test colorize-alpha - two color") { mapnik::filter::filter_image(im, "colorize-alpha(green,blue)"); - CHECK(im(0,0) == 0xfffc0000); - CHECK(im(0,1) == 0xfffc0000); - CHECK(im(0,2) == 0xfffc0000); - CHECK(im(1,0) == 0xfffc0000); - CHECK(im(1,1) == 0xfffc0000); - CHECK(im(1,2) == 0xfffc0000); - CHECK(im(2,0) == 0xfffc0000); - CHECK(im(2,1) == 0xfffc0000); - CHECK(im(2,2) == 0xfffc0000); + CHECK(im(0,0) == 0xfffd0000); + CHECK(im(0,1) == 0xfffd0000); + CHECK(im(0,2) == 0xfffd0000); + CHECK(im(1,0) == 0xfffd0000); + CHECK(im(1,1) == 0xfffd0000); + CHECK(im(1,2) == 0xfffd0000); + CHECK(im(2,0) == 0xfffd0000); + CHECK(im(2,1) == 0xfffd0000); + CHECK(im(2,2) == 0xfffd0000); } // END SECTION +SECTION("test colorize-alpha - one color with transparency") { + + mapnik::image_rgba8 im(3,3); + mapnik::fill(im,mapnik::color("#0000ffaa")); + mapnik::set_pixel(im, 1, 1, mapnik::color("#aaaaaaaa")); + + mapnik::filter::filter_image(im, "colorize-alpha(#0000ff99)"); + + CHECK(im(0,0) == 0x66660000); + CHECK(im(0,1) == 0x66660000); + CHECK(im(0,2) == 0x66660000); + CHECK(im(1,0) == 0x66660000); + CHECK(im(1,1) == 0x66660000); + CHECK(im(1,2) == 0x66660000); + CHECK(im(2,0) == 0x66660000); + CHECK(im(2,1) == 0x66660000); + CHECK(im(2,2) == 0x66660000); + +} // END SECTION + +SECTION("test colorize-alpha - two color with transparency") { + + mapnik::image_rgba8 im(3,3); + mapnik::fill(im,mapnik::color("#0000ffaa")); + mapnik::set_pixel(im, 1, 1, mapnik::color("#aaaaaaaa")); + + mapnik::filter::filter_image(im, "colorize-alpha(#0000ff00,#00ff00ff)"); + + CHECK(im(0,0) == 0x70264a00); + CHECK(im(0,1) == 0x70264a00); + CHECK(im(0,2) == 0x70264a00); + CHECK(im(1,0) == 0x70264a00); + CHECK(im(1,1) == 0x70264a00); + CHECK(im(1,2) == 0x70264a00); + CHECK(im(2,0) == 0x70264a00); + CHECK(im(2,1) == 0x70264a00); + CHECK(im(2,2) == 0x70264a00); + +} // END SECTION + SECTION("test color-blind-protanope") { mapnik::image_rgba8 im(2,2); diff --git a/test/unit/imaging/image_io_test.cpp b/test/unit/imaging/image_io_test.cpp index 6daeca8..8a51502 100644 --- a/test/unit/imaging/image_io_test.cpp +++ b/test/unit/imaging/image_io_test.cpp @@ -21,6 +21,11 @@ SECTION("readers") { boost::optional<std::string> type; try { + mapnik::image_rgba8 im_og; + auto im_size = mapnik::image_rgba8::pixel_size * im_og.width() * im_og.height(); + mapnik::detail::buffer buf(im_og.bytes(), im_size); + mapnik::image_rgba8 im2(im_og.width(), im_og.height(), buf.data()); + CHECK( im2.bytes() == im_og.bytes() ); #if defined(HAVE_JPEG) should_throw = "./test/data/images/blank.jpg"; REQUIRE( mapnik::util::exists( should_throw ) ); -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mapnik.git _______________________________________________ Pkg-grass-devel mailing list Pkg-grass-devel@lists.alioth.debian.org http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-grass-devel