[mapnik] 02/06: Imported Upstream version 3.0.13~rc1+ds

Bas Couwenberg sebastic at debian.org
Wed Jan 18 23:47:41 UTC 2017


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository mapnik.

commit 6c3d443da5da481b30f83e65a011ed190832e491
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Wed Jan 18 22:48:48 2017 +0100

    Imported Upstream version 3.0.13~rc1+ds
---
 .travis.yml                                        |  35 ++++---
 CHANGELOG.md                                       |  24 ++++-
 README.md                                          |   1 -
 bootstrap.sh                                       |   3 +-
 include/mapnik/cxx11_support.hpp                   |  43 ++++++++
 include/mapnik/enumeration.hpp                     |  16 ++-
 include/mapnik/feature_style_processor_impl.hpp    |   5 +-
 include/mapnik/group/group_symbolizer_helper.hpp   |  10 --
 include/mapnik/image_filter.hpp                    |  42 ++++----
 include/mapnik/json/feature_grammar.hpp            |   3 +-
 include/mapnik/json/feature_grammar_impl.hpp       |  18 ++--
 include/mapnik/json/geometry_grammar.hpp           |   1 +
 include/mapnik/json/geometry_grammar_impl.hpp      |  22 +++--
 include/mapnik/json/positions_grammar.hpp          |   2 -
 include/mapnik/offset_converter.hpp                |  10 +-
 .../renderer_common/render_group_symbolizer.hpp    |   4 +-
 include/mapnik/renderer_common/render_thunk.hpp    |   3 +-
 include/mapnik/simplify_converter.hpp              |  12 +--
 include/mapnik/symbolizer_base.hpp                 |  13 +--
 include/mapnik/text/placement_finder.hpp           |   2 -
 include/mapnik/util/variant.hpp                    |  10 +-
 include/mapnik/util/variant_io.hpp                 |   2 +-
 include/mapnik/value.hpp                           |  30 ++----
 include/mapnik/value_hash.hpp                      |  15 +--
 include/mapnik/value_types.hpp                     | 101 ++++---------------
 plugins/input/csv/csv_utils.cpp                    |   8 +-
 plugins/input/geojson/geojson_datasource.cpp       |  28 +++---
 plugins/input/pgraster/pgraster_datasource.cpp     |   4 +-
 scripts/travis-common.sh                           |  11 ++-
 src/agg/agg_renderer.cpp                           |   5 +-
 src/agg/process_line_pattern_symbolizer.cpp        |  78 ++-------------
 src/agg/process_polygon_pattern_symbolizer.cpp     | 110 ++-------------------
 src/group/group_layout_manager.cpp                 |  46 ++++-----
 src/image.cpp                                      |   1 -
 src/image_util_jpeg.cpp                            |   2 -
 src/image_util_png.cpp                             |   4 -
 src/image_util_webp.cpp                            |   2 -
 src/renderer_common/render_group_symbolizer.cpp    |   8 +-
 src/renderer_common/render_thunk_extractor.cpp     |   6 +-
 test/standalone/font_registration_test.cpp         |  36 ++-----
 test/unit/core/conversions_test.cpp                |  15 +--
 test/unit/datasource/geojson.cpp                   |  52 ++++++++++
 utils/mapnik-config/build.py                       |   2 +-
 43 files changed, 358 insertions(+), 487 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index bc4d546..387e677 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -10,8 +10,8 @@ env:
    - CCACHE_COMPRESS=1
    - HEAVY_JOBS="2"
    - PREFIX=/tmp/mapnik
-   - secure: "N3a5nzzsgpuu45k8qWdYsHNxrSnqeAGLTOYpfYoAH7B94vuf7pa7XV1tQjXbxrnx2D6ryTdtUtyRKwy7zXbwXxGt4DpczWEo8f6DUd6+obAp3kdnXABg2Sj4oA7KMs0F0CmoADy0jdUZD5YyOJHu64LCIIgzEQ9q49PFMNbU3IE="
-   - secure: "iQYPNpMtejcgYeUkWZGIWz1msIco5qydJrhZTSCQOYahAQerdT7q5WZEpEo3G6IWOGgO1eo7GFuY8DvqQjw1+jC9b9mhkRNdo3LhGTKS9Gsbl5Q27k0rjlaFZmmQHrfPlQJwhfAIp+KLugHtQw5bCoLh+95E3j0F0DayF1tuJ3s="
+   - secure: "D5CLP5lbyFru788iZO8RqDenY/YsHPREvr34zCEi93xMqOTxPmME/zyuEZSyjP5ZLyf8g/fxOuPYSDbOQ1QLwNDBWxB0JomWOahyimHKrMCrMcGHCjl//2W2mE+p9VwF5VLGgfy7CskGkS49Mye37FDK0ejwuq6MDI45DsH4Fkk="
+   - secure: "ZPHyAVL3ID5g3KEmwcnzG9z2tAQwSx526Qd3Y6tsZ3Yj+aSagVBiZQjZGKWgNX74lymtmYKnb2Md46apWLeImt6tjB3MWTu7WwWoZRnqUligz/8Nmg4Lgo7EOCkQcjN/gpA1i+cM5b+ZKDTZYOaHO6/+DAaunQzA7/p99hw/XYg="
    - secure: "F6ivqDNMBQQnrDGA9+7IX+GDswuIqQQd7YPJdQqa2Ked9jddAQDeJClb05ig3JlwfOlYLGZOd43ZX0pKuMtI2Gbkwz211agGP9S3YunwlRg8iWtJlO5kYFUdKCmJNhjg4icfkGELCgwXn+zuEWFSLpkPcjqAFKFlQrIJeAJJgKM="
 addons:
   postgresql: "9.4"
@@ -25,19 +25,27 @@ matrix:
     - os: linux
       sudo: false
       compiler: ": clang"
-      env: JOBS=8 MASON_PUBLISH=true CXX="ccache clang++-3.8 -Qunused-arguments" CC="clang-3.8" TRIGGER=true
+      env: JOBS=4 CXX="ccache g++-6" CC="gcc-6"
       addons:
         apt:
           sources: [ 'ubuntu-toolchain-r-test']
-          packages: [ 'libstdc++-5-dev', 'xutils-dev']
+          packages: [ 'libstdc++-6-dev', 'g++-6', 'xutils-dev']
+    - os: linux
+      sudo: false
+      compiler: ": clang"
+      env: JOBS=8 MASON_PUBLISH=true CXX="ccache clang++-3.9 -Qunused-arguments" CC="clang-3.9" TRIGGER=true
+      addons:
+        apt:
+          sources: [ 'ubuntu-toolchain-r-test']
+          packages: [ 'libstdc++-4.9-dev', 'xutils-dev']
     - os: linux
       sudo: false
       compiler: ": clang-coverage"
-      env: JOBS=8 COVERAGE=true CXX="ccache clang++-3.8 -Qunused-arguments" CC="clang-3.8"
+      env: JOBS=8 COVERAGE=true CXX="ccache clang++-3.9 -Qunused-arguments" CC="clang-3.9"
       addons:
         apt:
           sources: [ 'ubuntu-toolchain-r-test']
-          packages: ['libstdc++-5-dev', 'xutils-dev' ]
+          packages: ['libstdc++-4.9-dev', 'xutils-dev' ]
     - os: osx
       compiler: ": clang-osx"
       # https://docs.travis-ci.com/user/languages/objective-c/#Supported-OS-X-iOS-SDK-versions
@@ -78,10 +86,12 @@ before_script:
  - source bootstrap.sh
  - |
    if [[ $(uname -s) == 'Linux' ]]; then
-     mason install clang 3.8.0
-     export PATH=$(mason prefix clang 3.8.0)/bin:${PATH}
-     which clang++
-     export LLVM_COV="$(mason prefix clang 3.8.0)/bin/llvm-cov"
+     mason install clang++ 3.9.0
+     export PATH=$(mason prefix clang++ 3.9.0)/bin:${PATH}
+     mason install llvm-cov 3.9.0
+     export PATH=$(mason prefix llvm-cov 3.9.0)/bin:${PATH}
+     which llvm-cov
+     export LLVM_COV="$(mason prefix llvm-cov 3.9.0)/bin/llvm-cov"
    fi
  - ccache --version
  - ccache -p || true
@@ -98,7 +108,10 @@ script:
  # (and might work) for the next build
  - DURATION=2400
  - scripts/travis-command-wrapper.py -s "date" -i 120 --deadline=$(( $(date +%s) + ${DURATION} )) make
- - make test
+ - RESULT=0
+ - make test || RESULT=$?
+ # we allow visual failures with g++ for now: https://github.com/mapnik/mapnik/issues/3567
+ - if [[ ${RESULT} != 0 ]] && [[ ${CXX} =~ 'clang++' ]]; then false; fi;
  - enabled ${COVERAGE} coverage
  - enabled ${BENCH} make bench
 
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 1551687..43a48f3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,28 @@ Developers: Please commit along with changes.
 
 For a complete change history, see the git log.
 
