diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e1ad8c26..f42e90da2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ Released: June 5, 2017 - shapeindex - return error code when no features can read from shapefile (#3198) - Upgrade Scons to `2.5.1` - Fixed bug (typo) in `raster_featureset.cpp` (#3696) +- Made `freetype_engine` singleton again. This allows for better control of its life-time. Original interface is preserved via adding static methods (#3688) ## 3.0.13 diff --git a/include/mapnik/json/feature_grammar_x3_def.hpp b/include/mapnik/json/feature_grammar_x3_def.hpp index d6432c5d6..d05219350 100644 --- a/include/mapnik/json/feature_grammar_x3_def.hpp +++ b/include/mapnik/json/feature_grammar_x3_def.hpp @@ -164,6 +164,8 @@ struct geometry_type_ : x3::symbols } } geometry_type_symbols; +namespace { + auto assign_name = [](auto const& ctx) { std::get<0>(_val(ctx)) = std::move(_attr(ctx)); @@ -173,6 +175,8 @@ auto assign_value = [](auto const& ctx) std::get<1>(_val(ctx)) = std::move(_attr(ctx)); }; +} // VS2017 + auto const assign_geometry_type = [] (auto const& ctx) { std::get<0>(_val(ctx)) = _attr(ctx); diff --git a/include/mapnik/json/generic_json_grammar_x3_def.hpp b/include/mapnik/json/generic_json_grammar_x3_def.hpp index 8c30cb37d..c16d9477a 100644 --- a/include/mapnik/json/generic_json_grammar_x3_def.hpp +++ b/include/mapnik/json/generic_json_grammar_x3_def.hpp @@ -31,6 +31,8 @@ namespace mapnik { namespace json { namespace grammar { namespace x3 = boost::spirit::x3; +namespace { + auto make_null = [] (auto const& ctx) { _val(ctx) = mapnik::value_null{}; @@ -48,19 +50,20 @@ auto make_false = [] (auto const& ctx) auto assign = [](auto const& ctx) { - _val(ctx) = _attr(ctx); + _val(ctx) = std::move(_attr(ctx)); }; auto assign_key = [](auto const& ctx) { - std::get<0>(_val(ctx)) = _attr(ctx); + std::get<0>(_val(ctx)) = std::move(_attr(ctx)); }; auto assign_value = [](auto const& ctx) { - std::get<1>(_val(ctx)) = _attr(ctx); + std::get<1>(_val(ctx)) = std::move(_attr(ctx)); }; +} // VS2017 using x3::lit; using x3::string; diff --git a/include/mapnik/svg/svg_parser.hpp b/include/mapnik/svg/svg_parser.hpp index 7a8e88f91..fab0b8e19 100644 --- a/include/mapnik/svg/svg_parser.hpp +++ b/include/mapnik/svg/svg_parser.hpp @@ -69,8 +69,8 @@ public: explicit svg_parser(svg_converter_type & path, bool strict = false); ~svg_parser(); error_handler & err_handler(); - bool parse(std::string const& filename); - bool parse_from_string(std::string const& svg); + void parse(std::string const& filename); + void parse_from_string(std::string const& svg); svg_converter_type & path_; bool is_defs_; bool strict_; diff --git a/include/mapnik/text/harfbuzz_shaper.hpp b/include/mapnik/text/harfbuzz_shaper.hpp index 534feb633..a62071800 100644 --- a/include/mapnik/text/harfbuzz_shaper.hpp +++ b/include/mapnik/text/harfbuzz_shaper.hpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #pragma GCC diagnostic pop @@ -54,7 +55,8 @@ static inline hb_script_t _icu_script_to_script(UScriptCode script) static inline const uint16_t * uchar_to_utf16(const UChar* src) { static_assert(sizeof(UChar) == sizeof(uint16_t),"UChar is eq size to uint16_t"); -#if defined(_MSC_VER) +#if defined(_MSC_VER) || (U_ICU_VERSION_MAJOR_NUM >= 59) + // ^^ http://site.icu-project.org/download/59#TOC-ICU4C-char16_t1 return reinterpret_cast(src); #else return src; diff --git a/include/mapnik/transform/transform_expression.hpp b/include/mapnik/transform/transform_expression.hpp index 1b6649f42..18c5ac092 100644 --- a/include/mapnik/transform/transform_expression.hpp +++ b/include/mapnik/transform/transform_expression.hpp @@ -171,7 +171,7 @@ struct transform_node : base_() {} template - transform_node(T const& val) + explicit transform_node(T const& val) : base_(val) {} template diff --git a/include/mapnik/unicode.hpp b/include/mapnik/unicode.hpp index 18034d262..798bfcb4e 100644 --- a/include/mapnik/unicode.hpp +++ b/include/mapnik/unicode.hpp @@ -31,6 +31,13 @@ // std #include #include +// icu +#if (U_ICU_VERSION_MAJOR_NUM >= 59) +#pragma GCC diagnostic push +#include +#include +#pragma GCC diagnostic pop +#endif struct UConverter; diff --git a/plugins/input/gdal/gdal_featureset.cpp b/plugins/input/gdal/gdal_featureset.cpp index 02f2dd745..979f9e587 100644 --- a/plugins/input/gdal/gdal_featureset.cpp +++ b/plugins/input/gdal/gdal_featureset.cpp @@ -545,7 +545,7 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) if (alpha) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: processing alpha band..."; - if (!raster_has_nodata) + if (!raster_has_nodata || (red && green && blue)) { raster_io_error = alpha->RasterIO(GF_Read, x_off, y_off, width, height, image.bytes() + 3, image.width(), image.height(), GDT_Byte, 4, 4 * image.width()); diff --git a/src/cairo/cairo_renderer.cpp b/src/cairo/cairo_renderer.cpp index 162fd6096..e3a8f34e9 100644 --- a/src/cairo/cairo_renderer.cpp +++ b/src/cairo/cairo_renderer.cpp @@ -149,6 +149,7 @@ void cairo_renderer::setup(Map const& map) { cairo_save_restore guard(context_); context_.set_color(*bg); + context_.set_operator(composite_mode_e::src); context_.paint(); } boost::optional const& image_filename = map.background_image(); diff --git a/src/load_map.cpp b/src/load_map.cpp index 6db669709..4d6066755 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -1380,7 +1380,6 @@ void map_parser::parse_raster_symbolizer(rule & rule, xml_node const & node) { found_colorizer = true; raster_colorizer_ptr colorizer = std::make_shared(); - put(raster_sym, keys::colorizer, colorizer); if (parse_raster_colorizer(colorizer, css)) put(raster_sym, keys::colorizer, colorizer); } diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index 2e223ec90..d7ea7facb 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -175,14 +175,14 @@ std::shared_ptr marker_cache::find(std::string const& uri, svg_path_adapter svg_path(stl_storage); svg_converter_type svg(svg_path, marker_path->attributes()); svg_parser p(svg, strict); + p.parse_from_string(known_svg_string); - if (!p.parse_from_string(known_svg_string) && !strict) + if (!strict) { for (auto const& msg : p.err_handler().error_messages()) { MAPNIK_LOG_ERROR(marker_cache) << "SVG PARSING ERROR:\"" << msg << "\""; } - //return std::make_shared(mapnik::marker_null()); } //svg.arrange_orientations(); double lox,loy,hix,hiy; @@ -215,15 +215,14 @@ std::shared_ptr marker_cache::find(std::string const& uri, svg_path_adapter svg_path(stl_storage); svg_converter_type svg(svg_path, marker_path->attributes()); svg_parser p(svg, strict); + p.parse(uri); - - if (!p.parse(uri) && !strict) + if (!strict) { for (auto const& msg : p.err_handler().error_messages()) { MAPNIK_LOG_ERROR(marker_cache) << "SVG PARSING ERROR:\"" << msg << "\""; } - //return std::make_shared(mapnik::marker_null()); } //svg.arrange_orientations(); double lox,loy,hix,hiy; diff --git a/src/svg/svg_parser.cpp b/src/svg/svg_parser.cpp index 15e32699d..0dc14c440 100644 --- a/src/svg/svg_parser.cpp +++ b/src/svg/svg_parser.cpp @@ -80,7 +80,7 @@ namespace mapnik { namespace svg { namespace rapidxml = boost::property_tree::detail::rapidxml; -bool traverse_tree(svg_parser& parser, rapidxml::xml_node const* node); +void traverse_tree(svg_parser& parser, rapidxml::xml_node const* node); void end_element(svg_parser& parser, rapidxml::xml_node const* node); void parse_path(svg_parser& parser, rapidxml::xml_node const* node); void parse_element(svg_parser& parser, char const* name, rapidxml::xml_node const* node); @@ -112,7 +112,7 @@ static std::array const unsupported_elements name_to_int("a")} }; - +#if 0 // disable to reduce verbosity static std::array const unsupported_attributes { {name_to_int("alignment-baseline"), name_to_int("baseline-shift"), @@ -158,6 +158,8 @@ static std::array const unsupported_attributes name_to_int("writing-mode")} }; +#endif + template void handle_unsupported(svg_parser& parser, T const& ar, char const* name) { @@ -166,7 +168,7 @@ void handle_unsupported(svg_parser& parser, T const& ar, char const* name) { if (e == element) { - parser.err_handler().on_error(std::string("Unsupported:\"") + name); + parser.err_handler().on_error(std::string("Unsupported:'") + name + "'"); } } } @@ -368,7 +370,7 @@ bool parse_id_from_url (char const* str, std::string & id) x3::space); } -bool traverse_tree(svg_parser & parser, rapidxml::xml_node const* node) +void traverse_tree(svg_parser & parser, rapidxml::xml_node const* node) { auto const* name = node->name(); switch (node->type()) @@ -464,7 +466,6 @@ bool traverse_tree(svg_parser & parser, rapidxml::xml_node const* node) default: break; } - return true; } @@ -697,7 +698,8 @@ void parse_attr(svg_parser & parser, char const* name, char const* value ) } break; default: - handle_unsupported(parser, unsupported_attributes, name); + //handle_unsupported(parser, unsupported_attributes, name); + // disable for now to reduce verbosity break; } } @@ -1403,7 +1405,7 @@ svg_parser::svg_parser(svg_converter stream(mapnik::utf8_to_utf16(filename)); @@ -1414,8 +1416,7 @@ bool svg_parser::parse(std::string const& filename) { std::stringstream ss; ss << "Unable to open '" << filename << "'"; - err_handler_.on_error(ss.str()); - return false; + throw std::runtime_error(ss.str()); } stream.unsetf(std::ios::skipws); @@ -1433,8 +1434,7 @@ bool svg_parser::parse(std::string const& filename) { std::stringstream ss; ss << "svg_parser::parse - Unable to parse '" << filename << "'"; - err_handler_.on_error(ss.str()); - return false; + throw std::runtime_error(ss.str()); } for (rapidxml::xml_node const* child = doc.first_node(); @@ -1442,10 +1442,9 @@ bool svg_parser::parse(std::string const& filename) { traverse_tree(*this, child); } - return err_handler_.error_messages().empty() ? true : false; } -bool svg_parser::parse_from_string(std::string const& svg) +void svg_parser::parse_from_string(std::string const& svg) { const int flags = rapidxml::parse_trim_whitespace | rapidxml::parse_validate_closing_tags; rapidxml::xml_document<> doc; @@ -1459,15 +1458,13 @@ bool svg_parser::parse_from_string(std::string const& svg) { std::stringstream ss; ss << "Unable to parse '" << svg << "'"; - err_handler_.on_error(ss.str()); - return false; + throw std::runtime_error(ss.str()); } for (rapidxml::xml_node const* child = doc.first_node(); child; child = child->next_sibling()) { traverse_tree(*this, child); } - return err_handler_.error_messages().empty() ? true : false; } svg_parser::error_handler & svg_parser::err_handler() diff --git a/src/text/renderer.cpp b/src/text/renderer.cpp index 9e0833f93..692190b8e 100644 --- a/src/text/renderer.cpp +++ b/src/text/renderer.cpp @@ -157,6 +157,7 @@ void composite_color_bitmap(T & pixmap, FT_Bitmap *bitmap, int x, int y, double int scaled_height = bitmap->rows * scale; image_rgba8 scaled_image(scaled_width, scaled_height); scale_image_agg(scaled_image, image , SCALING_BILINEAR , scale, scale, 0.0, 0.0, 1.0, 0); + set_premultiplied_alpha(scaled_image, true); composite(pixmap, scaled_image, comp_op, opacity, x, y); } diff --git a/test/data b/test/data index 99da07d5e..f95fe1c7b 160000 --- a/test/data +++ b/test/data @@ -1 +1 @@ -Subproject commit 99da07d5e76ccf5978ef0a380bf5f631f9088584 +Subproject commit f95fe1c7b56a5eeb4fa2c2bcdc403d9254ce7448 diff --git a/test/data-visual b/test/data-visual index fd518f1f5..df578e343 160000 --- a/test/data-visual +++ b/test/data-visual @@ -1 +1 @@ -Subproject commit fd518f1f512b8aea4ac740c2ce12c249616a291c +Subproject commit df578e3436681bb9bc582c7ac55a4205e98334f4 diff --git a/test/unit/datasource/geojson.cpp b/test/unit/datasource/geojson.cpp index 460b263ac..60af00de8 100644 --- a/test/unit/datasource/geojson.cpp +++ b/test/unit/datasource/geojson.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include /* diff --git a/test/unit/map/background.cpp b/test/unit/map/background.cpp new file mode 100644 index 000000000..18c1b4bf6 --- /dev/null +++ b/test/unit/map/background.cpp @@ -0,0 +1,66 @@ + +#include "catch.hpp" + +#include +#include + +#if defined(HAVE_CAIRO) +#include +#include +#endif + +TEST_CASE("map") { + +SECTION("set background - agg") { + + mapnik::Map map(256, 256); + mapnik::image_rgba8 image(map.width(), map.height()); + const mapnik::color c1(255, 0, 0); + mapnik::fill(image, c1); + + CHECK(image(0, 0) == c1.rgba()); + + // Fully transparent black should replace red color + const mapnik::color c2(0, 0, 0, 0); + map.set_background(c2); + mapnik::agg_renderer ren(map, image); + ren.apply(); + + CHECK(image(0, 0) == c2.rgba()); +} + +#if defined(HAVE_CAIRO) +SECTION("set background - cairo") { + + mapnik::Map map(256, 256); + mapnik::cairo_surface_ptr image_surface( + cairo_image_surface_create(CAIRO_FORMAT_ARGB32, map.width(), map.height()), + mapnik::cairo_surface_closer()); + mapnik::cairo_ptr image_context(mapnik::create_context(image_surface)); + + cairo_set_source_rgba(image_context.get(), 1.0, 0.0, 0.0, 1.0); + cairo_paint(image_context.get()); + + { + mapnik::image_rgba8 image(map.width(), map.height()); + mapnik::cairo_image_to_rgba8(image, image_surface); + const mapnik::color c1(255, 0, 0); + CHECK(image(0, 0) == c1.rgba()); + } + + // Fully transparent black should replace red color + const mapnik::color c2(0, 0, 0, 0); + map.set_background(c2); + mapnik::cairo_renderer ren(map, image_context, 1.0); + ren.apply(); + + { + mapnik::image_rgba8 image(map.width(), map.height()); + mapnik::cairo_image_to_rgba8(image, image_surface); + CHECK(image(0, 0) == c2.rgba()); + } +} +#endif + +} + diff --git a/test/unit/serialization/wkb_test.cpp b/test/unit/serialization/wkb_test.cpp index c19b8cdca..8eea6d3bf 100644 --- a/test/unit/serialization/wkb_test.cpp +++ b/test/unit/serialization/wkb_test.cpp @@ -129,8 +129,8 @@ TEST_CASE("Well-known-geometries") geom_3.emplace_back(0,0); geom_3.emplace_back(1,1); geom_3.emplace_back(2,2); - REQUIRE(mapnik::util::to_wkt(wkt0, geom_2)); - REQUIRE(mapnik::util::to_wkt(wkt1, geom_3)); + REQUIRE(mapnik::util::to_wkt(wkt0, mapnik::geometry::geometry(geom_2))); + REQUIRE(mapnik::util::to_wkt(wkt1, mapnik::geometry::geometry(geom_3))); if (!mapnik::geometry::is_empty(geom_2) && !mapnik::geometry::is_empty(geom_3)) { REQUIRE(wkt2 == wkt3); diff --git a/test/unit/svg/svg_parser_test.cpp b/test/unit/svg/svg_parser_test.cpp index d076909bb..b49e3d7d4 100644 --- a/test/unit/svg/svg_parser_test.cpp +++ b/test/unit/svg/svg_parser_test.cpp @@ -44,11 +44,11 @@ namespace // internal mapnik::svg::svg_converter_type svg; mapnik::svg::svg_parser p; - test_parser() + explicit test_parser(bool strict = false) : stl_storage(path.source()) , svg_path(stl_storage) , svg(svg_path, path.attributes()) - , p(svg) + , p(svg, strict) {} mapnik::svg::svg_parser* operator->() @@ -91,8 +91,14 @@ TEST_CASE("SVG parser") { }; test_parser p; - REQUIRE(!p->parse(svg_name)); - REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + try + { + p->parse(svg_name); + } + catch (std::exception const& ex) + { + REQUIRE(ex.what() == join(expected_errors)); + } } SECTION("SVG::parse_from_string syntax error") @@ -108,8 +114,14 @@ TEST_CASE("SVG parser") { std::istreambuf_iterator()); test_parser p; - REQUIRE(!p->parse_from_string(svg_str)); - REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + try + { + p->parse_from_string(svg_str); + } + catch (std::exception const& ex) + { + REQUIRE(ex.what() == join(expected_errors)); + } } SECTION("SVG::parse_from_string syntax error") @@ -121,8 +133,14 @@ TEST_CASE("SVG parser") { }; test_parser p; - REQUIRE(!p->parse(svg_name)); - REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + try + { + p->parse(svg_name); + } + catch (std::exception const& ex) + { + REQUIRE(ex.what() == join(expected_errors)); + } } SECTION("SVG parser color ") @@ -140,9 +158,22 @@ TEST_CASE("SVG parser") { std::string svg_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - test_parser p; - REQUIRE(!p->parse_from_string(svg_str)); - REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + { + test_parser p; + p->parse_from_string(svg_str); + REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + } + { + test_parser p(true); + try + { + p->parse_from_string(svg_str); + } + catch (std::exception const& ex) + { + REQUIRE(ex.what() == std::string(expected_errors[0])); + } + } } SECTION("SVG - cope with erroneous geometries") @@ -170,9 +201,24 @@ TEST_CASE("SVG parser") { std::string svg_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - test_parser p; - REQUIRE(!p->parse_from_string(svg_str)); - REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + { + test_parser p; + p->parse_from_string(svg_str); + REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + } + + { + // strict + test_parser p(true); + try + { + p->parse_from_string(svg_str); + } + catch (std::exception const& ex) + { + REQUIRE(ex.what() == std::string(expected_errors[0])); + } + } } SECTION("SVG parser double % ") @@ -188,9 +234,22 @@ TEST_CASE("SVG parser") { std::string svg_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - test_parser p; - REQUIRE(!p->parse_from_string(svg_str)); - REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + { + test_parser p; + p->parse_from_string(svg_str); + REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + } + { + test_parser p(true); + try + { + p->parse_from_string(svg_str); + } + catch (std::exception const& ex) + { + REQUIRE(ex.what() == std::string(expected_errors[0])); + } + } } SECTION("SVG parser display=none") @@ -327,7 +386,7 @@ TEST_CASE("SVG parser") { std::string svg_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); test_parser p; - REQUIRE(p->parse_from_string(svg_str)); + p->parse_from_string(svg_str); auto width = p.svg.width(); auto height = p.svg.height(); REQUIRE(width == 100); @@ -610,10 +669,22 @@ TEST_CASE("SVG parser") { "Failed to find gradient fill: MyGradient", "Failed to find gradient stroke: MyGradient", }; - - test_parser p; - REQUIRE(!p->parse(svg_name)); - REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + { + test_parser p; + p->parse(svg_name); + REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + } + { + test_parser p(true); + try + { + p->parse(svg_name); + } + catch (std::exception const& ex) + { + REQUIRE(ex.what() == std::string(expected_errors[0])); + } + } } SECTION("SVG missing id") @@ -629,9 +700,22 @@ TEST_CASE("SVG parser") { std::string svg_str((std::istreambuf_iterator(in)), std::istreambuf_iterator()); - test_parser p; - REQUIRE(!p->parse_from_string(svg_str)); - REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + { + test_parser p; + p->parse_from_string(svg_str); + REQUIRE(join(p->err_handler().error_messages()) == join(expected_errors)); + } + { + test_parser p(true); + try + { + p->parse_from_string(svg_str); + } + catch (std::exception const& ex) + { + REQUIRE(ex.what() == std::string(expected_errors[0])); + } + } } SECTION("SVG missing inheritance") diff --git a/test/visual/parse_map_sizes.cpp b/test/visual/parse_map_sizes.cpp index 56df50e99..d0df2db9d 100644 --- a/test/visual/parse_map_sizes.cpp +++ b/test/visual/parse_map_sizes.cpp @@ -38,8 +38,9 @@ namespace visual_tests { namespace x3 = boost::spirit::x3; using x3::ulong_; -auto const map_sizes_grammar = x3::rule >{} = - (ulong_ >> ',' >> ulong_) % ';' ; +auto const map_size_rule = x3::rule {} = ulong_ >> ',' >> ulong_; +auto const map_sizes_grammar = x3::rule > {} = + map_size_rule % ';' ; void parse_map_sizes(std::string const & str, std::vector & sizes) {