+## 3.0.13
+
+Released: January xx, 2017
+
+(Packaged from xxxxxxx)
+
+#### Summary
+
+- Unbundle `unifont` font from distribution
+- GeoJSON: imporoved parsing grammar avoiding temp synthesised attribute (#3507)
+- GeoJSON: expose `num_features_to_query` datasource parameter + unit test (#3515)
+- Fixed intersecting extents in different projections (PR #3525 )
+- Fixed `blur` implementation by taking into account `scale_factor`
+- postgis.input - use 2D box for pgraster bounding box (PR #3551)
+- Fixed GroupSymbolizer PairLayout with 3+ items (#3526)
+- Simplified `hash` implementation (204d30e58d3553278ab6bcda2d4122b0f13f6392)
+- Simplified `mapnik::valu`e conversion rules (#3570)
+- Changed `render_thunk_list` to `std::list<render_thunk>` (PR #3585)
+- Upgraded to variant `v1.1.5`
+- CSV.input - fixed `blank` line test (8a3a380b3b5c64681f2478b4f0d06f6a907f5eed)
+
+
 ## 3.0.12
 
 Released: September 8, 2016
@@ -459,7 +481,7 @@ Released June 3rd, 2013
 
 Summary: The 2.2.0 release is primarily a performance and stability release. The code line represents development in the master branch since the release of 2.1.0 in Aug 2012 and therefore includes nearly a year of bug-fixes and optimizations. Nearly 500 new tests have been added bring the total coverage to 925. Shapefile and PostGIS datasources have benefited from numerous stability fixes, 64 bit integer support has been added to support OSM data in the grid renderer and in attribute fil [...]
 
-- Removed 3 depedencies without loosing any functionality: `ltdl`, `cairomm` and `libsigc++` (#1804,#806,#1681)
+- Removed 3 dependencies without loosing any functionality: `ltdl`, `cairomm` and `libsigc++` (#1804,#806,#1681)
 
 - Added 64 bit integer support in expressions, feature ids, and the grid_renderer (#1661,#1662,#1662)
 
diff --git a/README.md b/README.md
index e99df98..b58be71 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,6 @@ _/      _/    _/_/_/  _/_/_/    _/    _/  _/  _/    _/
 ```
 
 [![Build Status Linux](https://api.travis-ci.org/mapnik/mapnik.svg?branch=master)](http://travis-ci.org/mapnik/mapnik)
-[![CircleCI](https://circleci.com/gh/mapnik/mapnik.svg?style=svg)](https://circleci.com/gh/mapnik/mapnik)
 [![Build Status Windows](https://ci.appveyor.com/api/projects/status/hc9l7okdjtucfqqn?branch=master&svg=true)](https://ci.appveyor.com/project/Mapbox/mapnik)
 [![Coverage Status](https://coveralls.io/repos/mapnik/mapnik/badge.svg?branch=master&service=github)](https://coveralls.io/github/mapnik/mapnik?branch=master)
 
diff --git a/bootstrap.sh b/bootstrap.sh
index e926c26..f7d0ce3 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -11,7 +11,7 @@ todo
 - shrink icu data
 '
 
-MASON_VERSION="new-pkgs"
+MASON_VERSION="3e2944322"
 
 function setup_mason() {
     if [[ ! -d ./.mason ]]; then
@@ -95,6 +95,7 @@ function make_config() {
     echo "
 CXX = '$CXX'
 CC = '$CC'
+CUSTOM_CXXFLAGS = '-D_GLIBCXX_USE_CXX11_ABI=0'
 RUNTIME_LINK = 'static'
 INPUT_PLUGINS = 'all'
 PATH = '${MASON_LINKED_REL}/bin'
diff --git a/include/mapnik/cxx11_support.hpp b/include/mapnik/cxx11_support.hpp
new file mode 100644
index 0000000..dafd721
--- /dev/null
+++ b/include/mapnik/cxx11_support.hpp
@@ -0,0 +1,43 @@
+/*****************************************************************************
+ *
+ * This file is part of Mapnik (c++ mapping toolkit)
+ *
+ * Copyright (C) 2016 Artem Pavlenko
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ *****************************************************************************/
+
+#ifndef MAPNIK_CXX11_SUPPORT_HPP
+#define MAPNIK_CXX11_SUPPORT_HPP
+
+#include <type_traits>
+
+namespace mapnik {
+namespace detail {
+
+template <bool B, typename T, typename F>
+using conditional_t = typename std::conditional<B, T, F>::type;
+
+template <typename T>
+using decay_t = typename std::decay<T>::type;
+
+template <bool B, typename T = void>
+using enable_if_t = typename std::enable_if<B, T>::type;
+
+} // namespace detail
+} // namespace mapnik
+
+#endif // MAPNIK_CXX11_SUPPORT_HPP
diff --git a/include/mapnik/enumeration.hpp b/include/mapnik/enumeration.hpp
index 9064c2d..ded9dc0 100644
--- a/include/mapnik/enumeration.hpp
+++ b/include/mapnik/enumeration.hpp
@@ -28,7 +28,6 @@
 #include <mapnik/debug.hpp>
 
 // stl
-#include <bitset>
 #include <iostream>
 #include <cstdlib>
 #include <algorithm>
@@ -189,7 +188,12 @@ public:
         }
         for (unsigned i = 0; i < THE_MAX; ++i)
         {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc
+#pragma GCC diagnostic ignored "-Wpragmas" // gcc
+#pragma GCC diagnostic ignored "-Wundefined-var-template"
             if (str_copy == our_strings_[i])
+#pragma GCC diagnostic pop
             {
                 value_ = static_cast<ENUM>(i);
                 if (deprecated)
@@ -199,14 +203,24 @@ public:
                 return;
             }
         }
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc
+#pragma GCC diagnostic ignored "-Wpragmas" // gcc
+#pragma GCC diagnostic ignored "-Wundefined-var-template"
         throw illegal_enum_value(std::string("Illegal enumeration value '") +
                                  str + "' for enum " + our_name_);
+#pragma GCC diagnostic pop
     }
 
     /** Returns the current value as a string identifier. */
     std::string as_string() const
     {
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunknown-pragmas" // clang+gcc
+#pragma GCC diagnostic ignored "-Wpragmas" // gcc
+#pragma GCC diagnostic ignored "-Wundefined-var-template"
         return our_strings_[value_];
+#pragma GCC diagnostic pop
     }
 
     /** Static helper function to iterate over valid identifiers. */
diff --git a/include/mapnik/feature_style_processor_impl.hpp b/include/mapnik/feature_style_processor_impl.hpp
index 89e0c3a..2fea9d8 100644
--- a/include/mapnik/feature_style_processor_impl.hpp
+++ b/include/mapnik/feature_style_processor_impl.hpp
@@ -266,6 +266,7 @@ void feature_style_processor<Processor>::prepare_layer(layer_rendering_material
     }
 
     box2d<double> layer_ext = lay.envelope();
+    const box2d<double> buffered_query_ext_map_srs = buffered_query_ext;
     bool fw_success = false;
     bool early_return = false;
 
@@ -281,9 +282,9 @@ void feature_style_processor<Processor>::prepare_layer(layer_rendering_material
         early_return = true;
     }
     // next try intersection of layer extent back projected into map srs
-    else if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext.intersects(layer_ext))
+    else if (prj_trans.backward(layer_ext, PROJ_ENVELOPE_POINTS) && buffered_query_ext_map_srs.intersects(layer_ext))
     {
-        layer_ext.clip(buffered_query_ext);
+        layer_ext.clip(buffered_query_ext_map_srs);
         // forward project layer extent back into native projection
         if (! prj_trans.forward(layer_ext, PROJ_ENVELOPE_POINTS))
         {
diff --git a/include/mapnik/group/group_symbolizer_helper.hpp b/include/mapnik/group/group_symbolizer_helper.hpp
index 93c7d4f..41b784b 100644
--- a/include/mapnik/group/group_symbolizer_helper.hpp
+++ b/include/mapnik/group/group_symbolizer_helper.hpp
@@ -68,16 +68,6 @@ public:
         box_elements_.push_back(box_element(box, repeat_key));
     }
 
-    inline void clear_box_elements()
-    {
-        box_elements_.clear();
-    }
-
-    inline text_symbolizer_properties const& get_properties() const
-    {
-        return info_ptr_->properties;
-    }
-
     pixel_position_list const& get();
 
     // Iterate over the given path, placing line-following labels or point labels with respect to label_spacing.
diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp
index a96d4cd..4aa1e8c 100644
--- a/include/mapnik/image_filter.hpp
+++ b/include/mapnik/image_filter.hpp
@@ -390,7 +390,7 @@ void apply_convolution_3x3(Src const& src_view, Dst & dst_view, Filter const& fi
 }
 
 template <typename Src, typename Filter>
-void apply_filter(Src & src, Filter const& filter)
+void apply_filter(Src & src, Filter const& filter, double /*scale_factor*/)
 {
     demultiply_alpha(src);
     double_buffer<Src> tb(src);
@@ -398,12 +398,12 @@ void apply_filter(Src & src, Filter const& filter)
 }
 
 template <typename Src>
-void apply_filter(Src & src, agg_stack_blur const& op)
+void apply_filter(Src & src, agg_stack_blur const& op, double scale_factor)
 {
     premultiply_alpha(src);
     agg::rendering_buffer buf(src.bytes(),src.width(),src.height(), src.row_size());
     agg::pixfmt_rgba32_pre pixf(buf);
-    agg::stack_blur_rgba32(pixf,op.rx,op.ry);
+    agg::stack_blur_rgba32(pixf, op.rx * scale_factor, op.ry * scale_factor);
 }
 
 inline double channel_delta(double source, double match)
@@ -420,7 +420,7 @@ inline uint8_t apply_alpha_shift(double source, double match, double alpha)
 }
 
 template <typename Src>
-void apply_filter(Src & src, color_to_alpha const& op)
+void apply_filter(Src & src, color_to_alpha const& op, double /*scale_factor*/)
 {
     using namespace boost::gil;
     bool premultiplied = src.get_premultiplied();
@@ -481,7 +481,7 @@ void apply_filter(Src & src, color_to_alpha const& op)
 }
 
 template <typename Src>
-void apply_filter(Src & src, colorize_alpha const& op)
+void apply_filter(Src & src, colorize_alpha const& op, double /*scale_factor*/)
 {
     using namespace boost::gil;
     std::ptrdiff_t size = op.size();
@@ -590,7 +590,7 @@ void apply_filter(Src & src, colorize_alpha const& op)
 }
 
 template <typename Src>
-void apply_filter(Src & src, scale_hsla const& transform)
+void apply_filter(Src & src, scale_hsla const& transform, double /*scale_factor*/)
 {
     using namespace boost::gil;
     bool tinting = !transform.is_identity();
@@ -802,25 +802,25 @@ void color_blind_filter(Src & src, ColorBlindFilter const& op)
 }
 
 template <typename Src>
-void apply_filter(Src & src, color_blind_protanope const& op)
+void apply_filter(Src & src, color_blind_protanope const& op, double /*scale_factor*/)
 {
     color_blind_filter(src, op);
 }
 
 template <typename Src>
-void apply_filter(Src & src, color_blind_deuteranope const& op)
+void apply_filter(Src & src, color_blind_deuteranope const& op, double /*scale_factor*/)
 {
     color_blind_filter(src, op);
 }
 
 template <typename Src>
-void apply_filter(Src & src, color_blind_tritanope const& op)
+void apply_filter(Src & src, color_blind_tritanope const& op, double /*scale_factor*/)
 {
     color_blind_filter(src, op);
 }
 
 template <typename Src>
-void apply_filter(Src & src, gray const& /*op*/)
+void apply_filter(Src & src, gray const& /*op*/, double /*scale_factor*/)
 {
     premultiply_alpha(src);
     using namespace boost::gil;
@@ -871,7 +871,7 @@ void x_gradient_impl(Src const& src_view, Dst const& dst_view)
 }
 
 template <typename Src>
-void apply_filter(Src & src, x_gradient const& /*op*/)
+void apply_filter(Src & src, x_gradient const& /*op*/, double /*scale_factor*/)
 {
     premultiply_alpha(src);
     double_buffer<Src> tb(src);
@@ -879,7 +879,7 @@ void apply_filter(Src & src, x_gradient const& /*op*/)
 }
 
 template <typename Src>
-void apply_filter(Src & src, y_gradient const& /*op*/)
+void apply_filter(Src & src, y_gradient const& /*op*/, double /*scale_factor*/)
 {
     premultiply_alpha(src);
     double_buffer<Src> tb(src);
@@ -888,7 +888,7 @@ void apply_filter(Src & src, y_gradient const& /*op*/)
 }
 
 template <typename Src>
-void apply_filter(Src & src, invert const& /*op*/)
+void apply_filter(Src & src, invert const& /*op*/, double /*scale_factor*/)
 {
     premultiply_alpha(src);
     using namespace boost::gil;
@@ -916,16 +916,18 @@ void apply_filter(Src & src, invert const& /*op*/)
 template <typename Src>
 struct filter_visitor
 {
-    filter_visitor(Src & src)
-    : src_(src) {}
+    filter_visitor(Src & src, double scale_factor=1.0)
+    : src_(src),
+      scale_factor_(scale_factor) {}
 
     template <typename T>
     void operator () (T const& filter) const
     {
-        apply_filter(src_, filter);
+        apply_filter(src_, filter, scale_factor_);
     }
 
     Src & src_;
+    double scale_factor_;
 };
 
 struct filter_radius_visitor
@@ -944,14 +946,14 @@ struct filter_radius_visitor
 };
 
 template<typename Src>
-void filter_image(Src & src, std::string const& filter)
+void filter_image(Src & src, std::string const& filter, double scale_factor=1)
 {
     std::vector<filter_type> filter_vector;
     if(!parse_image_filters(filter, filter_vector))
     {
         throw std::runtime_error("Failed to parse filter argument in filter_image: '" + filter + "'");
     }
-    filter_visitor<Src> visitor(src);
+    filter_visitor<Src> visitor(src, scale_factor);
     for (filter_type const& filter_tag : filter_vector)
     {
         util::apply_visitor(visitor, filter_tag);
@@ -959,7 +961,7 @@ void filter_image(Src & src, std::string const& filter)
 }
 
 template<typename Src>
-Src filter_image(Src const& src, std::string const& filter)
+Src filter_image(Src const& src, std::string const& filter, double scale_factor=1)
 {
     std::vector<filter_type> filter_vector;
     if(!parse_image_filters(filter, filter_vector))
@@ -967,7 +969,7 @@ Src filter_image(Src const& src, std::string const& filter)
         throw std::runtime_error("Failed to parse filter argument in filter_image: '" + filter + "'");
     }
     Src new_src(src);
-    filter_visitor<Src> visitor(new_src);
+    filter_visitor<Src> visitor(new_src, scale_factor);
     for (filter_type const& filter_tag : filter_vector)
     {
         util::apply_visitor(visitor, filter_tag);
diff --git a/include/mapnik/json/feature_grammar.hpp b/include/mapnik/json/feature_grammar.hpp
index c329eb7..fae8ed5 100644
--- a/include/mapnik/json/feature_grammar.hpp
+++ b/include/mapnik/json/feature_grammar.hpp
@@ -72,7 +72,8 @@ struct feature_grammar : qi::grammar<Iterator, void(FeatureType&), space_type>
     generic_json<Iterator> json_;
     // geoJSON
     qi::rule<Iterator, void(FeatureType&),space_type> start;
-    qi::rule<Iterator, qi::locals<bool>, void(FeatureType&),space_type> feature;
+    qi::rule<Iterator, qi::locals<bool>, void(FeatureType&), space_type> feature;
+    qi::rule<Iterator, void(FeatureType&, bool&), space_type> feature_part;
     qi::rule<Iterator, space_type> feature_type;
     qi::rule<Iterator,void(FeatureType &),space_type> properties;
     qi::rule<Iterator,qi::locals<std::string>, void(FeatureType &),space_type> attributes;
diff --git a/include/mapnik/json/feature_grammar_impl.hpp b/include/mapnik/json/feature_grammar_impl.hpp
index 88f72ff..bdda650 100644
--- a/include/mapnik/json/feature_grammar_impl.hpp
+++ b/include/mapnik/json/feature_grammar_impl.hpp
@@ -41,6 +41,7 @@ feature_grammar<Iterator,FeatureType,ErrorHandler>::feature_grammar(mapnik::tran
     qi::_4_type _4;
     qi::_a_type _a;
     qi::_r1_type _r1;
+    qi::_r2_type _r2;
     qi::eps_type eps;
     qi::char_type char_;
     using qi::fail;
@@ -55,16 +56,19 @@ feature_grammar<Iterator,FeatureType,ErrorHandler>::feature_grammar(mapnik::tran
     start = feature(_r1);
 
     feature = eps[_a = false] > lit('{') >
-        (feature_type[_a = true]
-         |
-         (lit("\"geometry\"") > lit(':') > geometry_grammar_[set_geometry(_r1, _1)])
-         |
-         properties(_r1)
-         |
-         json_.key_value) % lit(',')
+        feature_part(_r1, _a) % lit(',')
         > eps(_a) > lit('}')
         ;
 
+    feature_part = feature_type[_r2 = true]
+        |
+        (lit("\"geometry\"") > lit(':') > geometry_grammar_[set_geometry(_r1, _1)])
+        |
+        properties(_r1)
+        |
+        json_.key_value
+        ;
+
     properties = lit("\"properties\"")
         > lit(':') > ((lit('{') > -attributes(_r1) > lit('}')) | lit("null"))
         ;
diff --git a/include/mapnik/json/geometry_grammar.hpp b/include/mapnik/json/geometry_grammar.hpp
index 4b0d119..fc0d3a4 100644
--- a/include/mapnik/json/geometry_grammar.hpp
+++ b/include/mapnik/json/geometry_grammar.hpp
@@ -47,6 +47,7 @@ struct geometry_grammar :
     geometry_grammar();
     qi::rule<Iterator, mapnik::geometry::geometry<double>(), space_type> start;
     qi::rule<Iterator, qi::locals<int, mapnik::json::coordinates>, mapnik::geometry::geometry<double>(), space_type> geometry;
+    qi::rule<Iterator, void(int&, mapnik::json::coordinates&, mapnik::geometry::geometry<double>&), space_type> geometry_part;
     qi::rule<Iterator, mapnik::geometry::geometry_collection<double>(), space_type> geometry_collection;
     qi::symbols<char, int> geometry_type_dispatch;
     positions_grammar<Iterator> coordinates;
diff --git a/include/mapnik/json/geometry_grammar_impl.hpp b/include/mapnik/json/geometry_grammar_impl.hpp
index 29ea846..171894c 100644
--- a/include/mapnik/json/geometry_grammar_impl.hpp
+++ b/include/mapnik/json/geometry_grammar_impl.hpp
@@ -46,21 +46,27 @@ geometry_grammar<Iterator, ErrorHandler>::geometry_grammar()
     qi::_4_type _4;
     qi::_a_type _a;
     qi::_b_type _b;
+    qi::_r1_type _r1;
+    qi::_r2_type _r2;
+    qi::_r3_type _r3;
     qi::eps_type eps;
     using qi::fail;
     using qi::on_error;
     using phoenix::push_back;
 
     start = geometry.alias() | lit("null");
+
     geometry = lit('{')[_a = 0]
-        > (((lit("\"type\"") > lit(':') > geometry_type_dispatch[_a = _1])
-            |
-            (lit("\"coordinates\"") > lit(':') > coordinates[_b = _1])
-            |
-            (lit("\"geometries\"") > lit(':') > lit('[') > geometry_collection[_val = _1] > lit(']'))
-            |
-            json_.key_value) % lit(',')) [create_geometry(_val,_a,_b)]
-        > lit('}')
+        > (geometry_part(_a, _b, _val) % lit(','))[create_geometry(_val, _a, _b)]
+        > lit('}');
+
+    geometry_part = ((lit("\"type\"") > lit(':') > geometry_type_dispatch[_r1 = _1])
+                     |
+                     (lit("\"coordinates\"") > lit(':') > coordinates[_r2 = _1])
+                     |
+                     (lit("\"geometries\"") > lit(':') > lit('[') > geometry_collection[_r3 = _1] > lit(']'))
+                     |
+                     json_.key_value)
         ;
 
     geometry_collection = geometry[push_back(_val, _1)] % lit(',')
diff --git a/include/mapnik/json/positions_grammar.hpp b/include/mapnik/json/positions_grammar.hpp
index 016ecb2..6984300 100644
--- a/include/mapnik/json/positions_grammar.hpp
+++ b/include/mapnik/json/positions_grammar.hpp
@@ -24,10 +24,8 @@
 #define MAPNIK_JSON_POSITIONS_GRAMMAR_HPP
 
 // mapnik
-#include <mapnik/util/variant.hpp>
 #include <mapnik/json/positions.hpp>
 #include <mapnik/json/error_handler.hpp>
-#include <mapnik/geometry.hpp>
 #pragma GCC diagnostic push
 #include <mapnik/warning_ignore.hpp>
 #include <boost/spirit/include/qi.hpp>
diff --git a/include/mapnik/offset_converter.hpp b/include/mapnik/offset_converter.hpp
index 310ed80..8bbb9aa 100644
--- a/include/mapnik/offset_converter.hpp
+++ b/include/mapnik/offset_converter.hpp
@@ -77,18 +77,18 @@ struct offset_converter
         return threshold_;
     }
 
-    void set_offset(double value)
+    void set_offset(double val)
     {
-        if (offset_ != value)
+        if (offset_ != val)
         {
-            offset_ = value;
+            offset_ = val;
             reset();
         }
     }
 
-    void set_threshold(double value)
+    void set_threshold(double val)
     {
-        threshold_ = value;
+        threshold_ = val;
         // no need to reset(), since threshold doesn't affect
         // offset vertices' computation, it only controls how
         // far will we be looking for self-intersections
diff --git a/include/mapnik/renderer_common/render_group_symbolizer.hpp b/include/mapnik/renderer_common/render_group_symbolizer.hpp
index e7b1b22..65cc0f9 100644
--- a/include/mapnik/renderer_common/render_group_symbolizer.hpp
+++ b/include/mapnik/renderer_common/render_group_symbolizer.hpp
@@ -42,9 +42,9 @@ struct render_thunk_list_dispatch
     {
         offset_ = offset;
 
-        for (render_thunk_ptr const& thunk : thunks)
+        for (render_thunk const& thunk : thunks)
         {
-            util::apply_visitor(std::ref(*this), *thunk);
+            util::apply_visitor(std::ref(*this), thunk);
         }
     }
 
diff --git a/include/mapnik/renderer_common/render_thunk.hpp b/include/mapnik/renderer_common/render_thunk.hpp
index 2a957d2..66b108b 100644
--- a/include/mapnik/renderer_common/render_thunk.hpp
+++ b/include/mapnik/renderer_common/render_thunk.hpp
@@ -107,8 +107,7 @@ struct text_render_thunk : util::movable
 using render_thunk = util::variant<vector_marker_render_thunk,
                                    raster_marker_render_thunk,
                                    text_render_thunk>;
-using render_thunk_ptr = std::unique_ptr<render_thunk>;
-using render_thunk_list = std::list<render_thunk_ptr>;
+using render_thunk_list = std::list<render_thunk>;
 
 } // namespace mapnik
 
diff --git a/include/mapnik/simplify_converter.hpp b/include/mapnik/simplify_converter.hpp
index 2488425..a8a6c37 100644
--- a/include/mapnik/simplify_converter.hpp
+++ b/include/mapnik/simplify_converter.hpp
@@ -120,11 +120,11 @@ public:
         return algorithm_;
     }
 
-    void set_simplify_algorithm(simplify_algorithm_e value)
+    void set_simplify_algorithm(simplify_algorithm_e val)
     {
-        if (algorithm_ != value)
+        if (algorithm_ != val)
         {
-            algorithm_ = value;
+            algorithm_ = val;
             reset();
         }
     }
@@ -134,11 +134,11 @@ public:
         return tolerance_;
     }
 
-    void set_simplify_tolerance(double value)
+    void set_simplify_tolerance(double val)
     {
-        if (tolerance_ != value)
+        if (tolerance_ != val)
         {
-            tolerance_ = value;
+            tolerance_ = val;
             reset();
         }
     }
diff --git a/include/mapnik/symbolizer_base.hpp b/include/mapnik/symbolizer_base.hpp
index f07cf3d..8ece232 100644
--- a/include/mapnik/symbolizer_base.hpp
+++ b/include/mapnik/symbolizer_base.hpp
@@ -100,18 +100,13 @@ struct strict_value : value_base_type
 {
     strict_value() = default;
 
-    strict_value(const char* val)
+    strict_value(const char* val) noexcept(false)
         : value_base_type(std::string(val)) {}
 
-    template <typename T>
-    strict_value(T const& obj)
-        : value_base_type(typename detail::mapnik_value_type<T>::type(obj))
-    {}
-
-    template <typename T>
+    template <typename T, typename U = detail::mapnik_value_type_t<T>>
     strict_value(T && obj)
-        noexcept(std::is_nothrow_constructible<value_base_type, T && >::value)
-        : value_base_type(std::forward<T>(obj))
+        noexcept(std::is_nothrow_constructible<value_base_type, U>::value)
+        : value_base_type(U(std::forward<T>(obj)))
     {}
 };
 
diff --git a/include/mapnik/text/placement_finder.hpp b/include/mapnik/text/placement_finder.hpp
index 3b02d89..83e8a04 100644
--- a/include/mapnik/text/placement_finder.hpp
+++ b/include/mapnik/text/placement_finder.hpp
@@ -67,8 +67,6 @@ private:
     bool single_line_placement(vertex_cache &pp, text_upright_e orientation);
     // Moves dx pixels but makes sure not to fall of the end.
     void path_move_dx(vertex_cache & pp, double dx);
-    // Normalize angle in range [-pi, +pi].
-    static double normalize_angle(double angle);
     // Adjusts user defined spacing to place an integer number of labels.
     double get_spacing(double path_length, double layout_width) const;
     // Checks for collision.
diff --git a/include/mapnik/util/variant.hpp b/include/mapnik/util/variant.hpp
index 27993ce..b73533d 100644
--- a/include/mapnik/util/variant.hpp
+++ b/include/mapnik/util/variant.hpp
@@ -32,15 +32,7 @@ template <typename T>
 using recursive_wrapper = typename mapbox::util::recursive_wrapper<T>;
 
 template<typename... Types>
-class variant : public mapbox::util::variant<Types...>
-{
-public:
-    // tell spirit that this is an adapted variant
-    struct adapted_variant_tag;
-    using types = std::tuple<Types...>;
-    // inherit ctor's
-    using mapbox::util::variant<Types...>::variant;
-};
+using variant = typename  mapbox::util::variant<Types...>;
 
 // unary visitor interface
 // const
diff --git a/include/mapnik/util/variant_io.hpp b/include/mapnik/util/variant_io.hpp
index 02f0be5..98978e3 100644
--- a/include/mapnik/util/variant_io.hpp
+++ b/include/mapnik/util/variant_io.hpp
@@ -24,7 +24,7 @@
 #define MAPNIK_UTIL_VARIANT_IO_HPP
 
 
-namespace mapnik { namespace util {
+namespace mapbox { namespace util {
 
 namespace detail {
 
diff --git a/include/mapnik/value.hpp b/include/mapnik/value.hpp
index 9ee7323..fb1e817 100644
--- a/include/mapnik/value.hpp
+++ b/include/mapnik/value.hpp
@@ -47,30 +47,20 @@ class MAPNIK_DECL value : public value_base
 public:
     value() = default;
 
-    // conversion from type T is done via a temporary of type U, which
-    // is determined by mapnik_value_type;
-    // enable_if< decay<T> != value > is necessary to avoid ill-formed
-    // recursion in noexcept specifier; and it also prevents using this
-    // constructor where implicitly-declared copy/move should be used
-    // (e.g. value(value&))
-    template <typename T,
-              typename U = typename std::enable_if<
-                                !detail::is_same_decay<T, value>::value,
-                                detail::mapnik_value_type_decay<T>
-                            >::type::type>
+    // Conversion from type T is done via a temporary value or reference
+    // of type U, which is determined by mapnik_value_type_t.
+    //
+    // CAVEAT: We don't check `noexcept(conversion from T to U)`.
+    //         But since the type U is either value_bool, value_integer,
+    //         value_double or T &&, this conversion SHOULD NEVER throw.
+    template <typename T, typename U = detail::mapnik_value_type_t<T>>
     value(T && val)
-        noexcept(noexcept(U(std::forward<T>(val))) &&
-                 std::is_nothrow_constructible<value_base, U && >::value)
+        noexcept(std::is_nothrow_constructible<value_base, U>::value)
         : value_base(U(std::forward<T>(val))) {}
 
-    template <typename T,
-              typename U = typename std::enable_if<
-                                !detail::is_same_decay<T, value>::value,
-                                detail::mapnik_value_type_decay<T>
-                            >::type::type>
+    template <typename T, typename U = detail::mapnik_value_type_t<T>>
     value& operator=(T && val)
-        noexcept(noexcept(U(std::forward<T>(val))) &&
-                 std::is_nothrow_assignable<value_base, U && >::value)
+        noexcept(std::is_nothrow_assignable<value_base, U>::value)
     {
         value_base::operator=(U(std::forward<T>(val)));
         return *this;
diff --git a/include/mapnik/value_hash.hpp b/include/mapnik/value_hash.hpp
index 80e10d8..3a2536c 100644
--- a/include/mapnik/value_hash.hpp
+++ b/include/mapnik/value_hash.hpp
@@ -37,11 +37,6 @@
 
 namespace mapnik { namespace detail {
 
-inline void hash_combine(std::size_t & seed, std::size_t val)
-{
-    seed ^= val + 0x9e3779b9 + (seed << 6) + (seed >> 2);
-}
-
 struct value_hasher
 {
     std::size_t operator() (value_null val) const
@@ -54,11 +49,6 @@ struct value_hasher
         return static_cast<std::size_t>(val.hashCode());
     }
 
-    std::size_t operator()(value_integer val) const
-    {
-        return static_cast<std::size_t>(val);
-    }
-
     template <class T>
     std::size_t operator()(T const& val) const
     {
@@ -72,10 +62,7 @@ struct value_hasher
 template <typename T>
 std::size_t mapnik_hash_value(T const& val)
 {
-    std::size_t seed = 0;
-    detail::hash_combine(seed, util::apply_visitor(detail::value_hasher(), val));
-    detail::hash_combine(seed, val.which());
-    return seed;
+    return util::apply_visitor(detail::value_hasher(), val);
 }
 
 } // namespace mapnik
diff --git a/include/mapnik/value_types.hpp b/include/mapnik/value_types.hpp
index 235133a..7682d52 100644
--- a/include/mapnik/value_types.hpp
+++ b/include/mapnik/value_types.hpp
@@ -25,6 +25,7 @@
 
 // mapnik
 #include <mapnik/config.hpp>
+#include <mapnik/cxx11_support.hpp>
 #include <mapnik/pixel_types.hpp>
 
 
@@ -34,7 +35,6 @@
 #pragma GCC diagnostic pop
 
 // stl
-#include <type_traits>
 #include <iosfwd>
 #include <cstddef>
 
@@ -152,90 +152,23 @@ inline std::istream& operator>> ( std::istream & s, value_null & )
 
 
 namespace detail {
-// to mapnik::value_type conversions traits
-template <typename T>
-struct is_value_bool
-{
-    constexpr static bool value = std::is_same<T, bool>::value;
-};
-
-template <typename T>
-struct is_value_integer
-{
-    constexpr static bool value = std::is_integral<T>::value && !std::is_same<T, bool>::value;
-};
-
-template <typename T>
-struct is_value_double
-{
-    constexpr static bool value = std::is_floating_point<T>::value;
-};
-
-template <typename T>
-struct is_value_unicode_string
-{
-    constexpr static bool value = std::is_same<T, typename mapnik::value_unicode_string>::value;
-};
-
-template <typename T>
-struct is_value_string
-{
-    constexpr static bool value = std::is_same<T, typename std::string>::value;
-};
-
-template <typename T>
-struct is_value_null
-{
-    constexpr static bool value = std::is_same<T, typename mapnik::value_null>::value;
-};
-
-template <typename T, class Enable = void>
-struct mapnik_value_type
-{
-    using type = T;
-};
-
-// value_null
-template <typename T>
-struct mapnik_value_type<T, typename std::enable_if<detail::is_value_null<T>::value>::type>
-{
-    using type = mapnik::value_null;
-};
-
-// value_bool
-template <typename T>
-struct mapnik_value_type<T, typename std::enable_if<detail::is_value_bool<T>::value>::type>
-{
-    using type = mapnik::value_bool;
-};
-
-// value_integer
-template <typename T>
-struct mapnik_value_type<T, typename std::enable_if<detail::is_value_integer<T>::value>::type>
-{
-    using type = mapnik::value_integer;
-};
-
-// value_double
-template <typename T>
-struct mapnik_value_type<T, typename std::enable_if<detail::is_value_double<T>::value>::type>
-{
-    using type = mapnik::value_double;
-};
-
-// value_unicode_string
-template <typename T>
-struct mapnik_value_type<T, typename std::enable_if<detail::is_value_unicode_string<T>::value>::type>
-{
-    using type = mapnik::value_unicode_string const&;
-};
-
-template <typename T>
-using mapnik_value_type_decay = mapnik_value_type<typename std::decay<T>::type>;
 
-template <typename T, typename U>
-using is_same_decay = std::is_same<typename std::decay<T>::type,
-                                   typename std::decay<U>::type>;
+// Helper metafunction for mapnik::value construction and assignment.
+// Returns:
+//  value_bool      if T is bool
+//  value_integer   if T is an integral type (except bool)
+//  value_double    if T is a floating-point type
+//  T &&            otherwise
+
+template <typename T, typename dT = decay_t<T>>
+using mapnik_value_type_t =
+    conditional_t<
+        std::is_same<dT, bool>::value, value_bool,
+        conditional_t<
+            std::is_integral<dT>::value, value_integer,
+            conditional_t<
+                std::is_floating_point<dT>::value, value_double,
+                T && >>>;
 
 } // namespace detail
 
diff --git a/plugins/input/csv/csv_utils.cpp b/plugins/input/csv/csv_utils.cpp
index 217276f..409cf6f 100644
--- a/plugins/input/csv/csv_utils.cpp
+++ b/plugins/input/csv/csv_utils.cpp
@@ -285,7 +285,10 @@ void csv_file_parser::parse_csv_and_boxes(std::istream & csv_file, T & boxes)
             {
                 auto headers = csv_utils::parse_line(csv_line, separator_, quote_);
                 // skip blank lines
-                if (headers.size() > 0 && headers[0].empty()) ++line_number;
+                if (headers.size() == 1 && headers[0].empty())
+                {
+                    ++line_number;
+                }
                 else
                 {
                     std::size_t index = 0;
@@ -300,7 +303,7 @@ void csv_file_parser::parse_csv_and_boxes(std::istream & csv_file, T & boxes)
                                 std::ostringstream s;
                                 s << "CSV Plugin: expected a column header at line ";
                                 s << line_number << ", column " << index;
-                                s << " - ensure this row contains valid header fields: '";
+                                s << " - expected fields: '";
                                 s << csv_line;
                                 throw mapnik::datasource_exception(s.str());
                             }
@@ -338,7 +341,6 @@ void csv_file_parser::parse_csv_and_boxes(std::istream & csv_file, T & boxes)
         std::string str("CSV Plugin: could not detect column(s) with the name(s) of wkt, geojson, x/y, or ");
         str += "latitude/longitude in:\n";
         str += csv_line;
-        str += "\n - this is required for reading geometry data";
         throw mapnik::datasource_exception(str);
     }
 
diff --git a/plugins/input/geojson/geojson_datasource.cpp b/plugins/input/geojson/geojson_datasource.cpp
index 2709c53..60fd7b7 100644
--- a/plugins/input/geojson/geojson_datasource.cpp
+++ b/plugins/input/geojson/geojson_datasource.cpp
@@ -108,16 +108,16 @@ struct attr_value_converter
 };
 
 geojson_datasource::geojson_datasource(parameters const& params)
-  : datasource(params),
-    type_(datasource::Vector),
-    desc_(geojson_datasource::name(),
-          *params.get<std::string>("encoding","utf-8")),
-    filename_(),
-    from_inline_string_(false),
-    extent_(),
-    features_(),
-    tree_(nullptr),
-    num_features_to_query_(*params.get<mapnik::value_integer>("num_features_to_query",5))
+    : datasource(params),
+      type_(datasource::Vector),
+      desc_(geojson_datasource::name(),
+            *params.get<std::string>("encoding","utf-8")),
+      filename_(),
+      from_inline_string_(false),
+      extent_(),
+      features_(),
+      tree_(nullptr),
+      num_features_to_query_(std::max(mapnik::value_integer(1), *params.get<mapnik::value_integer>("num_features_to_query", 5)))
 {
     boost::optional<std::string> inline_string = params.get<std::string>("inline");
     if (!inline_string)
@@ -261,8 +261,8 @@ void geojson_datasource::initialise_index(Iterator start, Iterator end)
         std::size_t start_id = 1;
         mapnik::json::default_feature_callback callback(features_);
         bool result = boost::spirit::qi::phrase_parse(itr, end, (geojson_datasource_static_feature_callback_grammar)
-                                                 (boost::phoenix::ref(ctx), boost::phoenix::ref(start_id), boost::phoenix::ref(callback)),
-                                                 space);
+                                                      (boost::phoenix::ref(ctx), boost::phoenix::ref(start_id), boost::phoenix::ref(callback)),
+                                                      space);
         if (!result || itr != end)
         {
             if (from_inline_string_) throw mapnik::datasource_exception("geojson_datasource: Failed to parse GeoJSON file from in-memory string");
@@ -481,8 +481,8 @@ boost::optional<mapnik::datasource_geometry_t> geojson_datasource::get_geometry_
     }
     else if (cache_features_)
     {
-        unsigned num_features = features_.size();
-        for (unsigned i = 0; i < num_features && i < num_features_to_query_; ++i)
+        std::size_t num_features = features_.size();
+        for (std::size_t i = 0; i < num_features && i < num_features_to_query_; ++i)
         {
             result = mapnik::util::to_ds_type(features_[i]->get_geometry());
             if (result)
diff --git a/plugins/input/pgraster/pgraster_datasource.cpp b/plugins/input/pgraster/pgraster_datasource.cpp
index e6eddf7..2c64f3a 100644
--- a/plugins/input/pgraster/pgraster_datasource.cpp
+++ b/plugins/input/pgraster/pgraster_datasource.cpp
@@ -627,10 +627,10 @@ std::string pgraster_datasource::sql_bbox(box2d<double> const& env) const
         b << "ST_SetSRID(";
     }
 
-    b << "'BOX3D(";
+    b << "'BOX(";
     b << std::setprecision(16);
     b << env.minx() << " " << env.miny() << ",";
-    b << env.maxx() << " " << env.maxy() << ")'::box3d";
+    b << env.maxx() << " " << env.maxy() << ")'::box2d";
 
     if (srid_ > 0)
     {
diff --git a/scripts/travis-common.sh b/scripts/travis-common.sh
index 40d1837..288fcc1 100644
--- a/scripts/travis-common.sh
+++ b/scripts/travis-common.sh
@@ -30,14 +30,15 @@ on () {
 
 git_submodule_update () {
     git submodule update "$@" && return
-    # failed, search pull requests for matching commits
+    # failed, search branch and pull request heads for matching commit
     git submodule foreach \
         '
         test "$sha1" = "`git rev-parse HEAD`" ||
-        git ls-remote origin "refs/pull/*/head" |
+        git ls-remote origin "refs/heads/*" "refs/pull/*/head" |
         while read hash ref; do
             if test "$hash" = "$sha1"; then
-                git config --add remote.origin.fetch "+$ref:$ref";
+                git config --add remote.origin.fetch "+$ref:$ref"
+                break
             fi
         done
         '
@@ -82,9 +83,9 @@ config_override () {
 configure () {
     if enabled ${COVERAGE}; then
         ./configure "$@" PREFIX=${PREFIX} PGSQL2SQLITE=False SVG2PNG=False SVG_RENDERER=False \
-            COVERAGE=True DEBUG=True WARNING_CXXFLAGS="-Wno-unknown-warning-option"
+            COVERAGE=True DEBUG=True
     else
-        ./configure "$@" PREFIX=${PREFIX} WARNING_CXXFLAGS="-Wno-unknown-warning-option"
+        ./configure "$@" PREFIX=${PREFIX}
     fi
     # print final config values, sorted and indented
     sort -sk1,1 ./config.py | sed -e 's/^/	/'
diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp
index f144cea..dc2c215 100644
--- a/src/agg/agg_renderer.cpp
+++ b/src/agg/agg_renderer.cpp
@@ -257,6 +257,7 @@ void agg_renderer<T0,T1>::start_style_processing(feature_type_style const& st)
             {
                 util::apply_visitor(visitor, filter_tag);
             }
+            radius *= common_.scale_factor_;
             if (radius > common_.t_.offset())
             {
                 common_.t_.set_offset(radius);
@@ -309,7 +310,7 @@ void agg_renderer<T0,T1>::end_style_processing(feature_type_style const& st)
         if (st.image_filters().size() > 0)
         {
             blend_from = true;
-            mapnik::filter::filter_visitor<buffer_type> visitor(*current_buffer_);
+            mapnik::filter::filter_visitor<buffer_type> visitor(*current_buffer_, common_.scale_factor_);
             for (mapnik::filter::filter_type const& filter_tag : st.image_filters())
             {
                 util::apply_visitor(visitor, filter_tag);
@@ -334,7 +335,7 @@ void agg_renderer<T0,T1>::end_style_processing(feature_type_style const& st)
     if (st.direct_image_filters().size() > 0)
     {
         // apply any 'direct' image filters
-        mapnik::filter::filter_visitor<buffer_type> visitor(pixmap_);
+        mapnik::filter::filter_visitor<buffer_type> visitor(pixmap_, common_.scale_factor_);
         for (mapnik::filter::filter_type const& filter_tag : st.direct_image_filters())
         {
             util::apply_visitor(visitor, filter_tag);
diff --git a/src/agg/process_line_pattern_symbolizer.cpp b/src/agg/process_line_pattern_symbolizer.cpp
index dbbb7f2..e8770e2 100644
--- a/src/agg/process_line_pattern_symbolizer.cpp
+++ b/src/agg/process_line_pattern_symbolizer.cpp
@@ -79,80 +79,23 @@ struct agg_renderer_process_visitor_l
 
     void operator() (marker_svg const& marker) const
     {
-        using color = agg::rgba8;
-        using order = agg::order_rgba;
-        using blender_type = agg::comp_op_adaptor_rgba_pre<color, order>;
-        using pattern_filter_type = agg::pattern_filter_bilinear_rgba8;
-        using pattern_type = agg::line_image_pattern<pattern_filter_type>;
-        using pixfmt_type = agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer>;
-        using renderer_base = agg::renderer_base<pixfmt_type>;
-        using renderer_type = agg::renderer_outline_image<renderer_base, pattern_type>;
-        using rasterizer_type = agg::rasterizer_outline_aa<renderer_type>;
-
-        value_double opacity = get<value_double, keys::opacity>(sym_, feature_, common_.vars_);
         agg::trans_affine image_tr = agg::trans_affine_scaling(common_.scale_factor_);
         auto image_transform = get_optional<transform_type>(sym_, keys::image_transform);
         if (image_transform) evaluate_transform(image_tr, feature_, common_.vars_, *image_transform, common_.scale_factor_);
         mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr;
         image_rgba8 image(bbox_image.width(), bbox_image.height());
         render_pattern<buffer_type>(*ras_ptr_, marker, image_tr, 1.0, image);
-
-        value_bool clip = get<value_bool, keys::clip>(sym_, feature_, common_.vars_);
-        value_double offset = get<value_double, keys::offset>(sym_, feature_, common_.vars_);
-        value_double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym_, feature_, common_.vars_);
-        value_double smooth = get<value_double, keys::smooth>(sym_, feature_, common_.vars_);
-
-        agg::rendering_buffer buf(current_buffer_->bytes(),current_buffer_->width(),current_buffer_->height(), current_buffer_->row_size());
-        pixfmt_type pixf(buf);
-        pixf.comp_op(static_cast<agg::comp_op_e>(get<composite_mode_e, keys::comp_op>(sym_, feature_, common_.vars_)));
-        renderer_base ren_base(pixf);
-        agg::pattern_filter_bilinear_rgba8 filter;
-
-        pattern_source source(image, opacity);
-        pattern_type pattern (filter,source);
-        renderer_type ren(ren_base, pattern);
-        double half_stroke = std::max(marker.width()/2.0,marker.height()/2.0);
-        int rast_clip_padding = static_cast<int>(std::round(half_stroke));
-        ren.clip_box(-rast_clip_padding,-rast_clip_padding,common_.width_+rast_clip_padding,common_.height_+rast_clip_padding);
-        rasterizer_type ras(ren);
-
-        agg::trans_affine tr;
-        auto transform = get_optional<transform_type>(sym_, keys::geometry_transform);
-        if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_);
-
-        box2d<double> clip_box = clipping_extent(common_);
-        if (clip)
-        {
-            double padding = (double)(common_.query_extent_.width()/pixmap_.width());
-            if (half_stroke > 1)
-                padding *= half_stroke;
-            if (std::fabs(offset) > 0)
-                padding *= std::fabs(offset) * 1.2;
-            padding *= common_.scale_factor_;
-            clip_box.pad(padding);
-        }
-        using vertex_converter_type = vertex_converter<clip_line_tag, transform_tag,
-                                                       affine_transform_tag,
-                                                       simplify_tag,smooth_tag,
-                                                       offset_transform_tag>;
-
-        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>();
-        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
-        converter.set<affine_transform_tag>(); // optional affine transform
-        if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter
-
-        using apply_vertex_converter_type = detail::apply_vertex_converter<vertex_converter_type, rasterizer_type>;
-        using vertex_processor_type = geometry::vertex_processor<apply_vertex_converter_type>;
-        apply_vertex_converter_type apply(converter, ras);
-        mapnik::util::apply_visitor(vertex_processor_type(apply),feature_.get_geometry());
+        render(image, marker.width(), marker.height());
     }
 
     void operator() (marker_rgba8 const& marker) const
     {
+        render(marker.get_data(), marker.width(), marker.height());
+    }
+
+private:
+    void render(mapnik::image_rgba8 const& marker, double width, double height) const
+    {
         using color = agg::rgba8;
         using order = agg::order_rgba;
         using blender_type = agg::comp_op_adaptor_rgba_pre<color, order>;
@@ -164,8 +107,6 @@ struct agg_renderer_process_visitor_l
         using rasterizer_type = agg::rasterizer_outline_aa<renderer_type>;
 
         value_double opacity = get<value_double, keys::opacity>(sym_, feature_, common_.vars_);
-        mapnik::image_rgba8 const& image = marker.get_data();
-
         value_bool clip = get<value_bool, keys::clip>(sym_, feature_, common_.vars_);
         value_double offset = get<value_double, keys::offset>(sym_, feature_, common_.vars_);
         value_double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym_, feature_, common_.vars_);
@@ -178,10 +119,10 @@ struct agg_renderer_process_visitor_l
         renderer_base ren_base(pixf);
         agg::pattern_filter_bilinear_rgba8 filter;
 
-        pattern_source source(image, opacity);
+        pattern_source source(marker, opacity);
         pattern_type pattern (filter,source);
         renderer_type ren(ren_base, pattern);
-        double half_stroke = std::max(marker.width()/2.0,marker.height()/2.0);
+        double half_stroke = std::max(width / 2.0, height / 2.0);
         int rast_clip_padding = static_cast<int>(std::round(half_stroke));
         ren.clip_box(-rast_clip_padding,-rast_clip_padding,common_.width_+rast_clip_padding,common_.height_+rast_clip_padding);
         rasterizer_type ras(ren);
@@ -221,7 +162,6 @@ struct agg_renderer_process_visitor_l
         mapnik::util::apply_visitor(vertex_processor_type(apply), feature_.get_geometry());
     }
 
-  private:
     renderer_common & common_;
     buffer_type & pixmap_;
     buffer_type * current_buffer_;
diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp
index f2a0159..5e017cf 100644
--- a/src/agg/process_polygon_pattern_symbolizer.cpp
+++ b/src/agg/process_polygon_pattern_symbolizer.cpp
@@ -88,7 +88,17 @@ struct agg_renderer_process_visitor_p
         mapnik::box2d<double> const& bbox_image = marker.get_data()->bounding_box() * image_tr;
         mapnik::image_rgba8 image(bbox_image.width(), bbox_image.height());
         render_pattern<buffer_type>(*ras_ptr_, marker, image_tr, 1.0, image);
+        render(image);
+    }
 
+    void operator() (marker_rgba8 const& marker) const
+    {
+        render(marker.get_data());
+    }
+
+private:
+    void render(mapnik::image_rgba8 const& image) const
+    {
         agg::rendering_buffer buf(current_buffer_->bytes(), current_buffer_->width(),
                                   current_buffer_->height(), current_buffer_->row_size());
         ras_ptr_->reset();
@@ -147,105 +157,6 @@ struct agg_renderer_process_visitor_p
             using apply_local_alignment = detail::apply_local_alignment;
             apply_local_alignment apply(common_.t_,prj_trans_, clip_box, x0, y0);
             util::apply_visitor(geometry::vertex_processor<apply_local_alignment>(apply), feature_.get_geometry());
-            offset_x = unsigned(current_buffer_->width() - x0);
-            offset_y = unsigned(current_buffer_->height() - y0);
-        }
-
-        span_gen_type sg(img_src, offset_x, offset_y);
-
-        agg::span_allocator<agg::rgba8> sa;
-        renderer_type rp(renb,sa, sg, unsigned(opacity * 255));
-
-        agg::trans_affine tr;
-        auto transform = get_optional<transform_type>(sym_, keys::geometry_transform);
-        if (transform) evaluate_transform(tr, feature_, common_.vars_, *transform, common_.scale_factor_);
-        using vertex_converter_type = vertex_converter<clip_poly_tag,
-                                                       transform_tag,
-                                                       affine_transform_tag,
-                                                       simplify_tag,
-                                                       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>();
-        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
-        if (smooth > 0.0) converter.set<smooth_tag>(); // optional smooth converter
-
-        using apply_vertex_converter_type = detail::apply_vertex_converter<vertex_converter_type, rasterizer>;
-        using vertex_processor_type = geometry::vertex_processor<apply_vertex_converter_type>;
-        apply_vertex_converter_type apply(converter, *ras_ptr_);
-        mapnik::util::apply_visitor(vertex_processor_type(apply),feature_.get_geometry());
-        agg::scanline_u8 sl;
-        ras_ptr_->filling_rule(agg::fill_even_odd);
-        agg::render_scanlines(*ras_ptr_, sl, rp);
-    }
-
-    void operator() (marker_rgba8 const& marker) const
-    {
-        using color = agg::rgba8;
-        using order = agg::order_rgba;
-        using blender_type = agg::comp_op_adaptor_rgba_pre<color, order>;
-        using pixfmt_type = agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer>;
-
-        using wrap_x_type = agg::wrap_mode_repeat;
-        using wrap_y_type = agg::wrap_mode_repeat;
-        using img_source_type = agg::image_accessor_wrap<agg::pixfmt_rgba32_pre,
-                                                         wrap_x_type,
-                                                         wrap_y_type>;
-
-        using span_gen_type = agg::span_pattern_rgba<img_source_type>;
-        using ren_base = agg::renderer_base<pixfmt_type>;
-
-        using renderer_type = agg::renderer_scanline_aa_alpha<ren_base,
-                                                              agg::span_allocator<agg::rgba8>,
-                                                              span_gen_type>;
-        mapnik::image_rgba8 const& image = marker.get_data();
-
-
-        agg::rendering_buffer buf(current_buffer_->bytes(), current_buffer_->width(),
-                                  current_buffer_->height(), current_buffer_->row_size());
-        ras_ptr_->reset();
-        value_double gamma = get<value_double, keys::gamma>(sym_, feature_, common_.vars_);
-        gamma_method_enum gamma_method = get<gamma_method_enum, keys::gamma_method>(sym_, feature_, common_.vars_);
-        if (gamma != gamma_ || gamma_method != gamma_method_)
-        {
-            set_gamma_method(ras_ptr_, gamma, gamma_method);
-            gamma_method_ = gamma_method;
-            gamma_ = gamma;
-        }
-
-        value_bool clip = get<value_bool, keys::clip>(sym_, feature_, common_.vars_);
-        value_double opacity = get<double, keys::opacity>(sym_, feature_, common_.vars_);
-        value_double simplify_tolerance = get<value_double, keys::simplify_tolerance>(sym_, feature_, common_.vars_);
-        value_double smooth = get<value_double, keys::smooth>(sym_, feature_, common_.vars_);
-
-        box2d<double> clip_box = clipping_extent(common_);
-
-
-        pixfmt_type pixf(buf);
-        pixf.comp_op(static_cast<agg::comp_op_e>(get<composite_mode_e, keys::comp_op>(sym_, feature_, common_.vars_)));
-        ren_base renb(pixf);
-
-        unsigned w = image.width();
-        unsigned h = image.height();
-        agg::rendering_buffer pattern_rbuf((agg::int8u*)image.bytes(),w,h,w*4);
-        agg::pixfmt_rgba32_pre pixf_pattern(pattern_rbuf);
-        img_source_type img_src(pixf_pattern);
-
-        pattern_alignment_enum alignment = get<pattern_alignment_enum, keys::alignment>(sym_, feature_, common_.vars_);
-        unsigned offset_x=0;
-        unsigned offset_y=0;
-
-        if (alignment == LOCAL_ALIGNMENT)
-        {
-            double x0 = 0;
-            double y0 = 0;
-            using apply_local_alignment = detail::apply_local_alignment;
-            apply_local_alignment apply(common_.t_,prj_trans_, clip_box, x0, y0);
-            util::apply_visitor(geometry::vertex_processor<apply_local_alignment>(apply), feature_.get_geometry());
 
             offset_x = unsigned(current_buffer_->width() - x0);
             offset_y = unsigned(current_buffer_->height() - y0);
@@ -282,7 +193,6 @@ struct agg_renderer_process_visitor_p
         agg::render_scanlines(*ras_ptr_, sl, rp);
     }
 
-private:
     renderer_common & common_;
     buffer_type * current_buffer_;
     std::unique_ptr<rasterizer> const& ras_ptr_;
diff --git a/src/group/group_layout_manager.cpp b/src/group/group_layout_manager.cpp
index ad9aaad..a6b60d0 100644
--- a/src/group/group_layout_manager.cpp
+++ b/src/group/group_layout_manager.cpp
@@ -90,30 +90,26 @@ struct process_layout
             return;
         }
 
-        bound_box layout_box;
-        int middle_ifirst = safe_cast<int>((member_boxes_.size() - 1) >> 1);
-        int top_i = 0;
-        int bottom_i = 0;
-        if (middle_ifirst % 2 == 0)
-        {
-            layout_box = make_horiz_pair(0, 0.0, 0, x_margin, layout.get_max_difference());
-            top_i = middle_ifirst - 2;
-            bottom_i = middle_ifirst + 2;
-        }
-        else
+        auto max_diff = layout.get_max_difference();
+        auto layout_box = make_horiz_pair(0, 0.0, 0, x_margin, max_diff);
+        auto y_shift = 0.5 * layout_box.height();
+
+        for (size_t i = 2; i < member_boxes_.size(); i += 2)
         {
-            top_i = middle_ifirst - 1;
-            bottom_i = middle_ifirst + 1;
+            auto y = layout_box.maxy() + y_margin;
+            auto pair_box = make_horiz_pair(i, y, 1, x_margin, max_diff);
+            layout_box.expand_to_include(pair_box);
         }
 
-        while (bottom_i >= 0 && top_i >= 0 && top_i < static_cast<int>(member_offsets_.size()))
+        // layout_box.center corresponds to the center of the first row;
+        // shift offsets so that the whole group is centered vertically
+
+        y_shift -= 0.5 * layout_box.height();
+
+        for (auto & offset : member_offsets_)
         {
-            layout_box.expand_to_include(make_horiz_pair(static_cast<std::size_t>(top_i), layout_box.miny() - y_margin, -1, x_margin, layout.get_max_difference()));
-            layout_box.expand_to_include(make_horiz_pair(static_cast<std::size_t>(bottom_i), layout_box.maxy() + y_margin, 1, x_margin, layout.get_max_difference()));
-            top_i -= 2;
-            bottom_i += 2;
+            offset.y += y_shift;
         }
-
     }
 
 private:
@@ -146,12 +142,12 @@ private:
     // stores corresponding offset, and returns modified bounding box
     bound_box box_offset_align(size_t i, double x, double y, int x_dir, int y_dir) const
     {
-        bound_box const& box = member_boxes_[i];
-        pixel_position offset((x_dir == 0 ? x - input_origin_.x : x - (x_dir < 0 ? box.maxx() : box.minx())),
-                             (y_dir == 0 ? y - input_origin_.y : y - (y_dir < 0 ? box.maxy() : box.miny())));
-
-        member_offsets_[i] = offset;
-        return bound_box(box.minx() + offset.x, box.miny() + offset.y, box.maxx() + offset.x, box.maxy() + offset.y);
+        auto box = member_boxes_[i];
+        auto & offset = member_offsets_[i];
+        offset.x = x - (x_dir == 0 ? input_origin_.x : (x_dir < 0 ? box.maxx() : box.minx()));
+        offset.y = y - (y_dir == 0 ? input_origin_.y : (y_dir < 0 ? box.maxy() : box.miny()));
+        box.move(offset.x, offset.y);
+        return box;
     }
 };
 
diff --git a/src/image.cpp b/src/image.cpp
index 5141860..9772fb7 100644
--- a/src/image.cpp
+++ b/src/image.cpp
@@ -88,7 +88,6 @@ template struct MAPNIK_DECL image_dimensions<65535>;
 
 } // end ns detail
 
-template class MAPNIK_DECL image<null_t>;
 template class MAPNIK_DECL image<rgba8_t>;
 template class MAPNIK_DECL image<gray8_t>;
 template class MAPNIK_DECL image<gray8s_t>;
diff --git a/src/image_util_jpeg.cpp b/src/image_util_jpeg.cpp
index 13860fd..32d1979 100644
--- a/src/image_util_jpeg.cpp
+++ b/src/image_util_jpeg.cpp
@@ -119,7 +119,6 @@ void jpeg_saver::operator() (T const& image) const
     throw image_writer_exception("Mapnik does not support jpeg grayscale images");
 }
 
-template void jpeg_saver::operator()<image_rgba8> (image_rgba8 const& image) const;
 template void jpeg_saver::operator()<image_gray8> (image_gray8 const& image) const;
 template void jpeg_saver::operator()<image_gray8s> (image_gray8s const& image) const;
 template void jpeg_saver::operator()<image_gray16> (image_gray16 const& image) const;
@@ -130,7 +129,6 @@ template void jpeg_saver::operator()<image_gray32f> (image_gray32f const& image)
 template void jpeg_saver::operator()<image_gray64> (image_gray64 const& image) const;
 template void jpeg_saver::operator()<image_gray64s> (image_gray64s const& image) const;
 template void jpeg_saver::operator()<image_gray64f> (image_gray64f const& image) const;
-template void jpeg_saver::operator()<image_view_rgba8> (image_view_rgba8 const& image) const;
 template void jpeg_saver::operator()<image_view_gray8> (image_view_gray8 const& image) const;
 template void jpeg_saver::operator()<image_view_gray8s> (image_view_gray8s const& image) const;
 template void jpeg_saver::operator()<image_view_gray16> (image_view_gray16 const& image) const;
diff --git a/src/image_util_png.cpp b/src/image_util_png.cpp
index f09d580..322acd2 100644
--- a/src/image_util_png.cpp
+++ b/src/image_util_png.cpp
@@ -316,7 +316,6 @@ void png_saver_pal::operator() (T const& image) const
 #endif
 }
 
-template void png_saver::operator()<image_rgba8> (image_rgba8 const& image) const;
 template void png_saver::operator()<image_gray8> (image_gray8 const& image) const;
 template void png_saver::operator()<image_gray8s> (image_gray8s const& image) const;
 template void png_saver::operator()<image_gray16> (image_gray16 const& image) const;
@@ -327,7 +326,6 @@ template void png_saver::operator()<image_gray32f> (image_gray32f const& image)
 template void png_saver::operator()<image_gray64> (image_gray64 const& image) const;
 template void png_saver::operator()<image_gray64s> (image_gray64s const& image) const;
 template void png_saver::operator()<image_gray64f> (image_gray64f const& image) const;
-template void png_saver::operator()<image_view_rgba8> (image_view_rgba8 const& image) const;
 template void png_saver::operator()<image_view_gray8> (image_view_gray8 const& image) const;
 template void png_saver::operator()<image_view_gray8s> (image_view_gray8s const& image) const;
 template void png_saver::operator()<image_view_gray16> (image_view_gray16 const& image) const;
@@ -338,7 +336,6 @@ template void png_saver::operator()<image_view_gray32f> (image_view_gray32f cons
 template void png_saver::operator()<image_view_gray64> (image_view_gray64 const& image) const;
 template void png_saver::operator()<image_view_gray64s> (image_view_gray64s const& image) const;
 template void png_saver::operator()<image_view_gray64f> (image_view_gray64f const& image) const;
-template void png_saver_pal::operator()<image_rgba8> (image_rgba8 const& image) const;
 template void png_saver_pal::operator()<image_gray8> (image_gray8 const& image) const;
 template void png_saver_pal::operator()<image_gray8s> (image_gray8s const& image) const;
 template void png_saver_pal::operator()<image_gray16> (image_gray16 const& image) const;
@@ -349,7 +346,6 @@ template void png_saver_pal::operator()<image_gray32f> (image_gray32f const& ima
 template void png_saver_pal::operator()<image_gray64> (image_gray64 const& image) const;
 template void png_saver_pal::operator()<image_gray64s> (image_gray64s const& image) const;
 template void png_saver_pal::operator()<image_gray64f> (image_gray64f const& image) const;
-template void png_saver_pal::operator()<image_view_rgba8> (image_view_rgba8 const& image) const;
 template void png_saver_pal::operator()<image_view_gray8> (image_view_gray8 const& image) const;
 template void png_saver_pal::operator()<image_view_gray8s> (image_view_gray8s const& image) const;
 template void png_saver_pal::operator()<image_view_gray16> (image_view_gray16 const& image) const;
diff --git a/src/image_util_webp.cpp b/src/image_util_webp.cpp
index c7b96ac..99e6690 100644
--- a/src/image_util_webp.cpp
+++ b/src/image_util_webp.cpp
@@ -360,7 +360,6 @@ void webp_saver::operator() (T const& image) const
     throw image_writer_exception("Mapnik does not support webp grayscale images");
 }
 
-template void webp_saver::operator()<image_rgba8> (image_rgba8 const& image) const;
 template void webp_saver::operator()<image_gray8> (image_gray8 const& image) const;
 template void webp_saver::operator()<image_gray8s> (image_gray8s const& image) const;
 template void webp_saver::operator()<image_gray16> (image_gray16 const& image) const;
@@ -371,7 +370,6 @@ template void webp_saver::operator()<image_gray32f> (image_gray32f const& image)
 template void webp_saver::operator()<image_gray64> (image_gray64 const& image) const;
 template void webp_saver::operator()<image_gray64s> (image_gray64s const& image) const;
 template void webp_saver::operator()<image_gray64f> (image_gray64f const& image) const;
-template void webp_saver::operator()<image_view_rgba8> (image_view_rgba8 const& image) const;
 template void webp_saver::operator()<image_view_gray8> (image_view_gray8 const& image) const;
 template void webp_saver::operator()<image_view_gray8s> (image_view_gray8s const& image) const;
 template void webp_saver::operator()<image_view_gray16> (image_view_gray16 const& image) const;
diff --git a/src/renderer_common/render_group_symbolizer.cpp b/src/renderer_common/render_group_symbolizer.cpp
index 9892dfc..8e3aba9 100644
--- a/src/renderer_common/render_group_symbolizer.cpp
+++ b/src/renderer_common/render_group_symbolizer.cpp
@@ -66,7 +66,7 @@ void render_group_symbolizer(group_symbolizer const& sym,
 
     // keep track of which lists of render thunks correspond to
     // entries in the group_layout_manager.
-    std::vector<render_thunk_list> layout_thunks;
+    std::list<render_thunk_list> layout_thunks;
 
     // layout manager to store and arrange bboxes of matched features
     group_layout_manager layout_manager(props->get_layout());
@@ -182,11 +182,13 @@ void render_group_symbolizer(group_symbolizer const& sym,
     pixel_position_list const& positions = helper.get();
     for (pixel_position const& pos : positions)
     {
-        for (size_t layout_i = 0; layout_i < layout_thunks.size(); ++layout_i)
+        size_t layout_i = 0;
+        for (auto const& thunks : layout_thunks)
         {
             pixel_position const& offset = layout_manager.offset_at(layout_i);
             pixel_position render_offset = pos + offset;
-            render_thunks.render_list(layout_thunks[layout_i], render_offset);
+            render_thunks.render_list(thunks, render_offset);
+            ++layout_i;
         }
     }
 }
diff --git a/src/renderer_common/render_thunk_extractor.cpp b/src/renderer_common/render_thunk_extractor.cpp
index c437262..1a5d1b8 100644
--- a/src/renderer_common/render_thunk_extractor.cpp
+++ b/src/renderer_common/render_thunk_extractor.cpp
@@ -55,7 +55,7 @@ struct thunk_markers_renderer_context : markers_renderer_context
     {
         vector_marker_render_thunk thunk(src, attrs, marker_tr, params.opacity,
                                          comp_op_, params.snap_to_pixels);
-        thunks_.push_back(std::make_unique<render_thunk>(std::move(thunk)));
+        thunks_.emplace_back(std::move(thunk));
     }
 
     virtual void render_marker(image_rgba8 const& src,
@@ -64,7 +64,7 @@ struct thunk_markers_renderer_context : markers_renderer_context
     {
         raster_marker_render_thunk thunk(src, marker_tr, params.opacity,
                                          comp_op_, params.snap_to_pixels);
-        thunks_.push_back(std::make_unique<render_thunk>(std::move(thunk)));
+        thunks_.emplace_back(std::move(thunk));
     }
 
 private:
@@ -128,7 +128,7 @@ void render_thunk_extractor::extract_text_thunk(text_render_thunk::helper_ptr &&
     halo_rasterizer_enum halo_rasterizer = get<halo_rasterizer_enum>(sym, keys::halo_rasterizer, feature_, common_.vars_, HALO_RASTERIZER_FULL);
 
     text_render_thunk thunk(std::move(helper), opacity, comp_op, halo_rasterizer);
-    thunks_.push_back(std::make_unique<render_thunk>(std::move(thunk)));
+    thunks_.emplace_back(std::move(thunk));
 
     update_box();
 }
diff --git a/test/standalone/font_registration_test.cpp b/test/standalone/font_registration_test.cpp
index db56a30..a5ba0b2 100644
--- a/test/standalone/font_registration_test.cpp
+++ b/test/standalone/font_registration_test.cpp
@@ -40,26 +40,21 @@ SECTION("registration") {
         REQUIRE( mapnik::util::is_directory( fontdir ) );
 
         // test map cached fonts
-        REQUIRE( m.register_fonts(fontdir , false ) );
-        REQUIRE( m.get_font_memory_cache().size() == 0 );
-        REQUIRE( m.get_font_file_mapping().size() == 1 );
-        REQUIRE( m.load_fonts() );
-        REQUIRE( m.get_font_memory_cache().size() == 1 );
         REQUIRE( m.register_fonts(fontdir , true ) );
-        REQUIRE( m.get_font_file_mapping().size() == 23 );
+        REQUIRE( m.get_font_file_mapping().size() == 22 );
         REQUIRE( m.load_fonts() );
-        REQUIRE( m.get_font_memory_cache().size() == 23 );
+        REQUIRE( m.get_font_memory_cache().size() == 22 );
 
         // copy discards memory cache but not file mapping
         mapnik::Map m2(m);
         REQUIRE( m2.get_font_memory_cache().size() == 0 );
-        REQUIRE( m2.get_font_file_mapping().size() == 23 );
+        REQUIRE( m2.get_font_file_mapping().size() == 22 );
         REQUIRE( m2.load_fonts() );
-        REQUIRE( m2.get_font_memory_cache().size() == 23 );
+        REQUIRE( m2.get_font_memory_cache().size() == 22 );
 
         // test font-directory from XML
         mapnik::Map m3(1,1);
-        mapnik::load_map_string(m3,"<Map font-directory=\"fonts/\"></Map>");
+        mapnik::load_map_string(m3,"<Map font-directory=\"test/data/fonts/Noto/\"></Map>");
         REQUIRE( m3.get_font_memory_cache().size() == 0 );
         REQUIRE( m3.load_fonts() );
         REQUIRE( m3.get_font_memory_cache().size() == 1 );
@@ -97,22 +92,11 @@ SECTION("registration") {
         // now restore the original severity
         logger.set_severity(original_severity);
 
-        // register unifont, since we know it sits in the root fonts/ dir
-        REQUIRE( mapnik::freetype_engine::register_fonts(fontdir) );
-        face_names = mapnik::freetype_engine::face_names();
-        REQUIRE( face_names.size() > 0 );
-        REQUIRE( face_names.size() == 1 );
-
-        // re-register unifont, should not have any affect
-        REQUIRE( mapnik::freetype_engine::register_fonts(fontdir, false) );
-        face_names = mapnik::freetype_engine::face_names();
-        REQUIRE( face_names.size() == 1 );
-
         // single dejavu font in separate location
         std::string dejavu_bold_oblique("test/data/fonts/DejaVuSansMono-BoldOblique.ttf");
         REQUIRE( mapnik::freetype_engine::register_font(dejavu_bold_oblique) );
         face_names = mapnik::freetype_engine::face_names();
-        REQUIRE( face_names.size() == 2 );
+        REQUIRE( face_names.size() == 1 );
 
         // now, inspect font mapping and confirm the correct 'DejaVu Sans Mono Bold Oblique' is registered
         using font_file_mapping = std::map<std::string, std::pair<int,std::string> >;
@@ -132,7 +116,7 @@ SECTION("registration") {
         // recurse to find all dejavu fonts
         REQUIRE( mapnik::freetype_engine::register_fonts(fontdir, true) );
         face_names = mapnik::freetype_engine::face_names();
-        REQUIRE( face_names.size() == 23 );
+        REQUIRE( face_names.size() == 22 );
 
         // we should have re-registered 'DejaVu Sans Mono Bold Oblique' again,
         // but now at a new path
@@ -154,7 +138,7 @@ SECTION("registration") {
         mapnik::Map m4(1,1);
         REQUIRE( m4.register_fonts(fontdir , true ) );
         REQUIRE( m4.get_font_memory_cache().size() == 0 );
-        REQUIRE( m4.get_font_file_mapping().size() == 23 );
+        REQUIRE( m4.get_font_file_mapping().size() == 22 );
         REQUIRE( !m4.load_fonts() );
         REQUIRE( m4.get_font_memory_cache().size() == 0 );
         REQUIRE( m4.register_fonts(dejavu_bold_oblique, false) );
@@ -166,7 +150,7 @@ SECTION("registration") {
         // https://github.com/mapnik/mapnik/issues/2274
         REQUIRE( mapnik::freetype_engine::register_font("test/data/fonts/NotoSans-Regular.ttc") );
         face_names = mapnik::freetype_engine::face_names();
-        REQUIRE( face_names.size() == 25 );
+        REQUIRE( face_names.size() == 24 );
 
         // now blindly register as many system fonts as possible
         // the goal here to make sure we don't crash
@@ -179,7 +163,7 @@ SECTION("registration") {
         // windows
         mapnik::freetype_engine::register_fonts("C:\\Windows\\Fonts", true);
         face_names = mapnik::freetype_engine::face_names();
-        REQUIRE( face_names.size() > 23 );
+        REQUIRE( face_names.size() > 22 );
     }
     catch (std::exception const & ex)
     {
diff --git a/test/unit/core/conversions_test.cpp b/test/unit/core/conversions_test.cpp
index 43592af..9df4d93 100644
--- a/test/unit/core/conversions_test.cpp
+++ b/test/unit/core/conversions_test.cpp
@@ -284,16 +284,19 @@ SECTION("to string") {
         REQUIRE( string2bool("true",val) );
         REQUIRE( val == true );
 
-        // mapnik::value hashability
-        using values_container = std::unordered_map<mapnik::value, unsigned>;
+        // mapnik::value hash() and operator== works for all T in value<Types...>
+        mapnik::transcoder tr("utf8");
+        using values_container = std::unordered_map<mapnik::value, mapnik::value>;
         values_container vc;
-        mapnik::value val2(1);
-        vc[val2] = 1;
-        REQUIRE( vc[1] == static_cast<int>(1) );
+        mapnik::value keys[5] = {true, 123456789, 3.14159f, tr.transcode("Мапник"), mapnik::value_null()} ;
+        for (auto const& k : keys)
+        {
+            vc.insert({k, k});
+            REQUIRE( vc[k] == k );
+        }
 
         // mapnik::value << to ostream
         std::stringstream s;
-        mapnik::transcoder tr("utf-8");
         mapnik::value_unicode_string ustr = tr.transcode("hello world!");
         mapnik::value streamable(ustr);
         s << streamable;
diff --git a/test/unit/datasource/geojson.cpp b/test/unit/datasource/geojson.cpp
index bcc9fa2..b036684 100644
--- a/test/unit/datasource/geojson.cpp
+++ b/test/unit/datasource/geojson.cpp
@@ -115,6 +115,58 @@ TEST_CASE("geojson") {
             }
         }
 
+        SECTION("GeoJSON num_features_to_query")
+        {
+            std::string filename = "./test/data/json/featurecollection-multipleprops.geojson";
+            for (mapnik::value_integer num_features_to_query : { mapnik::value_integer(-1),
+                        mapnik::value_integer(0),
+                        mapnik::value_integer(1),
+                        mapnik::value_integer(2),
+                        mapnik::value_integer(3),
+                        std::numeric_limits<mapnik::value_integer>::max()})
+            {
+                for (auto create_index : { true, false })
+                {
+                    if (create_index)
+                    {
+                        int ret = create_disk_index(filename);
+                        int ret_posix = (ret >> 8) & 0x000000ff;
+                        INFO(ret);
+                        INFO(ret_posix);
+                        CHECK(mapnik::util::exists(filename + ".index"));
+                    }
+
+                    for (auto cache_features : {true, false})
+                    {
+                        mapnik::parameters params;
+                        params["type"] = "geojson";
+                        params["file"] = filename;
+                        params["cache_features"] = cache_features;
+                        params["num_features_to_query"] = num_features_to_query;
+                        auto ds = mapnik::datasource_cache::instance().create(params);
+                        CHECK(ds != nullptr);
+                        auto fields = ds->get_descriptor().get_descriptors();
+                        if (!create_index && cache_features)
+                        {
+                            // when there's no index and caching is enabled descriptor is always fully initialised
+                            REQUIRE(fields.size() == 2);
+                        }
+                        else
+                        {
+                            // at least 1 feature should be queried
+                            REQUIRE(fields.size() == std::min(std::max(mapnik::value_integer(1), num_features_to_query),
+                                                              mapnik::value_integer(2)));
+                        }
+                    }
+                    // cleanup
+                    if (create_index && mapnik::util::exists(filename + ".index"))
+                    {
+                        mapnik::util::remove(filename + ".index");
+                    }
+                }
+            }
+        }
+
         SECTION("GeoJSON attribute descriptors are alphabetically ordered")
         {
             for (auto cache_features : {true, false})
diff --git a/utils/mapnik-config/build.py b/utils/mapnik-config/build.py
index 35a730b..9ffd731 100644
--- a/utils/mapnik-config/build.py
+++ b/utils/mapnik-config/build.py
@@ -159,7 +159,7 @@ configuration = {
     "mapnik_bundled_icu_data":mapnik_bundled_icu_data,
 }
 
-## if we are statically linking depedencies
+## if we are statically linking dependencies
 ## then they do not need to be reported in ldflags
 #if env['RUNTIME_LINK'] == 'static':
 #    configuration['ldflags'] = ''

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/mapnik.git



More information about the Pkg-grass-devel mailing list