From dfa7e3747626c09d03c080394ba2dfb3169874cc Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Tue, 7 Aug 2018 15:06:55 -0400 Subject: [build] Fix CI failure when master and release branch are identical The search for branches containing the previous hash could return multiple matches on different lines, if, for instance, a newly-cut release branch were identical to master. --- scripts/environment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/environment.js b/scripts/environment.js index 9777377f19..bb0be77886 100755 --- a/scripts/environment.js +++ b/scripts/environment.js @@ -24,7 +24,7 @@ if (pr) { } else { const head = process.env['CIRCLE_SHA1']; for (const sha of execSync(`git rev-list --max-count=10 ${head}`).toString().trim().split('\n')) { - const base = execSync(`git branch -r --contains ${sha} origin/master origin/release-*`).toString().trim().replace(/^origin\//, ''); + const base = execSync(`git branch -r --contains ${sha} origin/master origin/release-*`).toString().replace(/$\n.*/m, '').trim().replace(/^origin\//, ''); if (base) { const mergeBase = execSync(`git merge-base origin/${base} ${head}`).toString().trim(); console.log(`export CIRCLE_TARGET_BRANCH=${base}`); -- cgit v1.2.1 From fd73dea05e645041cf27a28ba67ce37eb6d4c6bc Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Tue, 7 Aug 2018 20:01:05 -0400 Subject: Handle >2 branches by switching to split[0] --- scripts/environment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/environment.js b/scripts/environment.js index bb0be77886..0468be3720 100755 --- a/scripts/environment.js +++ b/scripts/environment.js @@ -24,7 +24,7 @@ if (pr) { } else { const head = process.env['CIRCLE_SHA1']; for (const sha of execSync(`git rev-list --max-count=10 ${head}`).toString().trim().split('\n')) { - const base = execSync(`git branch -r --contains ${sha} origin/master origin/release-*`).toString().replace(/$\n.*/m, '').trim().replace(/^origin\//, ''); + const base = execSync(`git branch -r --contains ${sha} origin/master origin/release-*`).toString().split('\n')[0].trim().replace(/^origin\//, ''); if (base) { const mergeBase = execSync(`git merge-base origin/${base} ${head}`).toString().trim(); console.log(`export CIRCLE_TARGET_BRANCH=${base}`); -- cgit v1.2.1 From 15a26231474d08e3884e424601b609c53d7ef086 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Tue, 7 Aug 2018 14:45:48 +0300 Subject: [core] Add lineMetrics to GeoJSONOptions This patch also bumps geojson-vt-cpp version to 6.6.0, which enables the `lineMetrics` option. --- cmake/mason-dependencies.cmake | 2 +- include/mbgl/style/sources/geojson_source.hpp | 1 + src/mbgl/style/conversion/geojson_options.cpp | 10 ++++++++++ src/mbgl/style/sources/geojson_source_impl.cpp | 1 + test/style/conversion/geojson_options.test.cpp | 5 ++++- 5 files changed, 17 insertions(+), 2 deletions(-) diff --git a/cmake/mason-dependencies.cmake b/cmake/mason-dependencies.cmake index d4e0378804..cffce0a440 100644 --- a/cmake/mason-dependencies.cmake +++ b/cmake/mason-dependencies.cmake @@ -5,7 +5,7 @@ mason_use(variant VERSION 1.1.4 HEADER_ONLY) mason_use(unique_resource VERSION cba309e HEADER_ONLY) mason_use(rapidjson VERSION 1.1.0 HEADER_ONLY) mason_use(boost VERSION 1.65.1 HEADER_ONLY) -mason_use(geojsonvt VERSION 6.5.1 HEADER_ONLY) +mason_use(geojsonvt VERSION 6.6.0 HEADER_ONLY) mason_use(supercluster VERSION 0.2.2 HEADER_ONLY) mason_use(kdbush VERSION 0.1.1-1 HEADER_ONLY) mason_use(earcut VERSION 0.12.4 HEADER_ONLY) diff --git a/include/mbgl/style/sources/geojson_source.hpp b/include/mbgl/style/sources/geojson_source.hpp index 372e7c7a78..a03b910279 100644 --- a/include/mbgl/style/sources/geojson_source.hpp +++ b/include/mbgl/style/sources/geojson_source.hpp @@ -18,6 +18,7 @@ struct GeoJSONOptions { uint16_t tileSize = util::tileSize; uint16_t buffer = 128; double tolerance = 0.375; + bool lineMetrics = false; // Supercluster options bool cluster = false; diff --git a/src/mbgl/style/conversion/geojson_options.cpp b/src/mbgl/style/conversion/geojson_options.cpp index 52a5030c34..77340e5f1d 100644 --- a/src/mbgl/style/conversion/geojson_options.cpp +++ b/src/mbgl/style/conversion/geojson_options.cpp @@ -77,6 +77,16 @@ optional Converter::operator()(const Convertible } } + const auto lineMetricsValue = objectMember(value, "lineMetrics"); + if (lineMetricsValue) { + if (toBool(*lineMetricsValue)) { + options.lineMetrics = *toBool(*lineMetricsValue); + } else { + error = { "GeoJSON source lineMetrics value must be a boolean" }; + return nullopt; + } + } + return { options }; } diff --git a/src/mbgl/style/sources/geojson_source_impl.cpp b/src/mbgl/style/sources/geojson_source_impl.cpp index fd6d7d3013..5ec3909d3e 100644 --- a/src/mbgl/style/sources/geojson_source_impl.cpp +++ b/src/mbgl/style/sources/geojson_source_impl.cpp @@ -64,6 +64,7 @@ GeoJSONSource::Impl::Impl(const Impl& other, const GeoJSON& geoJSON) vtOptions.extent = util::EXTENT; vtOptions.buffer = ::round(scale * options.buffer); vtOptions.tolerance = scale * options.tolerance; + vtOptions.lineMetrics = options.lineMetrics; data = std::make_unique(geoJSON, vtOptions); } } diff --git a/test/style/conversion/geojson_options.test.cpp b/test/style/conversion/geojson_options.test.cpp index 4c5a0c9aa4..181189775b 100644 --- a/test/style/conversion/geojson_options.test.cpp +++ b/test/style/conversion/geojson_options.test.cpp @@ -32,6 +32,7 @@ TEST(GeoJSONOptions, RetainsDefaults) { ASSERT_EQ(converted.maxzoom, defaults.maxzoom); ASSERT_EQ(converted.buffer, defaults.buffer); ASSERT_EQ(converted.tolerance, defaults.tolerance); + ASSERT_EQ(converted.lineMetrics, defaults.lineMetrics); // Supercluster ASSERT_EQ(converted.cluster, defaults.cluster); @@ -47,7 +48,8 @@ TEST(GeoJSONOptions, FullConversion) { "tolerance": 3, "cluster": true, "clusterRadius": 4, - "clusterMaxZoom": 5 + "clusterMaxZoom": 5, + "lineMetrics": true })JSON", error); // GeoJSON-VT @@ -55,6 +57,7 @@ TEST(GeoJSONOptions, FullConversion) { ASSERT_EQ(converted.maxzoom, 1); ASSERT_EQ(converted.buffer, 2); ASSERT_EQ(converted.tolerance, 3); + ASSERT_TRUE(converted.lineMetrics); // Supercluster ASSERT_EQ(converted.cluster, true); -- cgit v1.2.1 From 83bd4c213583058340d0606f2d24c85489091ccf Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 24 Jul 2018 20:58:54 +0300 Subject: [core] Replace remaining dynamic_cast with static_cast --- src/mbgl/renderer/layers/render_hillshade_layer.cpp | 4 ++-- src/mbgl/renderer/layers/render_symbol_layer.cpp | 2 +- src/mbgl/style/layers/circle_layer_impl.cpp | 2 +- src/mbgl/style/layers/fill_extrusion_layer_impl.cpp | 2 +- src/mbgl/style/layers/fill_layer_impl.cpp | 2 +- src/mbgl/style/layers/heatmap_layer_impl.cpp | 2 +- src/mbgl/style/layers/line_layer_impl.cpp | 2 +- src/mbgl/style/layers/symbol_layer_impl.cpp | 2 +- src/mbgl/text/placement.cpp | 2 +- src/mbgl/tile/geometry_tile.cpp | 2 +- src/mbgl/tile/raster_dem_tile.cpp | 2 +- src/mbgl/tile/raster_tile.cpp | 2 +- src/mbgl/tile/tile.cpp | 10 +++++++++- src/mbgl/tile/tile.hpp | 9 ++++++++- test/map/map.test.cpp | 2 +- 15 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/mbgl/renderer/layers/render_hillshade_layer.cpp b/src/mbgl/renderer/layers/render_hillshade_layer.cpp index 25eef98fcf..8bcd3f1837 100644 --- a/src/mbgl/renderer/layers/render_hillshade_layer.cpp +++ b/src/mbgl/renderer/layers/render_hillshade_layer.cpp @@ -59,8 +59,8 @@ bool RenderHillshadeLayer::hasTransition() const { void RenderHillshadeLayer::render(PaintParameters& parameters, RenderSource* src) { if (parameters.pass != RenderPass::Translucent && parameters.pass != RenderPass::Pass3D) return; - - RenderRasterDEMSource* demsrc = dynamic_cast(src); + + RenderRasterDEMSource* demsrc = static_cast(src); const uint8_t TERRAIN_RGB_MAXZOOM = 15; const uint8_t maxzoom = demsrc != nullptr ? demsrc->getMaxZoom() : TERRAIN_RGB_MAXZOOM; diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp index 63fcb6cfd5..f9e4e7c043 100644 --- a/src/mbgl/renderer/layers/render_symbol_layer.cpp +++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp @@ -126,7 +126,7 @@ void RenderSymbolLayer::render(PaintParameters& parameters, RenderSource*) { ); }; - assert(dynamic_cast(&tile.tile)); + assert(tile.tile.kind == Tile::Kind::Geometry); GeometryTile& geometryTile = static_cast(tile.tile); if (bucket.hasIconData()) { diff --git a/src/mbgl/style/layers/circle_layer_impl.cpp b/src/mbgl/style/layers/circle_layer_impl.cpp index 69f574cd6b..358598e09c 100644 --- a/src/mbgl/style/layers/circle_layer_impl.cpp +++ b/src/mbgl/style/layers/circle_layer_impl.cpp @@ -4,7 +4,7 @@ namespace mbgl { namespace style { bool CircleLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { - assert(dynamic_cast(&other)); + assert(other.type == LayerType::Circle); const auto& impl = static_cast(other); return filter != impl.filter || visibility != impl.visibility || diff --git a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp index d37c2ad29b..357ea3e973 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer_impl.cpp @@ -4,7 +4,7 @@ namespace mbgl { namespace style { bool FillExtrusionLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { - assert(dynamic_cast(&other)); + assert(other.type == LayerType::FillExtrusion); const auto& impl = static_cast(other); return filter != impl.filter || visibility != impl.visibility || diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp index 0dc7ed14d5..a8ba1b693b 100644 --- a/src/mbgl/style/layers/fill_layer_impl.cpp +++ b/src/mbgl/style/layers/fill_layer_impl.cpp @@ -4,7 +4,7 @@ namespace mbgl { namespace style { bool FillLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { - assert(dynamic_cast(&other)); + assert(other.type == LayerType::Fill); const auto& impl = static_cast(other); return filter != impl.filter || visibility != impl.visibility || diff --git a/src/mbgl/style/layers/heatmap_layer_impl.cpp b/src/mbgl/style/layers/heatmap_layer_impl.cpp index af20888d9d..8fd0cf72b2 100644 --- a/src/mbgl/style/layers/heatmap_layer_impl.cpp +++ b/src/mbgl/style/layers/heatmap_layer_impl.cpp @@ -4,7 +4,7 @@ namespace mbgl { namespace style { bool HeatmapLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { - assert(dynamic_cast(&other)); + assert(other.type == LayerType::Heatmap); const auto& impl = static_cast(other); return filter != impl.filter || visibility != impl.visibility || diff --git a/src/mbgl/style/layers/line_layer_impl.cpp b/src/mbgl/style/layers/line_layer_impl.cpp index bee88d6a47..68cd3a8f49 100644 --- a/src/mbgl/style/layers/line_layer_impl.cpp +++ b/src/mbgl/style/layers/line_layer_impl.cpp @@ -4,7 +4,7 @@ namespace mbgl { namespace style { bool LineLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { - assert(dynamic_cast(&other)); + assert(other.type == LayerType::Line); const auto& impl = static_cast(other); return filter != impl.filter || visibility != impl.visibility || diff --git a/src/mbgl/style/layers/symbol_layer_impl.cpp b/src/mbgl/style/layers/symbol_layer_impl.cpp index b59768725d..753b2fa184 100644 --- a/src/mbgl/style/layers/symbol_layer_impl.cpp +++ b/src/mbgl/style/layers/symbol_layer_impl.cpp @@ -4,7 +4,7 @@ namespace mbgl { namespace style { bool SymbolLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const { - assert(dynamic_cast(&other)); + assert(other.type == LayerType::Symbol); const auto& impl = static_cast(other); return filter != impl.filter || visibility != impl.visibility || diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 16dd94b374..8bd92087b1 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -48,7 +48,7 @@ void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatri if (!renderTile.tile.isRenderable()) { continue; } - assert(dynamic_cast(&renderTile.tile)); + assert(renderTile.tile.kind == Tile::Kind::Geometry); GeometryTile& geometryTile = static_cast(renderTile.tile); auto bucket = renderTile.tile.getBucket(*symbolLayer.baseImpl); diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp index d686d8440b..90d4d07895 100644 --- a/src/mbgl/tile/geometry_tile.cpp +++ b/src/mbgl/tile/geometry_tile.cpp @@ -44,7 +44,7 @@ using namespace style; GeometryTile::GeometryTile(const OverscaledTileID& id_, std::string sourceID_, const TileParameters& parameters) - : Tile(id_), + : Tile(Kind::Geometry, id_), sourceID(std::move(sourceID_)), mailbox(std::make_shared(*Scheduler::GetCurrent())), worker(parameters.workerScheduler, diff --git a/src/mbgl/tile/raster_dem_tile.cpp b/src/mbgl/tile/raster_dem_tile.cpp index f29861ee71..751f69bad9 100644 --- a/src/mbgl/tile/raster_dem_tile.cpp +++ b/src/mbgl/tile/raster_dem_tile.cpp @@ -15,7 +15,7 @@ namespace mbgl { RasterDEMTile::RasterDEMTile(const OverscaledTileID& id_, const TileParameters& parameters, const Tileset& tileset) - : Tile(id_), + : Tile(Kind::RasterDEM, id_), loader(*this, id_, parameters, tileset), mailbox(std::make_shared(*Scheduler::GetCurrent())), worker(parameters.workerScheduler, diff --git a/src/mbgl/tile/raster_tile.cpp b/src/mbgl/tile/raster_tile.cpp index cc71c04ba1..1346f87ae5 100644 --- a/src/mbgl/tile/raster_tile.cpp +++ b/src/mbgl/tile/raster_tile.cpp @@ -15,7 +15,7 @@ namespace mbgl { RasterTile::RasterTile(const OverscaledTileID& id_, const TileParameters& parameters, const Tileset& tileset) - : Tile(id_), + : Tile(Kind::Raster, id_), loader(*this, id_, parameters, tileset), mailbox(std::make_shared(*Scheduler::GetCurrent())), worker(parameters.workerScheduler, diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp index b95944f10e..5a69df5b43 100644 --- a/src/mbgl/tile/tile.cpp +++ b/src/mbgl/tile/tile.cpp @@ -9,7 +9,7 @@ namespace mbgl { static TileObserver nullObserver; -Tile::Tile(OverscaledTileID id_) : id(std::move(id_)), observer(&nullObserver) { +Tile::Tile(Kind kind_, OverscaledTileID id_) : kind(kind_), id(std::move(id_)), observer(&nullObserver) { } Tile::~Tile() = default; @@ -27,6 +27,14 @@ void Tile::setTriedCache() { } void Tile::dumpDebugLogs() const { + std::string kindString; + switch (kind) { + case Kind::Geometry: kindString = "Geometry"; break; + case Kind::Raster: kindString = "Raster"; break; + case Kind::RasterDEM: kindString = "RasterDEM"; break; + default: kindString = "Unknown"; break; + } + Log::Info(Event::General, "Tile::Kind: %s", kindString.c_str()); Log::Info(Event::General, "Tile::id: %s", util::toString(id).c_str()); Log::Info(Event::General, "Tile::renderable: %s", isRenderable() ? "yes" : "no"); Log::Info(Event::General, "Tile::complete: %s", isComplete() ? "yes" : "no"); diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp index 5cf74abff5..70b2aa0371 100644 --- a/src/mbgl/tile/tile.hpp +++ b/src/mbgl/tile/tile.hpp @@ -35,7 +35,13 @@ class Context; class Tile : private util::noncopyable { public: - Tile(OverscaledTileID); + enum class Kind : uint8_t { + Geometry, + Raster, + RasterDEM + }; + + Tile(Kind, OverscaledTileID); virtual ~Tile(); void setObserver(TileObserver* observer); @@ -119,6 +125,7 @@ public: void dumpDebugLogs() const; + const Kind kind; OverscaledTileID id; optional modified; optional expires; diff --git a/test/map/map.test.cpp b/test/map/map.test.cpp index 8e2d9cb9cd..cb45c2900b 100644 --- a/test/map/map.test.cpp +++ b/test/map/map.test.cpp @@ -207,7 +207,7 @@ TEST(Map, SetStyleInvalidJSON) { EXPECT_TRUE(fail); auto observer = Log::removeObserver(); - auto flo = dynamic_cast(observer.get()); + auto flo = static_cast(observer.get()); EXPECT_EQ(1u, flo->count({ EventSeverity::Error, Event::ParseStyle, -1, "Failed to parse style: 0 - Invalid value." })); auto unchecked = flo->unchecked(); -- cgit v1.2.1 From 990b3b11b9427ffd86f693d3f4c3dd351891e5d0 Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Sat, 28 Jul 2018 14:56:26 +0300 Subject: [core] Replace Boost.Spirit with std::regex in CacheControl::parse() --- src/mbgl/util/http_header.cpp | 28 +++++++--------------------- test/storage/headers.test.cpp | 9 +++++++++ 2 files changed, 16 insertions(+), 21 deletions(-) diff --git a/src/mbgl/util/http_header.cpp b/src/mbgl/util/http_header.cpp index 4d9e2bf84c..da68b4a790 100644 --- a/src/mbgl/util/http_header.cpp +++ b/src/mbgl/util/http_header.cpp @@ -2,34 +2,20 @@ #include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunknown-pragmas" -#pragma GCC diagnostic ignored "-Wunused-parameter" -#pragma GCC diagnostic ignored "-Wshadow" -#pragma clang diagnostic push - -#pragma clang diagnostic ignored "-Wshorten-64-to-32" -#pragma clang diagnostic ignored "-Wunknown-warning-option" -#pragma clang diagnostic ignored "-Wtautological-constant-compare" -#include -#include -#include -#pragma clang diagnostic pop -#pragma GCC diagnostic pop +#include namespace mbgl { namespace http { CacheControl CacheControl::parse(const std::string& value) { - namespace qi = boost::spirit::qi; - namespace phoenix = boost::phoenix; + std::regex maxAgeRegex(R"((?:[^"]*"[^"]*[^\\]")*[^"]*max-age[\s]*=[\s]*([\d]+).*)"); + std::smatch maxAgeMatch; CacheControl result; - qi::phrase_parse(value.begin(), value.end(), ( - (qi::lit("must-revalidate") [ phoenix::ref(result.mustRevalidate) = true ]) | - (qi::lit("max-age") >> '=' >> qi::ulong_long [ phoenix::ref(result.maxAge) = qi::_1 ]) | - (*(('"' >> *(('\\' >> qi::char_) | (qi::char_ - '"')) >> '"') | (qi::char_ - '"' - ','))) - ) % ',', qi::ascii::space); + result.mustRevalidate = value.find("must-revalidate") != std::string::npos; + if (std::regex_match(value, maxAgeMatch, maxAgeRegex) && maxAgeMatch.size() == 2) { + result.maxAge = ::atoll(maxAgeMatch[1].str().c_str()); + } return result; } diff --git a/test/storage/headers.test.cpp b/test/storage/headers.test.cpp index b7dcfc025d..613f469b59 100644 --- a/test/storage/headers.test.cpp +++ b/test/storage/headers.test.cpp @@ -10,6 +10,10 @@ TEST(HTTPHeader, Parsing) { ASSERT_FALSE(bool(cc.maxAge)); EXPECT_FALSE(cc.mustRevalidate); + cc = http::CacheControl::parse(R"#("max-age=34)#"); + ASSERT_FALSE(bool(cc.maxAge)); + EXPECT_FALSE(cc.mustRevalidate); + cc = http::CacheControl::parse(R"#(max-age =34)#"); ASSERT_TRUE(bool(cc.maxAge)); EXPECT_EQ(34u, *cc.maxAge); @@ -38,6 +42,11 @@ TEST(HTTPHeader, Parsing) { EXPECT_EQ(3u, *cc.maxAge); EXPECT_FALSE(cc.mustRevalidate); + cc = http::CacheControl::parse(R"#(max-age=3,max-age=""34)#"); + ASSERT_TRUE(bool(cc.maxAge)); + EXPECT_EQ(3u, *cc.maxAge); + EXPECT_FALSE(cc.mustRevalidate); + cc = http::CacheControl::parse(R"#(max-age="\",max-age=4,")#"); ASSERT_FALSE(bool(cc.maxAge)); EXPECT_FALSE(cc.mustRevalidate); -- cgit v1.2.1 From 3952ff5c343844d76f75ede0afc8ddad55748a0d Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Tue, 24 Jul 2018 21:25:21 +0300 Subject: [core] Replace unique_any with peer from mapbox-bindgen --- cmake/core-files.cmake | 2 +- cmake/test-files.cmake | 2 +- include/mbgl/style/layer.hpp | 4 +- include/mbgl/style/source.hpp | 4 +- include/mbgl/util/peer.hpp | 111 +++++++++++ include/mbgl/util/unique_any.hpp | 271 -------------------------- platform/android/src/style/sources/source.cpp | 4 +- platform/darwin/src/MGLStyle.mm | 4 +- test/util/peer.test.cpp | 194 ++++++++++++++++++ test/util/unique_any.test.cpp | 218 --------------------- 10 files changed, 315 insertions(+), 499 deletions(-) create mode 100644 include/mbgl/util/peer.hpp delete mode 100644 include/mbgl/util/unique_any.hpp create mode 100644 test/util/peer.test.cpp delete mode 100644 test/util/unique_any.test.cpp diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index addacc174d..2cfcb16771 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -679,6 +679,7 @@ set(MBGL_CORE_FILES include/mbgl/util/logging.hpp include/mbgl/util/noncopyable.hpp include/mbgl/util/optional.hpp + include/mbgl/util/peer.hpp include/mbgl/util/platform.hpp include/mbgl/util/premultiply.hpp include/mbgl/util/projection.hpp @@ -692,7 +693,6 @@ set(MBGL_CORE_FILES include/mbgl/util/traits.hpp include/mbgl/util/tuple.hpp include/mbgl/util/type_list.hpp - include/mbgl/util/unique_any.hpp include/mbgl/util/unitbezier.hpp include/mbgl/util/util.hpp include/mbgl/util/variant.hpp diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake index 1961d78dfc..2a679fc40b 100644 --- a/cmake/test-files.cmake +++ b/cmake/test-files.cmake @@ -137,6 +137,7 @@ set(MBGL_TEST_FILES test/util/merge_lines.test.cpp test/util/number_conversions.test.cpp test/util/offscreen_texture.test.cpp + test/util/peer.test.cpp test/util/position.test.cpp test/util/projection.test.cpp test/util/run_loop.test.cpp @@ -147,7 +148,6 @@ set(MBGL_TEST_FILES test/util/tile_range.test.cpp test/util/timer.test.cpp test/util/token.test.cpp - test/util/unique_any.test.cpp test/util/url.test.cpp ) diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index 12494f5387..b5a4b63d2e 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include #include @@ -132,7 +132,7 @@ public: // For use in SDK bindings, which store a reference to a platform-native peer // object here, so that separately-obtained references to this object share // identical platform-native peers. - util::unique_any peer; + util::peer peer; }; } // namespace style diff --git a/include/mbgl/style/source.hpp b/include/mbgl/style/source.hpp index 2f2838ade8..dc3a8d73fb 100644 --- a/include/mbgl/style/source.hpp +++ b/include/mbgl/style/source.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -77,7 +77,7 @@ public: // For use in SDK bindings, which store a reference to a platform-native peer // object here, so that separately-obtained references to this object share // identical platform-native peers. - util::unique_any peer; + util::peer peer; }; } // namespace style diff --git a/include/mbgl/util/peer.hpp b/include/mbgl/util/peer.hpp new file mode 100644 index 0000000000..a4abea0e88 --- /dev/null +++ b/include/mbgl/util/peer.hpp @@ -0,0 +1,111 @@ +#pragma once + +#include +#include + +namespace mbgl { +namespace util { + +class peer { +public: + peer() = default; + peer(const peer&) = delete; + + peer(peer&& other) + : vtable(other.vtable) + { + if (vtable) { + vtable->move(other.storage, storage); + } + other.vtable = nullptr; + } + + template + peer(T&& value) { + using _Vt = std::decay_t; + vtable = get_vtable<_Vt>(); + new (&storage) _Vt(std::forward(value)); + } + + ~peer() { + reset(); + } + + peer& operator=(peer&& rhs) { + peer(std::move(rhs)).swap(*this); + return *this; + } + + void reset() { + if (vtable) { + vtable->destroy(storage); + vtable = nullptr; + } + } + + void swap(peer& rhs) { + if (this == &rhs) { + return; + } else { + peer tmp(std::move(rhs)); + rhs.vtable = vtable; + if (rhs.vtable) { + rhs.vtable->move(storage, rhs.storage); + } + vtable = tmp.vtable; + if (vtable) { + vtable->move(tmp.storage, storage); + } + } + } + + bool has_value() const { + return vtable != nullptr; + } + + template + T& get() { + return reinterpret_cast(storage); + } + + template + T&& take() { + reset(); + return std::move(get()); + } + +private: + using storage_t = std::aligned_storage_t<2*sizeof(void*), alignof(void*)>; + + struct vtable { + virtual ~vtable() = default; + virtual void move(storage_t&, storage_t&) = 0; + virtual void destroy(storage_t&) = 0; + }; + + template + struct vtable_impl : public vtable { + static_assert(sizeof(T) <= sizeof(storage_t), "peer object is too big"); + + void move(storage_t& src, storage_t& dst) override { + new (&dst) T(std::move(reinterpret_cast(src))); + destroy(src); + } + + void destroy(storage_t& s) override { + reinterpret_cast(s).~T(); + } + }; + + template + static vtable* get_vtable() { + static vtable_impl vtable; + return &vtable; + } + + vtable* vtable = nullptr; + storage_t storage; +}; + +} // namespace util +} // namespace mbgl diff --git a/include/mbgl/util/unique_any.hpp b/include/mbgl/util/unique_any.hpp deleted file mode 100644 index c7dc8b38ea..0000000000 --- a/include/mbgl/util/unique_any.hpp +++ /dev/null @@ -1,271 +0,0 @@ -#pragma once - -#include -#include -#include -namespace mbgl { -namespace util { - -class bad_any_cast : public std::bad_cast { -public: - const char* what() const noexcept override { - return "bad any_cast<>()"; - } -}; -/** - * A variant of `std::any` for non-copyable types. - * - * Use `unique_any` for non-copyable types (e.g. `std::unique_ptr`) - * or to ensure that no copies are made of copyable types that are - * moved in. - * - * `uniqe_any` differs from `std::any` in that it does not support copy construction - * or copy assignment. It also does not require the contained type to be copy - * constructible. - * - * The `any_cast()` methods work similar to `std::any_cast()` except that - * non-copyable types may only be cast to references. - * - * Example usage: - * unique_any u1(3); - * auto u2 = unique_any(std::move(u1)); // u1 is moved from - * int i = any_cast(u2); - * - * unique_any u2; - * u2 = std::unique_ptr(new int); - * std::unique_ptr iPtr = any_cast>(std::move(u2)); - * - * Inspired by linb::any (https://github.com/thelink2012/any) and the - * libc++ implementation (https://github.com/llvm-mirror/libcxx). - */ -class unique_any final -{ -public: - unique_any() = default; - - //Copy constructor (deleted) - unique_any(const unique_any& rhs) = delete; - - unique_any(unique_any&& rhs) : vtable(rhs.vtable) { - if (vtable) { - vtable->move(std::move(rhs.storage), storage); - } - rhs.vtable = nullptr; - } - - // Constructs with a direct-initilizated object of type ValueType - template , - typename = std::enable_if_t::value> > - unique_any(ValueType&& value) { - create(std::forward(value)); - } - - ~unique_any() { - reset(); - } - - unique_any& operator=(unique_any&& rhs) { - unique_any(std::move(rhs)).swap(*this); - return *this; - } - - template , unique_any>::value> > - unique_any& operator=(ValueType&& rhs) { - unique_any(std::forward(rhs)).swap(*this); - return *this; - } - - void reset() { - if (vtable) { - vtable->destroy(storage); - vtable = nullptr; - } - } - - void swap(unique_any& rhs) { - if (this == &rhs) { - return; - } else { - unique_any tmp(std::move(rhs)); - rhs.vtable = vtable; - if (rhs.vtable) { - rhs.vtable->move(std::move(storage), rhs.storage); - } - vtable = tmp.vtable; - if (vtable) { - vtable->move(std::move(tmp.storage), storage); - } - } - } - - const std::type_info& type() const { - return !has_value()? typeid(void) : vtable->type(); - } - - bool has_value() const { - return vtable != nullptr; - } - -private: - - union Storage { - using StackStorage = std::aligned_storage_t<3*sizeof(void*), std::alignment_of::value>; - Storage() = default; - - void * dynamic { nullptr }; - StackStorage stack; - }; - - template - struct AllocateOnStack : std::integral_constant::value <= std::alignment_of::value - && std::is_nothrow_move_constructible::value> { - }; - - struct VTable { - virtual ~VTable() = default; - virtual void move(Storage&& src, Storage& dest) = 0; - virtual void destroy(Storage&) = 0; - virtual const std::type_info& type() = 0; - }; - - template - struct VTableHeap : public VTable { - void move(Storage&& src, Storage& dest) override { - dest.dynamic = src.dynamic; - src.dynamic = nullptr; - } - - void destroy(Storage& s) override { - delete reinterpret_cast(s.dynamic); - } - - const std::type_info& type() override { - return typeid(ValueType); - } - }; - - template - struct VTableStack : public VTable { - void move(Storage&& src, Storage& dest) override { - new (&dest.stack) ValueType(std::move(reinterpret_cast(src.stack))); - destroy(src); - } - - void destroy(Storage& s) override { - reinterpret_cast(s.stack).~ValueType(); - } - - const std::type_info& type() override { - return typeid(ValueType); - } - }; - - template - static VTable* vtableForType() { - using VTableType = std::conditional_t::value, VTableStack, VTableHeap >; - static VTableType vtable; - return &vtable; - } - - template - std::enable_if_t::value> - createStorage(ValueType&& value) { - new (&storage.stack) _Vt(std::forward(value)); - } - - template - std::enable_if_t::value> - createStorage(ValueType&& value) { - storage.dynamic = new _Vt(std::forward(value)); - } - - template - void create(ValueType&& value) { - using _Vt = std::decay_t; - vtable = vtableForType<_Vt>(); - createStorage(std::forward(value)); - } - - VTable* vtable { nullptr }; - Storage storage; - -protected: - template - friend const ValueType* any_cast(const unique_any* operand) ; - - template - friend ValueType* any_cast(unique_any* operand) ; - - template > - ValueType* cast() - { - return reinterpret_cast( - AllocateOnStack<_Vt>::value ? &storage.stack : storage.dynamic); - } -}; - -template -inline const ValueType* any_cast(const unique_any* any) -{ - return any_cast(const_cast(any)); -} - -template -inline ValueType* any_cast(unique_any* any) -{ - if(any == nullptr || any->type() != typeid(ValueType)) - return nullptr; - else - return any->cast(); -} - -template > -inline ValueType any_cast(const unique_any& any) -{ - static_assert(std::is_constructible::value, - "any_cast type can't construct copy of contained object"); - auto temp = any_cast<_Vt>(&any); - if (temp == nullptr) { - throw bad_any_cast(); - } - return static_cast(*temp); -} - -template > -inline ValueType any_cast(unique_any& any) -{ - static_assert(std::is_constructible::value, - "any_cast type can't construct copy of contained object"); - auto temp = any_cast<_Vt>(&any); - if (temp == nullptr) { - throw bad_any_cast(); - } - return static_cast(*temp); -} - -template > -inline ValueType any_cast(unique_any&& any) -{ - auto temp = any_cast<_Vt>(&any); - if (temp == nullptr) { - throw bad_any_cast(); - } - auto retValue = static_cast(std::move(*temp)); - any.reset(); - return std::move(retValue); -} - -} // namespace util -} // namespace mbgl - -namespace std { - -inline void swap(mbgl::util::unique_any& lhs, mbgl::util::unique_any& rhs) { - lhs.swap(rhs); -} - -} // namespace std diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp index 413530a5ec..5f68e40467 100644 --- a/platform/android/src/style/sources/source.cpp +++ b/platform/android/src/style/sources/source.cpp @@ -51,7 +51,7 @@ namespace android { if (!coreSource.peer.has_value()) { coreSource.peer = createSourcePeer(env, coreSource, frontend); } - return *mbgl::util::any_cast>(&coreSource.peer)->get()->javaPeer; + return *coreSource.peer.get>()->javaPeer; } Source::Source(jni::JNIEnv& env, mbgl::style::Source& coreSource, jni::Object obj, AndroidRendererFrontend& frontend) @@ -125,7 +125,7 @@ namespace android { // Release the peer relationships. These will be re-established when the source is added to a map assert(ownedSource->peer.has_value()); - util::any_cast>(&(ownedSource->peer))->release(); + ownedSource->peer.get>().release(); ownedSource->peer.reset(); // Release the strong reference to the java peer diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm index 3f9bfbf8ca..e0415c02f7 100644 --- a/platform/darwin/src/MGLStyle.mm +++ b/platform/darwin/src/MGLStyle.mm @@ -177,7 +177,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles, } - (MGLSource *)sourceFromMBGLSource:(mbgl::style::Source *)rawSource { - if (MGLSource *source = rawSource->peer.has_value() ? mbgl::util::any_cast(rawSource->peer).source : nil) { + if (MGLSource *source = rawSource->peer.has_value() ? rawSource->peer.get().source : nil) { return source; } @@ -341,7 +341,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles, { NSParameterAssert(rawLayer); - if (MGLStyleLayer *layer = rawLayer->peer.has_value() ? mbgl::util::any_cast(&(rawLayer->peer))->layer : nil) { + if (MGLStyleLayer *layer = rawLayer->peer.has_value() ? rawLayer->peer.get().layer : nil) { return layer; } diff --git a/test/util/peer.test.cpp b/test/util/peer.test.cpp new file mode 100644 index 0000000000..aa4dae5a88 --- /dev/null +++ b/test/util/peer.test.cpp @@ -0,0 +1,194 @@ +#include + +#include + +using namespace mbgl::util; + +class TestType { +public: + TestType() : i1(0), i2(1) { + str[0] = 'a'; + } + + //Detect moves + TestType(TestType&& t): i1(t.i1+1), i2(t.i2+2) { + str[0] = t.str[0]+1; + } + + TestType(const TestType&) = delete; + TestType& operator=(const TestType&) = delete; + + int i1; + int i2; + char str[256]; +}; + +bool IsStackAllocated (const peer& a, const void* obj1) { + uintptr_t a_ptr = (uintptr_t)(&a); + uintptr_t obj = (uintptr_t)(obj1); + return (obj >= a_ptr && obj < a_ptr + sizeof(peer)); +}; + +TEST(Peer, Empty) { + EXPECT_FALSE(peer().has_value()); +} + +TEST(Peer, BasicTypes) { + peer i = 3; + EXPECT_TRUE(i.has_value()); + EXPECT_TRUE(i.get() == 3); + + auto iValue = i.get(); + EXPECT_TRUE(iValue == 3); + + EXPECT_TRUE(peer(4).has_value()); + EXPECT_TRUE(peer(4).get() == 4); + + peer f = 6.2f; + EXPECT_TRUE(f.has_value()); + EXPECT_TRUE(f.get() == 6.2f); + + const float fValue = f.get(); + EXPECT_TRUE(fValue == 6.2f); + + EXPECT_TRUE(peer(1.0f).has_value()); + EXPECT_TRUE(peer(1.0f).get() == 1.0f); + + peer c = 'z'; + EXPECT_TRUE(c.has_value()); + EXPECT_TRUE(c.get() == 'z'); + + EXPECT_TRUE(peer('z').has_value()); + EXPECT_TRUE(peer('z').get() == 'z'); +} + +TEST(Peer, BasicTypes_Move) { + peer i = 3; + EXPECT_TRUE(i.has_value()); + + peer f = 6.2f; + EXPECT_TRUE(f.has_value()); + + f = std::move(i); + EXPECT_FALSE(i.has_value()); + + EXPECT_TRUE(f.has_value()); + EXPECT_TRUE(f.get() == 3); +} + +TEST(Peer, SmallType) { + struct T { + T(int32_t* p_) : p(p_) { + (*p)++; + } + + T(T&& t) noexcept : p(t.p) { + (*p)++; + } + + ~T() { + (*p)--; + } + + T(const T&) = delete; + T& operator=(const T&) = delete; + + int32_t* p; + }; + + int32_t p = 0; + + { + peer u1 = peer(T(&p)); + EXPECT_EQ(p, 1); + + auto u2(std::move(u1)); + EXPECT_EQ(p, 1); + } + + EXPECT_EQ(p, 0); +} + +// peer is not able to receive large types, unless we increase storage_t +// capacity. +//TEST(Peer, LargeType) { +// TestType t1; +// peer u1 = peer(std::move(t1)); +// EXPECT_TRUE(u1.has_value()); +// +// //TestType should be moved into owning peer +// EXPECT_EQ(u1.get().i1, 1); +// +// auto u2(std::move(u1)); +// EXPECT_FALSE(u1.has_value()); +// +// //TestType should not be moved when owning peer is moved; +// EXPECT_EQ(u2.get().i1, 1); +// +// //TestType should be moved out of owning peer +// // Note: two moves are involved in returning the moved value +// // First out of the peer, and then in the return statement +// auto t2 = std::move(u2.get()); +// EXPECT_FALSE(u2.has_value()); +// EXPECT_EQ(t2.i1, 3); +//} + +TEST(Peer, Pointer) { + auto t1 = new TestType(); + + auto u1 = peer(std::move(t1)); + EXPECT_TRUE(u1.has_value()); + + //Only the pointer should be moved + TestType * t2 = u1.get(); + EXPECT_EQ(t2->i1, 0); + + peer u2(4); + std::swap(u2, u1); + + EXPECT_TRUE(u1.has_value()); + + EXPECT_TRUE(u2.has_value()); + + t2 = u2.get(); + EXPECT_EQ(t2->i1, 0); + delete t2; +} + + +TEST(Peer, UniquePtr) { + auto t1 = std::make_unique(); + auto u1 = peer(std::move(t1)); + + EXPECT_EQ(t1.get(), nullptr); + EXPECT_TRUE(u1.has_value()); + + auto t2 = std::move(u1.take()); + EXPECT_FALSE(u1.has_value()); + (void)t2; + + peer u2; + TestType * t3 = new TestType(); + u2 = std::unique_ptr(t3); + EXPECT_TRUE(u2.has_value()); +} + +TEST(Peer, SharedPtr) { + + std::shared_ptr shared(new int(3)); + std::weak_ptr weak = shared; + peer u1 = 0; + + EXPECT_EQ(weak.use_count(), 1); + peer u2 = shared; + EXPECT_EQ(weak.use_count(), 2); + + u1 = std::move(u2); + EXPECT_EQ(weak.use_count(), 2); + u2.swap(u1); + EXPECT_EQ(weak.use_count(), 2); + u2 = 0; + EXPECT_EQ(weak.use_count(), 1); + shared = nullptr; + EXPECT_EQ(weak.use_count(), 0); +} diff --git a/test/util/unique_any.test.cpp b/test/util/unique_any.test.cpp deleted file mode 100644 index 9b622cd284..0000000000 --- a/test/util/unique_any.test.cpp +++ /dev/null @@ -1,218 +0,0 @@ -#include - -#include - -using namespace mbgl::util; - -class TestType { -public: - TestType() : i1(0), i2(1) { - str[0] = 'a'; - } - - //Detect moves - TestType(TestType&& t): i1(t.i1+1), i2(t.i2+2) { - str[0] = t.str[0]+1; - } - - TestType(const TestType&) = delete; - TestType& operator=(const TestType&) = delete; - - int i1; - int i2; - char str[256]; -}; - -bool IsStackAllocated (const unique_any& a, const void* obj1) { - uintptr_t a_ptr = (uintptr_t)(&a); - uintptr_t obj = (uintptr_t)(obj1); - return (obj >= a_ptr && obj < a_ptr + sizeof(unique_any)); -}; - -TEST(UniqueAny, Empty) { - EXPECT_FALSE(unique_any().has_value()); - EXPECT_TRUE(unique_any().type() == typeid(void)); - EXPECT_THROW(any_cast(unique_any()), bad_any_cast); -} - -TEST(UniqueAny, BasicTypes) { - unique_any i = 3; - EXPECT_TRUE(i.has_value()); - EXPECT_TRUE(i.type() == typeid(int)); - EXPECT_TRUE(IsStackAllocated(i, any_cast(&i))); - - auto iValue = any_cast(i); - EXPECT_TRUE(iValue == 3); - - EXPECT_TRUE(unique_any(4).has_value()); - EXPECT_TRUE(unique_any(4).type() == typeid(int)); - - unique_any f = 6.2f; - EXPECT_TRUE(f.has_value()); - EXPECT_TRUE(f.type() == typeid(float)); - EXPECT_TRUE(IsStackAllocated(f, any_cast(&f))); - - const float fValue = any_cast(f); - EXPECT_TRUE(fValue == 6.2f); - - EXPECT_TRUE(unique_any(1.0f).has_value()); - EXPECT_TRUE(unique_any(1.0f).type() == typeid(float)); - - unique_any c = 'z'; - EXPECT_TRUE(c.has_value()); - EXPECT_TRUE(c.type() == typeid(char)); - EXPECT_TRUE(IsStackAllocated(c, any_cast(&c))); - - EXPECT_THROW(any_cast(c), bad_any_cast); - - EXPECT_TRUE(unique_any('4').has_value()); - EXPECT_TRUE(unique_any('4').type() == typeid(char)); -} - -TEST(UniqueAny, BasicTypes_Move) { - unique_any i = 3; - EXPECT_TRUE(i.has_value()); - EXPECT_TRUE(i.type() == typeid(int)); - - unique_any f = 6.2f; - EXPECT_TRUE(f.has_value()); - EXPECT_TRUE(f.type() == typeid(float)); - - f = std::move(i); - EXPECT_FALSE(i.has_value()); - EXPECT_TRUE(i.type() == typeid(void)); - - EXPECT_TRUE(f.has_value()); - EXPECT_TRUE(f.type() == typeid(int)); - -} - -TEST(UniqueAny, SmallType) { - struct T { - T(int32_t* p_) : p(p_) { - (*p)++; - } - - T(T&& t) noexcept : p(t.p) { - (*p)++; - } - - ~T() { - (*p)--; - } - - T(const T&) = delete; - T& operator=(const T&) = delete; - - int32_t* p; - }; - - int32_t p = 0; - - { - unique_any u1 = unique_any(T(&p)); - EXPECT_EQ(p, 1); - - auto u2(std::move(u1)); - EXPECT_EQ(p, 1); - } - - EXPECT_EQ(p, 0); -} - -TEST(UniqueAny, LargeType) { - TestType t1; - unique_any u1 = unique_any(std::move(t1)); - EXPECT_TRUE(u1.has_value()); - EXPECT_TRUE(u1.type() == typeid(TestType)); - EXPECT_FALSE(IsStackAllocated(u1, any_cast(&u1))); - - //TestType should be moved into owning unique_any - EXPECT_EQ(any_cast(&u1)->i1, 1); - - auto u2(std::move(u1)); - EXPECT_TRUE(u2.type() == typeid(TestType)); - EXPECT_TRUE(u1.type() == typeid(void)); - - //TestType should not be moved when owning unique_any is moved; - EXPECT_EQ(any_cast(&u2)->i1, 1); - - //TestType should be moved out of owning unique_any - // Note: two moves are involved in returning the moved value - // First out of the unique_any, and then in the return statement - auto t2 = any_cast(std::move(u2)); - EXPECT_EQ(t2.i1, 3); - EXPECT_TRUE(u2.type() == typeid(void)); -} - -TEST(UniqueAny, Pointer) { - auto t1 = new TestType(); - - auto u1 = unique_any(std::move(t1)); - EXPECT_TRUE(u1.has_value()); - EXPECT_TRUE(u1.type() == typeid(TestType *)); - EXPECT_TRUE(IsStackAllocated(u1, any_cast(&u1))); - - //Only the pointer should be moved - TestType * t2 = *any_cast(&u1); - EXPECT_EQ(t2->i1, 0); - - unique_any u2(4); - std::swap(u2, u1); - - EXPECT_TRUE(u1.has_value()); - EXPECT_TRUE(u1.type() == typeid(int)); - - EXPECT_TRUE(u2.has_value()); - EXPECT_TRUE(u2.type() == typeid(TestType *)); - - t2 = *any_cast(&u2); - EXPECT_EQ(t2->i1, 0); - delete t2; -} - - -TEST(UniqueAny, UniquePtr) { - auto t1 = std::make_unique(); - auto u1 = unique_any(std::move(t1)); - - EXPECT_EQ(t1.get(), nullptr); - EXPECT_TRUE(u1.has_value()); - EXPECT_TRUE(u1.type() == typeid(std::unique_ptr)); - - EXPECT_TRUE(IsStackAllocated(u1, any_cast>(&u1))); - - auto t2 = any_cast >(std::move(u1)); - EXPECT_FALSE(u1.has_value()); - - unique_any u2; - TestType * t3 = new TestType(); - u2 = std::unique_ptr(t3); - EXPECT_TRUE(u2.has_value()); - EXPECT_TRUE(any_cast>(&u2)->get() == t3); -} - -TEST(UniqueAny, SharedPtr) { - - std::shared_ptr shared(new int(3)); - std::weak_ptr weak = shared; - unique_any u1 = 0; - - EXPECT_THROW(any_cast(u1), bad_any_cast); - - EXPECT_EQ(weak.use_count(), 1); - unique_any u2 = shared; - EXPECT_EQ(weak.use_count(), 2); - - EXPECT_EQ(any_cast>(&u1), nullptr); - EXPECT_FALSE(IsStackAllocated(u1, any_cast>(&u1))); - - u1 = std::move(u2); - EXPECT_EQ(weak.use_count(), 2); - u2.swap(u1); - EXPECT_EQ(weak.use_count(), 2); - u2 = 0; - EXPECT_EQ(weak.use_count(), 1); - shared = nullptr; - EXPECT_EQ(weak.use_count(), 0); -} -- cgit v1.2.1 From 4291688b864e17e7637634db423c624c52e49fa2 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Wed, 8 Aug 2018 07:53:01 -0700 Subject: [core] Use correct Log::record overload. (#12571) --- src/mbgl/util/logging.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/util/logging.cpp b/src/mbgl/util/logging.cpp index d322bd3670..fd3f14825d 100644 --- a/src/mbgl/util/logging.cpp +++ b/src/mbgl/util/logging.cpp @@ -35,7 +35,7 @@ void Log::record(EventSeverity severity, Event event, const char* format, ...) { vsnprintf(msg, sizeof(msg), format, args); va_end(args); - record(severity, event, -1, msg); + record(severity, event, -1, std::string{ msg }); } void Log::record(EventSeverity severity, Event event, int64_t code, const char* format, ...) { -- cgit v1.2.1 From 7fb2aade96e4248338e43928a7e8aeeddead38d7 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 27 Jun 2018 10:58:17 -0700 Subject: [build] Update gl-js --- cmake/node.cmake | 4 +++ mapbox-gl-js | 2 +- package.json | 7 +++-- platform/node/test/expression.test.js | 16 +++++------ platform/node/test/query.test.js | 10 +++---- platform/node/test/render.test.js | 10 +++---- platform/node/test/suite_implementation.js | 46 +++++++++++++++--------------- 7 files changed, 47 insertions(+), 48 deletions(-) diff --git a/cmake/node.cmake b/cmake/node.cmake index 103d99b6a5..6750adc03c 100644 --- a/cmake/node.cmake +++ b/cmake/node.cmake @@ -101,6 +101,7 @@ xcode_create_scheme( TYPE node NAME "node render tests (Active ABI)" ARGS + "-r esm" "platform/node/test/render.test.js" OPTIONAL_ARGS "group" @@ -112,6 +113,7 @@ xcode_create_scheme( TYPE node NAME "node query tests (Active ABI)" ARGS + "-r esm" "platform/node/test/query.test.js" OPTIONAL_ARGS "group" @@ -123,6 +125,7 @@ xcode_create_scheme( TYPE node NAME "node expression tests (Active ABI)" ARGS + "-r esm" "platform/node/test/expression.test.js" OPTIONAL_ARGS "group" @@ -134,6 +137,7 @@ xcode_create_scheme( TYPE node NAME "node-benchmark (Active ABI)" ARGS + "-r esm" "platform/node/test/benchmark.js" OPTIONAL_ARGS "group" diff --git a/mapbox-gl-js b/mapbox-gl-js index 47e637c398..6c22a1720d 160000 --- a/mapbox-gl-js +++ b/mapbox-gl-js @@ -1 +1 @@ -Subproject commit 47e637c3984a5121589bd17b51c6605f223aaeae +Subproject commit 6c22a1720dac51eac1c898ca06b3e2f24dbe0810 diff --git a/package.json b/package.json index ef23f4aa99..799d3ab85f 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "aws-sdk": "^2.285.1", "csscolorparser": "^1.0.2", "ejs": "^2.4.1", + "esm": "^3.0.55", "express": "^4.11.1", "flow-remove-types": "^1.2.1", "json-stringify-pretty-compact": "^1.0.4", @@ -43,9 +44,9 @@ "test": "tape platform/node/test/js/**/*.test.js", "test-memory": "node --expose-gc platform/node/test/memory.test.js", "test-suite": "run-s test-render test-query test-expressions", - "test-expressions": "node platform/node/test/expression.test.js", - "test-render": "node platform/node/test/render.test.js", - "test-query": "node platform/node/test/query.test.js" + "test-expressions": "node -r esm platform/node/test/expression.test.js", + "test-render": "node -r esm platform/node/test/render.test.js", + "test-query": "node -r esm platform/node/test/query.test.js" }, "gypfile": true, "binary": { diff --git a/platform/node/test/expression.test.js b/platform/node/test/expression.test.js index ffd1c68ff2..4635ef78f7 100644 --- a/platform/node/test/expression.test.js +++ b/platform/node/test/expression.test.js @@ -1,10 +1,8 @@ -'use strict'; +import {run} from '../../../mapbox-gl-js/test/integration/lib/expression'; +import mbgl from '../index'; +import ignores from './ignores.json'; -var suite = require('../../../mapbox-gl-js/test/integration').expression; -var mbgl = require('../index'); -var ignores = require('./ignores.json'); - -var tests; +let tests; if (process.argv[1] === __filename && process.argv.length > 2) { tests = process.argv.slice(2); @@ -30,7 +28,7 @@ function getExpectedType(spec) { return typeof spec.type === 'string' ? {kind: spec.type} : null; } -suite.run('native', {ignores: ignores, tests: tests}, (fixture) => { +run('native', {ignores, tests}, (fixture) => { const compiled = {}; const recompiled = {}; const result = { @@ -55,7 +53,7 @@ suite.run('native', {ignores: ignores, tests: tests}, (fixture) => { type: 'Feature', properties: {}, geometry: { type: 'Point', coordinates: [0, 0] } - }, input[1]) + }, input[1]); const output = expression.evaluate(input[0], feature); evaluateResults.push(output); @@ -68,7 +66,7 @@ suite.run('native', {ignores: ignores, tests: tests}, (fixture) => { compilationResult.result = 'error'; compilationResult.errors = expression; } - } + }; result.outputs = evaluateExpression(expression, compiled); if (expression instanceof mbgl.Expression) { diff --git a/platform/node/test/query.test.js b/platform/node/test/query.test.js index 02602d3f5a..3dfce4474c 100644 --- a/platform/node/test/query.test.js +++ b/platform/node/test/query.test.js @@ -1,8 +1,6 @@ -'use strict'; - -const suite = require('../../../mapbox-gl-js/test/integration').query; -const suiteImplementation = require('./suite_implementation'); -const ignores = require('./ignores.json'); +import {run} from '../../../mapbox-gl-js/test/integration/lib/query'; +import implementation from './suite_implementation'; +import ignores from './ignores.json'; let tests; @@ -10,4 +8,4 @@ if (process.argv[1] === __filename && process.argv.length > 2) { tests = process.argv.slice(2); } -suite.run('native', {tests: tests, ignores: ignores}, suiteImplementation); +run('native', {tests, ignores}, implementation); diff --git a/platform/node/test/render.test.js b/platform/node/test/render.test.js index 812a531f20..950f8eb7ab 100644 --- a/platform/node/test/render.test.js +++ b/platform/node/test/render.test.js @@ -1,7 +1,5 @@ -'use strict'; +import {run} from '../../../mapbox-gl-js/test/integration/lib/render'; +import implementation from './suite_implementation'; +import ignores from './ignores.json'; -const suite = require('../../../mapbox-gl-js/test/integration').render; -const suiteImplementation = require('./suite_implementation'); -const ignores = require('./ignores.json'); - -suite.run('native', ignores, suiteImplementation); +run('native', ignores, implementation); diff --git a/platform/node/test/suite_implementation.js b/platform/node/test/suite_implementation.js index c09e8f50bf..704cab8940 100644 --- a/platform/node/test/suite_implementation.js +++ b/platform/node/test/suite_implementation.js @@ -1,24 +1,24 @@ -'use strict'; - -var mbgl = require('../index'); -var request = require('request'); -var PNG = require('pngjs').PNG; -var fs = require('fs'); -var path = require('path'); +import mbgl from '../index'; +import request from 'request'; +import {PNG} from 'pngjs'; +import * as fs from 'fs'; +import * as path from 'path'; mbgl.on('message', function(msg) { console.log('%s (%s): %s', msg.severity, msg.class, msg.text); }); // Map of map objects by pixel ratio -var maps = new Map(); +const maps = new Map(); + +export default function (style, options, callback) { + const tileMode = options.mapMode === 'tile'; + let map; -module.exports = function (style, options, callback) { - var tileMode = options.mapMode === 'tile'; if (options.recycleMap) { - var key = options.pixelRatio + '/' + tileMode; + const key = options.pixelRatio + '/' + tileMode; if (maps.has(key)) { - var map = maps.get(key); + map = maps.get(key); map.request = mapRequest; } else { maps.set(key, new mbgl.Map({ @@ -26,18 +26,18 @@ module.exports = function (style, options, callback) { request: mapRequest, mode: options.mapMode })); - var map = maps.get(key); + map = maps.get(key); } } else { - var map = new mbgl.Map({ + map = new mbgl.Map({ ratio: options.pixelRatio, request: mapRequest, mode: options.mapMode }); } - var timedOut = false; - var watchdog = setTimeout(function () { + let timedOut = false; + const watchdog = setTimeout(function () { timedOut = true; map.dumpDebugLogs(); callback(new Error('timed out after 20 seconds')); @@ -61,19 +61,19 @@ module.exports = function (style, options, callback) { request(req.url, {encoding: null}, function (err, response, body) { if (err) { callback(err); - } else if (response.statusCode == 404) { + } else if (response.statusCode === 404) { callback(); - } else if (response.statusCode != 200) { + } else if (response.statusCode !== 200) { callback(new Error(response.statusMessage)); } else { callback(null, {data: body}); } }); - }; + } applyOperations(options.operations, function() { map.render(options, function (err, pixels) { - var results = options.queryGeometry ? + const results = options.queryGeometry ? map.queryRenderedFeatures(options.queryGeometry, options.queryOptions || {}) : []; if (!options.recycleMap) { @@ -86,7 +86,7 @@ module.exports = function (style, options, callback) { }); function applyOperations(operations, callback) { - var operation = operations && operations[0]; + const operation = operations && operations[0]; if (!operations || operations.length === 0) { callback(); @@ -102,7 +102,7 @@ module.exports = function (style, options, callback) { applyOperations(operations.slice(1), callback); }, operation[1]); } else if (operation[0] === 'addImage' || operation[0] === 'updateImage') { - var img = PNG.sync.read(fs.readFileSync(path.join(__dirname, '../../../mapbox-gl-js/test/integration', operation[2]))); + const img = PNG.sync.read(fs.readFileSync(path.join(__dirname, '../../../mapbox-gl-js/test/integration', operation[2]))); const testOpts = (operation.length > 3) ? operation[3] : {}; const options = { @@ -110,7 +110,7 @@ module.exports = function (style, options, callback) { width: img.width, pixelRatio: testOpts.pixelRatio || 1, sdf: testOpts.sdf || false - } + }; map.addImage(operation[1], img.data, options); -- cgit v1.2.1 From ca7ef2aac74dd2c2ba478aa04fa3159ca2653d26 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Wed, 25 Jul 2018 16:31:16 -0700 Subject: [build] Run expression tests in node-gcc6-debug job --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index e64f25b2e6..7b967d820b 100644 --- a/Makefile +++ b/Makefile @@ -506,6 +506,7 @@ test-node-recycle-map: node npm test npm run test-render -- --recycle-map --shuffle npm run test-query + npm run test-expressions #### Android targets ########################################################### -- cgit v1.2.1 From 20d21cb7bcc6fe7639f546c053cfac1145430c4c Mon Sep 17 00:00:00 2001 From: Bruno de Oliveira Abinader Date: Wed, 8 Aug 2018 18:29:17 +0300 Subject: Revert "[core] Replace Boost.Spirit with std::regex in CacheControl::parse()" This reverts commit 990b3b11b9427ffd86f693d3f4c3dd351891e5d0. --- src/mbgl/util/http_header.cpp | 28 +++++++++++++++++++++------- test/storage/headers.test.cpp | 9 --------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/mbgl/util/http_header.cpp b/src/mbgl/util/http_header.cpp index da68b4a790..4d9e2bf84c 100644 --- a/src/mbgl/util/http_header.cpp +++ b/src/mbgl/util/http_header.cpp @@ -2,20 +2,34 @@ #include -#include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-pragmas" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#pragma GCC diagnostic ignored "-Wshadow" +#pragma clang diagnostic push + +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#pragma clang diagnostic ignored "-Wunknown-warning-option" +#pragma clang diagnostic ignored "-Wtautological-constant-compare" +#include +#include +#include +#pragma clang diagnostic pop +#pragma GCC diagnostic pop namespace mbgl { namespace http { CacheControl CacheControl::parse(const std::string& value) { - std::regex maxAgeRegex(R"((?:[^"]*"[^"]*[^\\]")*[^"]*max-age[\s]*=[\s]*([\d]+).*)"); - std::smatch maxAgeMatch; + namespace qi = boost::spirit::qi; + namespace phoenix = boost::phoenix; CacheControl result; - result.mustRevalidate = value.find("must-revalidate") != std::string::npos; - if (std::regex_match(value, maxAgeMatch, maxAgeRegex) && maxAgeMatch.size() == 2) { - result.maxAge = ::atoll(maxAgeMatch[1].str().c_str()); - } + qi::phrase_parse(value.begin(), value.end(), ( + (qi::lit("must-revalidate") [ phoenix::ref(result.mustRevalidate) = true ]) | + (qi::lit("max-age") >> '=' >> qi::ulong_long [ phoenix::ref(result.maxAge) = qi::_1 ]) | + (*(('"' >> *(('\\' >> qi::char_) | (qi::char_ - '"')) >> '"') | (qi::char_ - '"' - ','))) + ) % ',', qi::ascii::space); return result; } diff --git a/test/storage/headers.test.cpp b/test/storage/headers.test.cpp index 613f469b59..b7dcfc025d 100644 --- a/test/storage/headers.test.cpp +++ b/test/storage/headers.test.cpp @@ -10,10 +10,6 @@ TEST(HTTPHeader, Parsing) { ASSERT_FALSE(bool(cc.maxAge)); EXPECT_FALSE(cc.mustRevalidate); - cc = http::CacheControl::parse(R"#("max-age=34)#"); - ASSERT_FALSE(bool(cc.maxAge)); - EXPECT_FALSE(cc.mustRevalidate); - cc = http::CacheControl::parse(R"#(max-age =34)#"); ASSERT_TRUE(bool(cc.maxAge)); EXPECT_EQ(34u, *cc.maxAge); @@ -42,11 +38,6 @@ TEST(HTTPHeader, Parsing) { EXPECT_EQ(3u, *cc.maxAge); EXPECT_FALSE(cc.mustRevalidate); - cc = http::CacheControl::parse(R"#(max-age=3,max-age=""34)#"); - ASSERT_TRUE(bool(cc.maxAge)); - EXPECT_EQ(3u, *cc.maxAge); - EXPECT_FALSE(cc.mustRevalidate); - cc = http::CacheControl::parse(R"#(max-age="\",max-age=4,")#"); ASSERT_FALSE(bool(cc.maxAge)); EXPECT_FALSE(cc.mustRevalidate); -- cgit v1.2.1 From 2dc18d2adac9f87b1a7c91d2e1de2f4811b896e9 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Tue, 7 Aug 2018 18:48:56 -0400 Subject: [build] Print binary size stats to CI logs, too --- scripts/check_binary_size.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/check_binary_size.js b/scripts/check_binary_size.js index 9caa1b9998..5a8aa70b1b 100755 --- a/scripts/check_binary_size.js +++ b/scripts/check_binary_size.js @@ -51,9 +51,7 @@ function getPriorSize() { console.log('No matching check found.'); return Promise.resolve(null); } - const prior = +run.output.summary.match(/`.*` is (\d+) bytes/)[1]; - console.log(`Prior size was ${prettyBytes(prior)}.`); - return prior; + return +run.output.summary.match(/`.*` is (\d+) bytes/)[1]; }); } @@ -71,6 +69,8 @@ github.apps.createInstallationToken({installation_id: SIZE_CHECK_APP_INSTALLATIO } })(); + console.log(`${label}: ${title} (${size} bytes)`); + return github.checks.create({ owner: 'mapbox', repo: 'mapbox-gl-native', -- cgit v1.2.1 From f3e16bcb475942112a0831628289abf346b84519 Mon Sep 17 00:00:00 2001 From: Julian Rex Date: Wed, 8 Aug 2018 14:11:54 -0400 Subject: [ios] Updated podspecs and changelog for release-espresso (#12579) --- platform/ios/CHANGELOG.md | 1 + platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec | 2 +- platform/ios/Mapbox-iOS-SDK-symbols.podspec | 2 +- platform/ios/Mapbox-iOS-SDK.podspec | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index a14021cf65..2edfca6262 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -17,6 +17,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Fixed an issue where the symbols for `MGLMapPointForCoordinate` could not be found. ([#12445](https://github.com/mapbox/mapbox-gl-native/issues/12445)) * Fixed an issue causing country and ocean labels to disappear after calling `-[MGLStyle localizeLabelsIntoLocale:]` when the system language is set to Simplified Chinese. ([#12164](https://github.com/mapbox/mapbox-gl-native/issues/12164)) * Fixed a crash that occurred when `MMELocationManager` was deallocated and the delegate was reporting updates. ([#12542](https://github.com/mapbox/mapbox-gl-native/pull/12542)) +* Various security related improvements. ## 4.2.0 - July 18, 2018 diff --git a/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec index 834c1b9aa1..ff680615ce 100644 --- a/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec +++ b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.3.0-alpha.2' + version = '4.3.0-beta.1' m.name = 'Mapbox-iOS-SDK-nightly-dynamic' m.version = "#{version}-nightly" diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec index 513bdf7b3a..d04fbc445f 100644 --- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec +++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.3.0-alpha.2' + version = '4.3.0-beta.1' m.name = 'Mapbox-iOS-SDK-symbols' m.version = "#{version}-symbols" diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec index 796d8425d5..b8e620f264 100644 --- a/platform/ios/Mapbox-iOS-SDK.podspec +++ b/platform/ios/Mapbox-iOS-SDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.3.0-alpha.2' + version = '4.3.0-beta.1' m.name = 'Mapbox-iOS-SDK' m.version = version -- cgit v1.2.1 From c11482260aea0234e5a8dc9715e8a4d85e9ee680 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Wed, 8 Aug 2018 12:45:11 -0700 Subject: [macos] Removed bogus library search path Fixed a build warning caused by a nonexistent library search path in the Debug configuration. --- platform/macos/macos.xcodeproj/project.pbxproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index ffb7b524c6..3ee1b8eab4 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -1967,10 +1967,6 @@ INFOPLIST_FILE = "$(SRCROOT)/sdk/Info.plist"; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; - LIBRARY_SEARCH_PATHS = ( - "$(inherited)", - "$(PROJECT_DIR)/cmake/Debug", - ); OTHER_CFLAGS = "-fvisibility=hidden"; OTHER_LDFLAGS = ( "$(mbgl_core_LINK_LIBRARIES)", -- cgit v1.2.1 From a84d59f2a25bcdf0f40466a0c3f76592dcf8f591 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Wed, 8 Aug 2018 18:29:03 -0400 Subject: [ios] Add MGLMapViewDecelerationRate typed enum MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Improves Swiftiness by allowing type-omission, à la `mapView.decelerationRate = .fast` and such. --- platform/ios/CHANGELOG.md | 4 ++++ platform/ios/src/MGLMapView.h | 9 ++++++--- platform/ios/src/MGLMapView.mm | 6 +++--- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 2edfca6262..a904d15835 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -2,6 +2,10 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started. +## master + +* Improved the Swift interface for `MGLMapView.decelerationRate`. ([#12584](https://github.com/mapbox/mapbox-gl-native/issues/12584)) + ## 4.3.0 ### Styles and rendering diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index ddc8be23f0..44d7ab9708 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -23,14 +23,17 @@ NS_ASSUME_NONNULL_BEGIN @protocol MGLFeature; @protocol MGLLocationManager; +/** Options for `MGLMapView.decelerationRate`. */ +typedef CGFloat MGLMapViewDecelerationRate NS_TYPED_EXTENSIBLE_ENUM; + /** The default deceleration rate for a map view. */ -FOUNDATION_EXTERN MGL_EXPORT const CGFloat MGLMapViewDecelerationRateNormal; +FOUNDATION_EXTERN MGL_EXPORT const MGLMapViewDecelerationRate MGLMapViewDecelerationRateNormal; /** A fast deceleration rate for a map view. */ -FOUNDATION_EXTERN MGL_EXPORT const CGFloat MGLMapViewDecelerationRateFast; +FOUNDATION_EXTERN MGL_EXPORT const MGLMapViewDecelerationRate MGLMapViewDecelerationRateFast; /** Disables deceleration in a map view. */ -FOUNDATION_EXTERN MGL_EXPORT const CGFloat MGLMapViewDecelerationRateImmediate; +FOUNDATION_EXTERN MGL_EXPORT const MGLMapViewDecelerationRate MGLMapViewDecelerationRateImmediate; /** The vertical alignment of an annotation within a map view. Used with diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index f772432eb7..fa0beb008d 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -84,9 +84,9 @@ class MBGLView; class MGLAnnotationContext; -const CGFloat MGLMapViewDecelerationRateNormal = UIScrollViewDecelerationRateNormal; -const CGFloat MGLMapViewDecelerationRateFast = UIScrollViewDecelerationRateFast; -const CGFloat MGLMapViewDecelerationRateImmediate = 0.0; +const MGLMapViewDecelerationRate MGLMapViewDecelerationRateNormal = UIScrollViewDecelerationRateNormal; +const MGLMapViewDecelerationRate MGLMapViewDecelerationRateFast = UIScrollViewDecelerationRateFast; +const MGLMapViewDecelerationRate MGLMapViewDecelerationRateImmediate = 0.0; const MGLMapViewPreferredFramesPerSecond MGLMapViewPreferredFramesPerSecondDefault = -1; const MGLMapViewPreferredFramesPerSecond MGLMapViewPreferredFramesPerSecondLowPower = 30; -- cgit v1.2.1 From 6c55470c7e0ecb9c01824c201cf9bdeb86f0bb5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 9 Aug 2018 15:20:27 +0200 Subject: [android] - telemetry bump to 3.1.5 --- platform/android/gradle/dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index 8589c18112..b59993035a 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -9,7 +9,7 @@ ext { versions = [ mapboxServices : '3.4.0', - mapboxTelemetry: '3.1.4', + mapboxTelemetry: '3.1.5', mapboxGestures : '0.2.0', supportLib : '27.1.1', espresso : '3.0.2', -- cgit v1.2.1 From a378d6fc9b71d5a40750158c5f7c475669408052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 9 Aug 2018 18:53:57 +0200 Subject: [android] - changelog for 6.4.0-beta.1 --- platform/android/CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 5db2fb213c..2df4bf18da 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,12 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## 6.4.0-beta.1 - August 9, 2018 + - Don't prefetch tiles for geojson sources [#12529](https://github.com/mapbox/mapbox-gl-native/pull/12529) + - Enable LTO in release builds [#12546](https://github.com/mapbox/mapbox-gl-native/pull/12546) + - Update Java Services to v3.4.0 [#12564](https://github.com/mapbox/mapbox-gl-native/pull/12564) + - Telemetry bump to 3.1.5 [#12589](https://github.com/mapbox/mapbox-gl-native/pull/12589) + ## 6.4.0-alpha.2 - August 1, 2018 - Compress shader source code [#12477](https://github.com/mapbox/mapbox-gl-native/pull/12477) - Add minimal touch target to marker click detection [#12482](https://github.com/mapbox/mapbox-gl-native/pull/12482) -- cgit v1.2.1 From ec7b920603299f66332df3b324ed481c732b3657 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Thu, 9 Aug 2018 13:35:28 -0400 Subject: [ios] Standardize exception definitions --- platform/darwin/src/MGLComputedShapeSource.h | 2 ++ platform/darwin/src/MGLComputedShapeSource.mm | 12 ++++++++---- platform/darwin/src/MGLForegroundStyleLayer.mm | 2 +- platform/darwin/src/MGLOfflinePack.h | 3 +++ platform/darwin/src/MGLOfflinePack.mm | 4 +++- platform/darwin/src/MGLOfflineStorage.h | 2 ++ platform/darwin/src/MGLOfflineStorage.mm | 6 ++++-- platform/darwin/src/MGLShape.mm | 7 +++---- platform/darwin/src/MGLSource.mm | 2 +- platform/darwin/src/MGLStyle.h | 6 ++++++ platform/darwin/src/MGLStyle.mm | 20 +++++++++++++------- platform/darwin/src/MGLStyleLayer.h | 2 ++ platform/darwin/src/MGLStyleLayer.mm | 4 +++- platform/darwin/src/MGLStyleLayer_Private.h | 2 +- platform/darwin/src/MGLTilePyramidOfflineRegion.mm | 5 ++--- platform/darwin/src/MGLTileSource.mm | 4 ++-- platform/darwin/src/MGLTypes.h | 8 ++++++++ platform/darwin/src/MGLTypes.m | 2 ++ platform/darwin/src/MGLVectorStyleLayer.m | 4 ++-- platform/darwin/src/NSBundle+MGLAdditions.h | 2 ++ platform/darwin/src/NSBundle+MGLAdditions.m | 6 ++++-- platform/darwin/test/MGLOfflinePackTests.m | 8 ++++---- platform/darwin/test/MGLOfflineRegionTests.m | 2 +- platform/darwin/test/MGLStyleTests.mm | 20 ++++++++++---------- platform/ios/CHANGELOG.md | 1 + platform/ios/src/MGLMapView.h | 4 ++++ platform/ios/src/MGLMapView.mm | 17 +++++++++++------ 27 files changed, 105 insertions(+), 52 deletions(-) diff --git a/platform/darwin/src/MGLComputedShapeSource.h b/platform/darwin/src/MGLComputedShapeSource.h index faf8871fc7..84dc4801a7 100644 --- a/platform/darwin/src/MGLComputedShapeSource.h +++ b/platform/darwin/src/MGLComputedShapeSource.h @@ -32,6 +32,8 @@ FOUNDATION_EXTERN MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionWrap */ FOUNDATION_EXTERN MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionClipsCoordinates; +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLInvalidDatasourceException; + /** Data source for `MGLComputedShapeSource`. This protocol defines two optional methods for fetching data, one based on tile coordinates, and one based on a bounding box. Classes that implement this diff --git a/platform/darwin/src/MGLComputedShapeSource.mm b/platform/darwin/src/MGLComputedShapeSource.mm index 04734d0ef5..609db7f399 100644 --- a/platform/darwin/src/MGLComputedShapeSource.mm +++ b/platform/darwin/src/MGLComputedShapeSource.mm @@ -10,6 +10,8 @@ #include #include +const MGLExceptionName MGLInvalidDatasourceException = @"MGLInvalidDatasourceException"; + const MGLShapeSourceOption MGLShapeSourceOptionWrapsCoordinates = @"MGLShapeSourceOptionWrapsCoordinates"; const MGLShapeSourceOption MGLShapeSourceOptionClipsCoordinates = @"MGLShapeSourceOptionClipsCoordinates"; @@ -205,10 +207,12 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi self.dataSourceImplementsFeaturesForTile = [dataSource respondsToSelector:@selector(featuresInTileAtX:y:zoomLevel:)]; self.dataSourceImplementsFeaturesForBounds = [dataSource respondsToSelector:@selector(featuresInCoordinateBounds:zoomLevel:)]; - if(!self.dataSourceImplementsFeaturesForBounds && !self.dataSourceImplementsFeaturesForTile) { - [NSException raise:@"Invalid Datasource" format:@"Datasource does not implement any MGLComputedShapeSourceDataSource methods"]; - } else if(self.dataSourceImplementsFeaturesForBounds && self.dataSourceImplementsFeaturesForTile) { - [NSException raise:@"Invalid Datasource" format:@"Datasource implements multiple MGLComputedShapeSourceDataSource methods"]; + if (!self.dataSourceImplementsFeaturesForBounds && !self.dataSourceImplementsFeaturesForTile) { + [NSException raise:MGLInvalidDatasourceException + format:@"Datasource does not implement any MGLComputedShapeSourceDataSource methods"]; + } else if (self.dataSourceImplementsFeaturesForBounds && self.dataSourceImplementsFeaturesForTile) { + [NSException raise:MGLInvalidDatasourceException + format:@"Datasource implements multiple MGLComputedShapeSourceDataSource methods"]; } _dataSource = dataSource; diff --git a/platform/darwin/src/MGLForegroundStyleLayer.mm b/platform/darwin/src/MGLForegroundStyleLayer.mm index 6888f89b92..76700d6f77 100644 --- a/platform/darwin/src/MGLForegroundStyleLayer.mm +++ b/platform/darwin/src/MGLForegroundStyleLayer.mm @@ -3,7 +3,7 @@ @implementation MGLForegroundStyleLayer - (NSString *)sourceIdentifier { - [NSException raise:@"MGLAbstractClassException" + [NSException raise:MGLAbstractClassException format:@"MGLForegroundStyleLayer is an abstract class"]; return nil; } diff --git a/platform/darwin/src/MGLOfflinePack.h b/platform/darwin/src/MGLOfflinePack.h index dfc47bf1c8..3d22f74e72 100644 --- a/platform/darwin/src/MGLOfflinePack.h +++ b/platform/darwin/src/MGLOfflinePack.h @@ -1,10 +1,13 @@ #import #import "MGLFoundation.h" +#import "MGLTypes.h" #import "MGLOfflineRegion.h" NS_ASSUME_NONNULL_BEGIN +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLInvalidOfflinePackException; + /** The state an offline pack is currently in. */ diff --git a/platform/darwin/src/MGLOfflinePack.mm b/platform/darwin/src/MGLOfflinePack.mm index 4653021a58..9d903ee841 100644 --- a/platform/darwin/src/MGLOfflinePack.mm +++ b/platform/darwin/src/MGLOfflinePack.mm @@ -8,6 +8,8 @@ #include +const MGLExceptionName MGLInvalidOfflinePackException = @"MGLInvalidOfflinePackException"; + /** Assert that the current offline pack is valid. @@ -17,7 +19,7 @@ #define MGLAssertOfflinePackIsValid() \ do { \ if (_state == MGLOfflinePackStateInvalid) { \ - [NSException raise:@"Invalid offline pack" \ + [NSException raise:MGLInvalidOfflinePackException \ format: \ @"-[MGLOfflineStorage removePack:withCompletionHandler:] has been called " \ @"on this instance of MGLOfflinePack, rendering it invalid. It is an " \ diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h index 250efd23a6..f8ea6e7453 100644 --- a/platform/darwin/src/MGLOfflineStorage.h +++ b/platform/darwin/src/MGLOfflineStorage.h @@ -105,6 +105,8 @@ FOUNDATION_EXTERN MGL_EXPORT const MGLOfflinePackUserInfoKey MGLOfflinePackUserI FOUNDATION_EXTERN MGL_EXPORT NSString * const MGLOfflinePackMaximumCountUserInfoKey __attribute__((unavailable("Use MGLOfflinePackUserInfoKeyMaximumCount"))); +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLUnsupportedRegionTypeException; + /** A block to be called once an offline pack has been completely created and added. diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm index f4e454534d..e6c10e942b 100644 --- a/platform/darwin/src/MGLOfflineStorage.mm +++ b/platform/darwin/src/MGLOfflineStorage.mm @@ -30,6 +30,8 @@ const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyProgress = @"Progress"; const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyError = @"Error"; const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"MaximumCount"; +const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegionTypeException"; + @interface MGLOfflineStorage () @property (nonatomic, strong, readwrite) NSMutableArray *packs; @@ -278,8 +280,8 @@ const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"Maximu - (void)_addPackForRegion:(id )region withContext:(NSData *)context completionHandler:(MGLOfflinePackAdditionCompletionHandler)completion { if (![region conformsToProtocol:@protocol(MGLOfflineRegion_Private)]) { - [NSException raise:@"Unsupported region type" format: - @"Regions of type %@ are unsupported.", NSStringFromClass([region class])]; + [NSException raise:MGLUnsupportedRegionTypeException + format:@"Regions of type %@ are unsupported.", NSStringFromClass([region class])]; return; } diff --git a/platform/darwin/src/MGLShape.mm b/platform/darwin/src/MGLShape.mm index e76e06c7e4..59643dcb6a 100644 --- a/platform/darwin/src/MGLShape.mm +++ b/platform/darwin/src/MGLShape.mm @@ -40,7 +40,7 @@ bool operator==(const CLLocationCoordinate2D lhs, const CLLocationCoordinate2D r } - (mbgl::Geometry)geometryObject { - [NSException raise:@"MGLAbstractClassException" + [NSException raise:MGLAbstractClassException format:@"MGLShape is an abstract class"]; return mbgl::Point(); } @@ -103,9 +103,8 @@ bool operator==(const CLLocationCoordinate2D lhs, const CLLocationCoordinate2D r - (CLLocationCoordinate2D)coordinate { - [[NSException exceptionWithName:@"MGLAbstractClassException" - reason:@"MGLShape is an abstract class" - userInfo:nil] raise]; + [NSException raise:MGLAbstractClassException + format:@"MGLShape is an abstract class"]; return kCLLocationCoordinate2DInvalid; } diff --git a/platform/darwin/src/MGLSource.mm b/platform/darwin/src/MGLSource.mm index 6d57e14e8c..a32e223782 100644 --- a/platform/darwin/src/MGLSource.mm +++ b/platform/darwin/src/MGLSource.mm @@ -48,7 +48,7 @@ - (void)addToMapView:(MGLMapView *)mapView { if (_pendingSource == nullptr) { - [NSException raise:@"MGLRedundantSourceException" + [NSException raise:MGLRedundantSourceException format:@"This instance %@ was already added to %@. Adding the same source instance " \ "to the style more than once is invalid.", self, mapView.style]; } diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h index 814a09ed21..7b62432d36 100644 --- a/platform/darwin/src/MGLStyle.h +++ b/platform/darwin/src/MGLStyle.h @@ -31,6 +31,12 @@ NS_ASSUME_NONNULL_BEGIN */ static MGL_EXPORT const NSInteger MGLStyleDefaultVersion = 10; +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLInvalidStyleURLException; +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLRedundantLayerException; +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLRedundantLayerIdentifierException; +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLRedundantSourceException; +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLRedundantSourceIdentifierException; + /** The proxy object for the current map style. diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm index e0415c02f7..88499cf9bb 100644 --- a/platform/darwin/src/MGLStyle.mm +++ b/platform/darwin/src/MGLStyle.mm @@ -55,6 +55,12 @@ #import "NSImage+MGLAdditions.h" #endif +const MGLExceptionName MGLInvalidStyleURLException = @"MGLInvalidStyleURLException"; +const MGLExceptionName MGLRedundantLayerException = @"MGLRedundantLayerException"; +const MGLExceptionName MGLRedundantLayerIdentifierException = @"MGLRedundantLayerIdentifierException"; +const MGLExceptionName MGLRedundantSourceException = @"MGLRedundantSourceException"; +const MGLExceptionName MGLRedundantSourceIdentifierException = @"MGLRedundantSourceIdentifierException"; + /** Model class for localization changes. */ @@ -210,7 +216,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles, try { [source addToMapView:self.mapView]; } catch (std::runtime_error & err) { - [NSException raise:@"MGLRedundantSourceIdentifierException" format:@"%s", err.what()]; + [NSException raise:MGLRedundantSourceIdentifierException format:@"%s", err.what()]; } } @@ -313,14 +319,14 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles, MGLStyleLayer *sibling = layers.size() ? [self layerFromMBGLLayer:layers.at(0)] : nil; [styleLayer addToStyle:self belowLayer:sibling]; } catch (const std::runtime_error & err) { - [NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()]; + [NSException raise:MGLRedundantLayerIdentifierException format:@"%s", err.what()]; } } else { try { MGLStyleLayer *sibling = [self layerFromMBGLLayer:layers.at(index)]; [styleLayer addToStyle:self belowLayer:sibling]; } catch (std::runtime_error & err) { - [NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()]; + [NSException raise:MGLRedundantLayerIdentifierException format:@"%s", err.what()]; } } } @@ -402,7 +408,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles, try { [layer addToStyle:self belowLayer:nil]; } catch (std::runtime_error & err) { - [NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()]; + [NSException raise:MGLRedundantLayerIdentifierException format:@"%s", err.what()]; } [self didChangeValueForKey:@"layers"]; } @@ -431,7 +437,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles, try { [layer addToStyle:self belowLayer:sibling]; } catch (std::runtime_error & err) { - [NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()]; + [NSException raise:MGLRedundantLayerIdentifierException format:@"%s", err.what()]; } [self didChangeValueForKey:@"layers"]; } @@ -473,14 +479,14 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles, try { [layer addToStyle:self belowLayer:nil]; } catch (std::runtime_error & err) { - [NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()]; + [NSException raise:MGLRedundantLayerIdentifierException format:@"%s", err.what()]; } } else { MGLStyleLayer *sibling = [self layerFromMBGLLayer:layers.at(index + 1)]; try { [layer addToStyle:self belowLayer:sibling]; } catch (std::runtime_error & err) { - [NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()]; + [NSException raise:MGLRedundantLayerIdentifierException format:@"%s", err.what()]; } } [self didChangeValueForKey:@"layers"]; diff --git a/platform/darwin/src/MGLStyleLayer.h b/platform/darwin/src/MGLStyleLayer.h index b610a27607..60634946cb 100644 --- a/platform/darwin/src/MGLStyleLayer.h +++ b/platform/darwin/src/MGLStyleLayer.h @@ -5,6 +5,8 @@ NS_ASSUME_NONNULL_BEGIN +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLInvalidStyleLayerException; + /** `MGLStyleLayer` is an abstract base class for style layers. A style layer manages the layout and appearance of content at a specific z-index in a style. diff --git a/platform/darwin/src/MGLStyleLayer.mm b/platform/darwin/src/MGLStyleLayer.mm index 6400b8fcbf..05885bc63e 100644 --- a/platform/darwin/src/MGLStyleLayer.mm +++ b/platform/darwin/src/MGLStyleLayer.mm @@ -4,6 +4,8 @@ #include #include +const MGLExceptionName MGLInvalidStyleLayerException = @"MGLInvalidStyleLayerException"; + @interface MGLStyleLayer () @property (nonatomic, readonly) mbgl::style::Layer *rawLayer; @@ -33,7 +35,7 @@ - (void)addToStyle:(MGLStyle *)style belowLayer:(MGLStyleLayer *)otherLayer { if (_pendingLayer == nullptr) { - [NSException raise:@"MGLRedundantLayerException" + [NSException raise:MGLRedundantLayerException format:@"This instance %@ was already added to %@. Adding the same layer instance " \ "to the style more than once is invalid.", self, style]; } diff --git a/platform/darwin/src/MGLStyleLayer_Private.h b/platform/darwin/src/MGLStyleLayer_Private.h index 9bee013c3d..ea43c680e0 100644 --- a/platform/darwin/src/MGLStyleLayer_Private.h +++ b/platform/darwin/src/MGLStyleLayer_Private.h @@ -24,7 +24,7 @@ struct LayerWrapper { #define MGLAssertStyleLayerIsValid() \ do { \ if (!self.rawLayer) { \ - [NSException raise:@"Invalid style layer" \ + [NSException raise:MGLInvalidStyleLayerException \ format: \ @"-[MGLStyle removeLayer:] has been called " \ @"with this instance but another style layer instance was added with the same identifer. It is an " \ diff --git a/platform/darwin/src/MGLTilePyramidOfflineRegion.mm b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm index e0d56484bf..7333703267 100644 --- a/platform/darwin/src/MGLTilePyramidOfflineRegion.mm +++ b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm @@ -23,8 +23,7 @@ } - (instancetype)init { - [NSException raise:@"Method unavailable" - format: + [NSException raise:NSGenericException format: @"-[MGLTilePyramidOfflineRegion init] is unavailable. " @"Use -initWithStyleURL:bounds:fromZoomLevel:toZoomLevel: instead."]; return nil; @@ -37,7 +36,7 @@ } if (!styleURL.scheme) { - [NSException raise:@"Invalid style URL" format: + [NSException raise:MGLInvalidStyleURLException format: @"%@ does not support setting a relative file URL as the style URL. " @"To download the online resources required by this style, " @"specify a URL to an online copy of this style. " diff --git a/platform/darwin/src/MGLTileSource.mm b/platform/darwin/src/MGLTileSource.mm index 2fafc6fb51..eef3b33430 100644 --- a/platform/darwin/src/MGLTileSource.mm +++ b/platform/darwin/src/MGLTileSource.mm @@ -25,7 +25,7 @@ const MGLTileSourceOption MGLTileSourceOptionDEMEncoding = @"MGLTileSourceOption @implementation MGLTileSource - (NSURL *)configurationURL { - [NSException raise:@"MGLAbstractClassException" + [NSException raise:MGLAbstractClassException format:@"MGLTileSource is an abstract class"]; return nil; } @@ -41,7 +41,7 @@ const MGLTileSourceOption MGLTileSourceOptionDEMEncoding = @"MGLTileSourceOption } - (NSString *)attributionHTMLString { - [NSException raise:@"MGLAbstractClassException" + [NSException raise:MGLAbstractClassException format:@"MGLTileSource is an abstract class"]; return nil; } diff --git a/platform/darwin/src/MGLTypes.h b/platform/darwin/src/MGLTypes.h index 3abc116ad7..95065999af 100644 --- a/platform/darwin/src/MGLTypes.h +++ b/platform/darwin/src/MGLTypes.h @@ -30,6 +30,14 @@ NS_ASSUME_NONNULL_BEGIN typedef NSString *NSNotificationName; #endif +typedef NSString *MGLExceptionName NS_TYPED_EXTENSIBLE_ENUM; + +/** + :nodoc: Generic exceptions used across multiple disparate classes. Exceptions + that are unique to a class or class-cluster should be defined in those headers. + */ +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLAbstractClassException; + /** Indicates an error occurred in the Mapbox SDK. */ FOUNDATION_EXTERN MGL_EXPORT NSErrorDomain const MGLErrorDomain; diff --git a/platform/darwin/src/MGLTypes.m b/platform/darwin/src/MGLTypes.m index 01e9a1467c..89f88a9c1d 100644 --- a/platform/darwin/src/MGLTypes.m +++ b/platform/darwin/src/MGLTypes.m @@ -1,3 +1,5 @@ #import "MGLTypes.h" +const MGLExceptionName MGLAbstractClassException = @"MGLAbstractClassException"; + NSString * const MGLErrorDomain = @"MGLErrorDomain"; diff --git a/platform/darwin/src/MGLVectorStyleLayer.m b/platform/darwin/src/MGLVectorStyleLayer.m index da6da0ea7f..23f3556e0b 100644 --- a/platform/darwin/src/MGLVectorStyleLayer.m +++ b/platform/darwin/src/MGLVectorStyleLayer.m @@ -3,12 +3,12 @@ @implementation MGLVectorStyleLayer - (void)setPredicate:(NSPredicate *)predicate { - [NSException raise:@"MGLAbstractClassException" + [NSException raise:MGLAbstractClassException format:@"MGLVectorStyleLayer is an abstract class"]; } - (NSPredicate *)predicate { - [NSException raise:@"MGLAbstractClassException" + [NSException raise:MGLAbstractClassException format:@"MGLVectorStyleLayer is an abstract class"]; return nil; } diff --git a/platform/darwin/src/NSBundle+MGLAdditions.h b/platform/darwin/src/NSBundle+MGLAdditions.h index 86dc27f22c..dcafefedec 100644 --- a/platform/darwin/src/NSBundle+MGLAdditions.h +++ b/platform/darwin/src/NSBundle+MGLAdditions.h @@ -27,6 +27,8 @@ NS_ASSUME_NONNULL_BEGIN #define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) \ [[NSBundle mgl_frameworkBundle] localizedStringForKey:(key) value:(val) table:(tbl)] +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLBundleNotFoundException; + @interface NSBundle (MGLAdditions) /// Returns the bundle containing the SDK’s classes and Info.plist file. diff --git a/platform/darwin/src/NSBundle+MGLAdditions.m b/platform/darwin/src/NSBundle+MGLAdditions.m index 37f78963d3..d472e40b1f 100644 --- a/platform/darwin/src/NSBundle+MGLAdditions.m +++ b/platform/darwin/src/NSBundle+MGLAdditions.m @@ -2,6 +2,8 @@ #import "MGLAccountManager.h" +const MGLExceptionName MGLBundleNotFoundException = @"MGLBundleNotFoundException"; + @implementation NSBundle (MGLAdditions) + (instancetype)mgl_frameworkBundle { @@ -14,8 +16,8 @@ if (bundlePath) { bundle = [self bundleWithPath:bundlePath]; } else { - [NSException raise:@"MGLBundleNotFoundException" format: - @"The Mapbox framework bundle could not be found. If using the Mapbox Maps SDK for iOS as a static framework, make sure that Mapbox.bundle is copied into the root of the app bundle."]; + [NSException raise:MGLBundleNotFoundException + format:@"The Mapbox framework bundle could not be found. If using the Mapbox Maps SDK for iOS as a static framework, make sure that Mapbox.bundle is copied into the root of the app bundle."]; } } diff --git a/platform/darwin/test/MGLOfflinePackTests.m b/platform/darwin/test/MGLOfflinePackTests.m index f58f306e5d..a33665ff0a 100644 --- a/platform/darwin/test/MGLOfflinePackTests.m +++ b/platform/darwin/test/MGLOfflinePackTests.m @@ -12,10 +12,10 @@ XCTAssertEqual(invalidPack.state, MGLOfflinePackStateInvalid, @"Offline pack should be invalid when initialized independently of MGLOfflineStorage."); - XCTAssertThrowsSpecificNamed(invalidPack.region, NSException, @"Invalid offline pack", @"Invalid offline pack should raise an exception when accessing its region."); - XCTAssertThrowsSpecificNamed(invalidPack.context, NSException, @"Invalid offline pack", @"Invalid offline pack should raise an exception when accessing its context."); - XCTAssertThrowsSpecificNamed([invalidPack resume], NSException, @"Invalid offline pack", @"Invalid offline pack should raise an exception when being resumed."); - XCTAssertThrowsSpecificNamed([invalidPack suspend], NSException, @"Invalid offline pack", @"Invalid offline pack should raise an exception when being suspended."); + XCTAssertThrowsSpecificNamed(invalidPack.region, NSException, MGLInvalidOfflinePackException, @"Invalid offline pack should raise an exception when accessing its region."); + XCTAssertThrowsSpecificNamed(invalidPack.context, NSException, MGLInvalidOfflinePackException, @"Invalid offline pack should raise an exception when accessing its context."); + XCTAssertThrowsSpecificNamed([invalidPack resume], NSException, MGLInvalidOfflinePackException, @"Invalid offline pack should raise an exception when being resumed."); + XCTAssertThrowsSpecificNamed([invalidPack suspend], NSException, MGLInvalidOfflinePackException, @"Invalid offline pack should raise an exception when being suspended."); } - (void)testProgressBoxing { diff --git a/platform/darwin/test/MGLOfflineRegionTests.m b/platform/darwin/test/MGLOfflineRegionTests.m index ff079fe798..da9928741b 100644 --- a/platform/darwin/test/MGLOfflineRegionTests.m +++ b/platform/darwin/test/MGLOfflineRegionTests.m @@ -14,7 +14,7 @@ XCTAssertEqualObjects(region.styleURL, [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion], @"Streets isn’t the default style."); NSURL *localURL = [NSURL URLWithString:@"beautiful.style"]; - XCTAssertThrowsSpecificNamed([[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:localURL bounds:bounds fromZoomLevel:0 toZoomLevel:DBL_MAX], NSException, @"Invalid style URL", @"No exception raised when initializing region with a local file URL as the style URL."); + XCTAssertThrowsSpecificNamed([[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:localURL bounds:bounds fromZoomLevel:0 toZoomLevel:DBL_MAX], NSException, MGLInvalidStyleURLException, @"No exception raised when initializing region with a local file URL as the style URL."); } - (void)testEquality { diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm index 32243c1bec..f2a02963fc 100644 --- a/platform/darwin/test/MGLStyleTests.mm +++ b/platform/darwin/test/MGLStyleTests.mm @@ -156,15 +156,15 @@ - (void)testAddingSourcesTwice { MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"shapeSource" shape:nil options:nil]; [self.style addSource:shapeSource]; - XCTAssertThrowsSpecificNamed([self.style addSource:shapeSource], NSException, @"MGLRedundantSourceException"); + XCTAssertThrowsSpecificNamed([self.style addSource:shapeSource], NSException, MGLRedundantSourceException); MGLRasterTileSource *rasterTileSource = [[MGLRasterTileSource alloc] initWithIdentifier:@"rasterTileSource" configurationURL:[NSURL URLWithString:@".json"] tileSize:42]; [self.style addSource:rasterTileSource]; - XCTAssertThrowsSpecificNamed([self.style addSource:rasterTileSource], NSException, @"MGLRedundantSourceException"); + XCTAssertThrowsSpecificNamed([self.style addSource:rasterTileSource], NSException, MGLRedundantSourceException); MGLVectorTileSource *vectorTileSource = [[MGLVectorTileSource alloc] initWithIdentifier:@"vectorTileSource" configurationURL:[NSURL URLWithString:@".json"]]; [self.style addSource:vectorTileSource]; - XCTAssertThrowsSpecificNamed([self.style addSource:vectorTileSource], NSException, @"MGLRedundantSourceException"); + XCTAssertThrowsSpecificNamed([self.style addSource:vectorTileSource], NSException, MGLRedundantSourceException); } - (void)testAddingSourcesWithDuplicateIdentifiers { @@ -172,7 +172,7 @@ MGLVectorTileSource *source2 = [[MGLVectorTileSource alloc] initWithIdentifier:@"my-source" configurationURL:[NSURL URLWithString:@"mapbox://mapbox.mapbox-terrain-v2"]]; [self.style addSource: source1]; - XCTAssertThrowsSpecificNamed([self.style addSource: source2], NSException, @"MGLRedundantSourceIdentifierException"); + XCTAssertThrowsSpecificNamed([self.style addSource: source2], NSException, MGLRedundantSourceIdentifierException); } - (void)testRemovingSourcesBeforeAddingThem { @@ -265,27 +265,27 @@ MGLBackgroundStyleLayer *backgroundLayer = [[MGLBackgroundStyleLayer alloc] initWithIdentifier:@"backgroundLayer"]; [self.style addLayer:backgroundLayer]; - XCTAssertThrowsSpecificNamed([self.style addLayer:backgroundLayer], NSException, @"MGLRedundantLayerException"); + XCTAssertThrowsSpecificNamed([self.style addLayer:backgroundLayer], NSException, MGLRedundantLayerException); MGLCircleStyleLayer *circleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"circleLayer" source:source]; [self.style addLayer:circleLayer]; - XCTAssertThrowsSpecificNamed([self.style addLayer:circleLayer], NSException, @"MGLRedundantLayerException"); + XCTAssertThrowsSpecificNamed([self.style addLayer:circleLayer], NSException, MGLRedundantLayerException); MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"fillLayer" source:source]; [self.style addLayer:fillLayer]; - XCTAssertThrowsSpecificNamed([self.style addLayer:fillLayer], NSException, @"MGLRedundantLayerException"); + XCTAssertThrowsSpecificNamed([self.style addLayer:fillLayer], NSException, MGLRedundantLayerException); MGLLineStyleLayer *lineLayer = [[MGLLineStyleLayer alloc] initWithIdentifier:@"lineLayer" source:source]; [self.style addLayer:lineLayer]; - XCTAssertThrowsSpecificNamed([self.style addLayer:lineLayer], NSException, @"MGLRedundantLayerException"); + XCTAssertThrowsSpecificNamed([self.style addLayer:lineLayer], NSException, MGLRedundantLayerException); MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"rasterLayer" source:source]; [self.style addLayer:rasterLayer]; - XCTAssertThrowsSpecificNamed([self.style addLayer:rasterLayer], NSException, @"MGLRedundantLayerException"); + XCTAssertThrowsSpecificNamed([self.style addLayer:rasterLayer], NSException, MGLRedundantLayerException); MGLSymbolStyleLayer *symbolLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"symbolLayer" source:source]; [self.style addLayer:symbolLayer]; - XCTAssertThrowsSpecificNamed([self.style addLayer:symbolLayer], NSException, @"MGLRedundantLayerException"); + XCTAssertThrowsSpecificNamed([self.style addLayer:symbolLayer], NSException, MGLRedundantLayerException); } - (void)testAddingLayersWithDuplicateIdentifiers { diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index a904d15835..303d8160bf 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -5,6 +5,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ## master * Improved the Swift interface for `MGLMapView.decelerationRate`. ([#12584](https://github.com/mapbox/mapbox-gl-native/issues/12584)) +* Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) ## 4.3.0 diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h index 44d7ab9708..20bfeeef39 100644 --- a/platform/ios/src/MGLMapView.h +++ b/platform/ios/src/MGLMapView.h @@ -97,6 +97,10 @@ FOUNDATION_EXTERN MGL_EXPORT const MGLMapViewPreferredFramesPerSecond MGLMapView /** The maximum supported frame rate; typically 60 FPS. */ FOUNDATION_EXTERN MGL_EXPORT const MGLMapViewPreferredFramesPerSecond MGLMapViewPreferredFramesPerSecondMaximum; +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLMissingLocationServicesUsageDescriptionException; +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLUserLocationAnnotationTypeException; +FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const MGLResourceNotFoundException; + /** An interactive, customizable map view with an interface similar to the one provided by Apple’s MapKit. diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index fa0beb008d..7423c23c7b 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -92,6 +92,10 @@ const MGLMapViewPreferredFramesPerSecond MGLMapViewPreferredFramesPerSecondDefau const MGLMapViewPreferredFramesPerSecond MGLMapViewPreferredFramesPerSecondLowPower = 30; const MGLMapViewPreferredFramesPerSecond MGLMapViewPreferredFramesPerSecondMaximum = 60; +const MGLExceptionName MGLMissingLocationServicesUsageDescriptionException = @"MGLMissingLocationServicesUsageDescriptionException"; +const MGLExceptionName MGLUserLocationAnnotationTypeException = @"MGLUserLocationAnnotationTypeException"; +const MGLExceptionName MGLResourceNotFoundException = @"MGLResourceNotFoundException"; + /// Indicates the manner in which the map view is tracking the user location. typedef NS_ENUM(NSUInteger, MGLUserTrackingState) { /// The map view is not yet tracking the user location. @@ -138,7 +142,7 @@ static NSString * const MGLInvisibleStyleMarkerSymbolName = @"invisible_marker"; /// Prefix that denotes a sprite installed by MGLMapView, to avoid collisions /// with style-defined sprites. -NSString *const MGLAnnotationSpritePrefix = @"com.mapbox.sprites."; +NSString * const MGLAnnotationSpritePrefix = @"com.mapbox.sprites."; /// Slop area around the hit testing point, allowing for imprecise annotation selection. const CGFloat MGLAnnotationImagePaddingForHitTest = 5; @@ -4790,7 +4794,8 @@ public: NSString *suggestedUsageKeys = requiresWhenInUseUsageDescription ? @"NSLocationWhenInUseUsageDescription and (optionally) NSLocationAlwaysAndWhenInUseUsageDescription" : @"NSLocationWhenInUseUsageDescription and/or NSLocationAlwaysUsageDescription"; - [NSException raise:@"Missing Location Services usage description" format:@"This app must have a value for %@ in its Info.plist.", suggestedUsageKeys]; + [NSException raise:MGLMissingLocationServicesUsageDescriptionException + format:@"This app must have a value for %@ in its Info.plist.", suggestedUsageKeys]; } } @@ -4827,7 +4832,7 @@ public: userLocationAnnotationView = (MGLUserLocationAnnotationView *)[self.delegate mapView:self viewForAnnotation:self.userLocation]; if (userLocationAnnotationView && ! [userLocationAnnotationView isKindOfClass:MGLUserLocationAnnotationView.class]) { - [NSException raise:@"MGLUserLocationAnnotationTypeException" + [NSException raise:MGLUserLocationAnnotationTypeException format:@"User location annotation view must be a kind of MGLUserLocationAnnotationView. %@", userLocationAnnotationView.debugDescription]; } } @@ -6007,7 +6012,7 @@ public: if ( ! image) { - [NSException raise:@"MGLResourceNotFoundException" format: + [NSException raise:MGLResourceNotFoundException format: @"The resource named “%@” could not be found in the Mapbox framework bundle.", imageName]; } @@ -6296,8 +6301,8 @@ private: NSURL *url = URLString.length ? [NSURL URLWithString:URLString] : nil; if (URLString.length && !url) { - [NSException raise:@"Invalid style URL" format: - @"“%@” is not a valid style URL.", URLString]; + [NSException raise:MGLInvalidStyleURLException + format:@"“%@” is not a valid style URL.", URLString]; } self.styleURL = url; } -- cgit v1.2.1 From f117865e8e680ddb3d0e5cb03caee326afd46d98 Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Tue, 7 Aug 2018 19:26:42 -0400 Subject: [ios] Remove Xcode 7 compatibility typedefs --- platform/darwin/src/MGLTypes.h | 7 ------- 1 file changed, 7 deletions(-) diff --git a/platform/darwin/src/MGLTypes.h b/platform/darwin/src/MGLTypes.h index 95065999af..1c90d7968b 100644 --- a/platform/darwin/src/MGLTypes.h +++ b/platform/darwin/src/MGLTypes.h @@ -23,13 +23,6 @@ NS_ASSUME_NONNULL_BEGIN -#ifndef NS_STRING_ENUM - #define NS_STRING_ENUM - #define NS_EXTENSIBLE_STRING_ENUM - typedef NSString *NSErrorDomain; - typedef NSString *NSNotificationName; -#endif - typedef NSString *MGLExceptionName NS_TYPED_EXTENSIBLE_ENUM; /** -- cgit v1.2.1 From e6d323eef0117696ed86e0cb23956c1221a7bd02 Mon Sep 17 00:00:00 2001 From: Osana Babayan <32496536+osana@users.noreply.github.com> Date: Thu, 9 Aug 2018 12:00:25 -0700 Subject: changed version of mapbox services to 3.4.1 (#12594) --- platform/android/gradle/dependencies.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle index b59993035a..303dd2f4b4 100644 --- a/platform/android/gradle/dependencies.gradle +++ b/platform/android/gradle/dependencies.gradle @@ -8,7 +8,7 @@ ext { ] versions = [ - mapboxServices : '3.4.0', + mapboxServices : '3.4.1', mapboxTelemetry: '3.1.5', mapboxGestures : '0.2.0', supportLib : '27.1.1', -- cgit v1.2.1 From bd2062f006a13e82e30619e55c77f867b1ed6e0e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Thu, 9 Aug 2018 03:43:33 -0700 Subject: [macos] Added zoom level options to Add Offline Pack sheet --- platform/macos/app/Base.lproj/MapDocument.xib | 185 +++++++++++++++++++++++++- platform/macos/app/MapDocument.m | 67 ++++++---- 2 files changed, 223 insertions(+), 29 deletions(-) diff --git a/platform/macos/app/Base.lproj/MapDocument.xib b/platform/macos/app/Base.lproj/MapDocument.xib index 5d0525a29d..72fa024fcc 100644 --- a/platform/macos/app/Base.lproj/MapDocument.xib +++ b/platform/macos/app/Base.lproj/MapDocument.xib @@ -1,15 +1,21 @@ - + - + + + + + + + @@ -57,7 +63,7 @@ - + @@ -71,7 +77,7 @@ - + @@ -88,7 +94,7 @@ - + @@ -133,7 +139,7 @@ - + @@ -301,8 +307,175 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m index 9ba28f3b37..805ffe35f0 100644 --- a/platform/macos/app/MapDocument.m +++ b/platform/macos/app/MapDocument.m @@ -75,6 +75,12 @@ NSArray> *MBXFlattenedShapes(NSArray> *sha @property (weak) IBOutlet NSTableView *styleLayersTableView; @property (weak) IBOutlet NSMenu *mapViewContextMenu; @property (weak) IBOutlet NSSplitView *splitView; +@property (weak) IBOutlet NSWindow *addOfflinePackWindow; +@property (weak) IBOutlet NSTextField *offlinePackNameField; +@property (weak) IBOutlet NSTextField *minimumOfflinePackZoomLevelField; +@property (weak) IBOutlet NSNumberFormatter *minimumOfflinePackZoomLevelFormatter; +@property (weak) IBOutlet NSTextField *maximumOfflinePackZoomLevelField; +@property (weak) IBOutlet NSNumberFormatter *maximumOfflinePackZoomLevelFormatter; @end @@ -915,33 +921,48 @@ NSArray> *MBXFlattenedShapes(NSArray> *sha #pragma mark Offline packs - (IBAction)addOfflinePack:(id)sender { - NSAlert *namePrompt = [[NSAlert alloc] init]; - namePrompt.messageText = @"Add offline pack"; - namePrompt.informativeText = @"Choose a name for the pack:"; - NSTextField *nameTextField = [[NSTextField alloc] initWithFrame:NSZeroRect]; - nameTextField.placeholderString = MGLStringFromCoordinateBounds(self.mapView.visibleCoordinateBounds); - [nameTextField sizeToFit]; - NSRect textFieldFrame = nameTextField.frame; - textFieldFrame.size.width = 300; - nameTextField.frame = textFieldFrame; - namePrompt.accessoryView = nameTextField; - [namePrompt addButtonWithTitle:@"Add"]; - [namePrompt addButtonWithTitle:@"Cancel"]; - if ([namePrompt runModal] != NSAlertFirstButtonReturn) { - return; - } - - id region = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:self.mapView.styleURL bounds:self.mapView.visibleCoordinateBounds fromZoomLevel:self.mapView.zoomLevel toZoomLevel:self.mapView.maximumZoomLevel]; - NSData *context = [[NSValueTransformer valueTransformerForName:@"OfflinePackNameValueTransformer"] reverseTransformedValue:nameTextField.stringValue]; - [[MGLOfflineStorage sharedOfflineStorage] addPackForRegion:region withContext:context completionHandler:^(MGLOfflinePack * _Nullable pack, NSError * _Nullable error) { - if (error) { - [[NSAlert alertWithError:error] runModal]; - } else { - [pack resume]; + self.offlinePackNameField.stringValue = @""; + self.offlinePackNameField.placeholderString = MGLStringFromCoordinateBounds(self.mapView.visibleCoordinateBounds); + self.minimumOfflinePackZoomLevelField.doubleValue = floor(self.mapView.zoomLevel); + self.maximumOfflinePackZoomLevelField.doubleValue = ceil(self.mapView.maximumZoomLevel); + self.minimumOfflinePackZoomLevelFormatter.minimum = @(floor(self.mapView.minimumZoomLevel)); + self.maximumOfflinePackZoomLevelFormatter.minimum = @(floor(self.mapView.minimumZoomLevel)); + self.minimumOfflinePackZoomLevelFormatter.maximum = @(ceil(self.mapView.maximumZoomLevel)); + self.maximumOfflinePackZoomLevelFormatter.maximum = @(ceil(self.mapView.maximumZoomLevel)); + + [self.addOfflinePackWindow makeFirstResponder:self.offlinePackNameField]; + + __weak __typeof__(self) weakSelf = self; + [self.window beginSheet:self.addOfflinePackWindow completionHandler:^(NSModalResponse returnCode) { + __typeof__(self) strongSelf = weakSelf; + if (!strongSelf || returnCode != NSModalResponseOK) { + return; + } + + id region = + [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:strongSelf.mapView.styleURL + bounds:strongSelf.mapView.visibleCoordinateBounds + fromZoomLevel:strongSelf.minimumOfflinePackZoomLevelField.integerValue + toZoomLevel:strongSelf.maximumOfflinePackZoomLevelField.integerValue]; + NSString *name = strongSelf.offlinePackNameField.stringValue; + if (!name.length) { + name = strongSelf.offlinePackNameField.placeholderString; } + NSData *context = [[NSValueTransformer valueTransformerForName:@"OfflinePackNameValueTransformer"] reverseTransformedValue:name]; + [[MGLOfflineStorage sharedOfflineStorage] addPackForRegion:region withContext:context completionHandler:^(MGLOfflinePack * _Nullable pack, NSError * _Nullable error) { + if (error) { + [[NSAlert alertWithError:error] runModal]; + } else { + [pack resume]; + } + }]; }]; } +- (IBAction)confirmAddingOfflinePack:(id)sender { + [self.window endSheet:self.addOfflinePackWindow returnCode:[sender tag] ? NSModalResponseOK : NSModalResponseCancel]; +} + #pragma mark Mouse events - (void)handlePressGesture:(NSPressGestureRecognizer *)gestureRecognizer { -- cgit v1.2.1 From c2f7d8a9fd8d59499379dac20b50dab79be5e2f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Thu, 9 Aug 2018 04:10:06 -0700 Subject: [macos] Play sound when offline pack completes or errors Play a sound when an offline pack being added finishes downloading or encounters an error. --- platform/macos/app/AppDelegate.h | 2 ++ platform/macos/app/AppDelegate.m | 26 ++++++++++++++++++++++++++ platform/macos/app/MapDocument.m | 1 + 3 files changed, 29 insertions(+) diff --git a/platform/macos/app/AppDelegate.h b/platform/macos/app/AppDelegate.h index a1d9297b2f..87b7514292 100644 --- a/platform/macos/app/AppDelegate.h +++ b/platform/macos/app/AppDelegate.h @@ -21,4 +21,6 @@ extern NSString * const MGLMapboxAccessTokenDefaultsKey; @property (copy) NSURL *pendingStyleURL; @property (assign) MGLMapDebugMaskOptions pendingDebugMask; +- (void)watchOfflinePack:(MGLOfflinePack *)pack; + @end diff --git a/platform/macos/app/AppDelegate.m b/platform/macos/app/AppDelegate.m index f7b35d0c83..eda989d7f9 100644 --- a/platform/macos/app/AppDelegate.m +++ b/platform/macos/app/AppDelegate.m @@ -135,6 +135,8 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask"; } - (void)applicationWillTerminate:(NSNotification *)notification { + [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:nil]; + if (![[NSUserDefaults standardUserDefaults] boolForKey:@"NSQuitAlwaysKeepsWindows"]) { NSDocument *currentDocument = [NSDocumentController sharedDocumentController].currentDocument; if ([currentDocument isKindOfClass:[MapDocument class]]) { @@ -204,6 +206,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask"; - (IBAction)delete:(id)sender { for (MGLOfflinePack *pack in self.offlinePacksArrayController.selectedObjects) { + [self unwatchOfflinePack:pack]; [[MGLOfflineStorage sharedOfflineStorage] removePack:pack withCompletionHandler:^(NSError * _Nullable error) { if (error) { [[NSAlert alertWithError:error] runModal]; @@ -228,11 +231,13 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask"; } case MGLOfflinePackStateInactive: + [self watchOfflinePack:pack]; [pack resume]; break; case MGLOfflinePackStateActive: [pack suspend]; + [self unwatchOfflinePack:pack]; break; default: @@ -241,6 +246,27 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask"; } } +- (void)watchOfflinePack:(MGLOfflinePack *)pack { + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackDidChangeProgress:) name:MGLOfflinePackProgressChangedNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackDidReceiveError:) name:MGLOfflinePackErrorNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(offlinePackDidReceiveError:) name:MGLOfflinePackMaximumMapboxTilesReachedNotification object:nil]; +} + +- (void)unwatchOfflinePack:(MGLOfflinePack *)pack { + [[NSNotificationCenter defaultCenter] removeObserver:self name:nil object:pack]; +} + +- (void)offlinePackDidChangeProgress:(NSNotification *)notification { + MGLOfflinePack *pack = notification.object; + if (pack.state == MGLOfflinePackStateComplete) { + [[NSSound soundNamed:@"Glass"] play]; + } +} + +- (void)offlinePackDidReceiveError:(NSNotification *)notification { + [[NSSound soundNamed:@"Basso"] play]; +} + #pragma mark Help methods - (IBAction)showShortcuts:(id)sender { diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m index 805ffe35f0..447929201c 100644 --- a/platform/macos/app/MapDocument.m +++ b/platform/macos/app/MapDocument.m @@ -953,6 +953,7 @@ NSArray> *MBXFlattenedShapes(NSArray> *sha if (error) { [[NSAlert alertWithError:error] runModal]; } else { + [(AppDelegate *)NSApp.delegate watchOfflinePack:pack]; [pack resume]; } }]; -- cgit v1.2.1 From fc0745a699a0ef60c080e9c2ff5eaecde9cb5306 Mon Sep 17 00:00:00 2001 From: Sudarsana Babu Nagineni Date: Thu, 9 Aug 2018 17:13:05 +0300 Subject: [core] Fix build when building Qt Location plugin for Android - log2 is not available on Android before API 18. - Android doesn't have 'round' on the std:: namespace when using g++. Co-authored-by: Thiago Marcos P. Santos --- include/mbgl/math/log2.hpp | 16 ++++++++++++++++ src/mbgl/renderer/buckets/symbol_bucket.cpp | 4 ++-- src/mbgl/util/tile_cover.cpp | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/include/mbgl/math/log2.hpp b/include/mbgl/math/log2.hpp index 6a1ba23ed9..3136ac22b4 100644 --- a/include/mbgl/math/log2.hpp +++ b/include/mbgl/math/log2.hpp @@ -2,6 +2,11 @@ #include #include +#include + +#if defined(__ANDROID__) +#include +#endif namespace mbgl { namespace util { @@ -12,3 +17,14 @@ uint32_t ceil_log2(uint64_t x); } // namespace util } // namespace mbgl + +// log2 is not available on Android before API 18. +#if defined(__ANDROID__) && defined(__GNUC__) && \ + defined(__ANDROID_API__) && __ANDROID_API__ < 18 + +template +typename std::enable_if_t::value, T> log2(T x) { + return ::log(x) / M_LN2; +} + +#endif diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp index 027e864be5..a3f652fc6e 100644 --- a/src/mbgl/renderer/buckets/symbol_bucket.cpp +++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp @@ -193,8 +193,8 @@ void SymbolBucket::sortFeatures(const float angle) { std::sort(symbolInstanceIndexes.begin(), symbolInstanceIndexes.end(), [sin, cos, this](size_t &aIndex, size_t &bIndex) { const SymbolInstance& a = symbolInstances[aIndex]; const SymbolInstance& b = symbolInstances[bIndex]; - const int32_t aRotated = static_cast(std::lround(sin * a.anchor.point.x + cos * a.anchor.point.y)); - const int32_t bRotated = static_cast(std::lround(sin * b.anchor.point.x + cos * b.anchor.point.y)); + const int32_t aRotated = static_cast(::lround(sin * a.anchor.point.x + cos * a.anchor.point.y)); + const int32_t bRotated = static_cast(::lround(sin * b.anchor.point.x + cos * b.anchor.point.y)); return aRotated != bRotated ? aRotated < bRotated : a.dataFeatureIndex > b.dataFeatureIndex; diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp index 3f39e53d40..f58d1270bd 100644 --- a/src/mbgl/util/tile_cover.cpp +++ b/src/mbgl/util/tile_cover.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include -- cgit v1.2.1 From 8ae5ea953e413e12813ee94d34cd0cd14bce3d8a Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Mon, 6 Aug 2018 13:33:38 +0200 Subject: [qt] Use FollowRedirectsAttribute in network requests --- platform/qt/src/http_file_source.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/qt/src/http_file_source.cpp b/platform/qt/src/http_file_source.cpp index 6e70693241..b95cfed0e9 100644 --- a/platform/qt/src/http_file_source.cpp +++ b/platform/qt/src/http_file_source.cpp @@ -29,6 +29,9 @@ void HTTPFileSource::Impl::request(HTTPRequest* req) } QNetworkRequest networkRequest = req->networkRequest(); +#if QT_VERSION >= 0x050600 + networkRequest.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); +#endif data.first = m_manager->get(networkRequest); connect(data.first, SIGNAL(finished()), this, SLOT(onReplyFinished())); @@ -72,7 +75,7 @@ void HTTPFileSource::Impl::cancel(HTTPRequest* req) void HTTPFileSource::Impl::onReplyFinished() { QNetworkReply* reply = qobject_cast(sender()); - const QUrl& url = reply->url(); + const QUrl& url = reply->request().url(); auto it = m_pending.find(url); if (it == m_pending.end()) { -- cgit v1.2.1 From 070f50d6b032942591fcc392fc4bdd72bddc31c4 Mon Sep 17 00:00:00 2001 From: Vladimir Kondrashov Date: Thu, 9 Aug 2018 14:15:01 -0700 Subject: Update mbgl.cmake --- cmake/mbgl.cmake | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cmake/mbgl.cmake b/cmake/mbgl.cmake index 338c2fd708..bb029a47db 100644 --- a/cmake/mbgl.cmake +++ b/cmake/mbgl.cmake @@ -115,7 +115,7 @@ endfunction() # Creates a library target for a vendored dependency function(add_vendor_target NAME TYPE) - add_library(${NAME} ${TYPE} cmake/empty.cpp) + add_library(${NAME} ${TYPE} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/empty.cpp") set(INCLUDE_TYPE "INTERFACE") set(SOURCE_TYPE "INTERFACE") if (TYPE STREQUAL "STATIC" OR TYPE STREQUAL "SHARED") @@ -124,11 +124,11 @@ function(add_vendor_target NAME TYPE) set_target_properties(${NAME} PROPERTIES SOURCES "") endif() set_target_properties(${NAME} PROPERTIES INTERFACE_SOURCES "") - file(STRINGS vendor/${NAME}/files.txt FILES) + file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/vendor/${NAME}/files.txt" FILES) foreach(FILE IN LISTS FILES) - target_sources(${NAME} ${SOURCE_TYPE} "${CMAKE_SOURCE_DIR}/vendor/${NAME}/${FILE}") + target_sources(${NAME} ${SOURCE_TYPE} "${CMAKE_CURRENT_SOURCE_DIR}/vendor/${NAME}/${FILE}") endforeach() - target_include_directories(${NAME} ${INCLUDE_TYPE} vendor/${NAME}/include) + target_include_directories(${NAME} ${INCLUDE_TYPE} "${CMAKE_CURRENT_SOURCE_DIR}/vendor/${NAME}/include") create_source_groups(${NAME}) endfunction() -- cgit v1.2.1 From b500577bfa9759241b374c161a06c1bef79cf4cd Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 9 Aug 2018 12:15:09 -0700 Subject: [android, linux] Upgrade to SQLite 3.24.0, compiled to minimize binary size --- circle.yml | 6 +++--- cmake/mason-dependencies.cmake | 4 ++-- cmake/mason.cmake | 4 ++-- test/storage/offline_database.test.cpp | 16 ++++++++++------ 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/circle.yml b/circle.yml index 6c4724600e..f6b8c6f47a 100644 --- a/circle.yml +++ b/circle.yml @@ -110,14 +110,14 @@ step-library: - &save-mason_packages-cache save_cache: name: Save mason_packages cache - key: 'mason_packages/v1/{{ arch }}/{{ checksum "cmake/mason-dependencies.cmake" }}' + key: 'mason_packages/v3/{{ arch }}/{{ checksum "cmake/mason-dependencies.cmake" }}' paths: [ "mason_packages/.binaries" ] - &restore-mason_packages-cache restore_cache: name: Restore mason_packages cache keys: - - 'mason_packages/v1/{{ arch }}/{{ checksum "cmake/mason-dependencies.cmake" }}' - - 'mason_packages/v1/{{ arch }}' + - 'mason_packages/v3/{{ arch }}/{{ checksum "cmake/mason-dependencies.cmake" }}' + - 'mason_packages/v3/{{ arch }}' - &save-ccache save_cache: name: Save ccache diff --git a/cmake/mason-dependencies.cmake b/cmake/mason-dependencies.cmake index cffce0a440..826dcf2e45 100644 --- a/cmake/mason-dependencies.cmake +++ b/cmake/mason-dependencies.cmake @@ -20,13 +20,13 @@ mason_use(vector-tile VERSION 1.0.2 HEADER_ONLY) if(MBGL_PLATFORM STREQUAL "android") mason_use(jni.hpp VERSION 3.0.0 HEADER_ONLY) - mason_use(sqlite VERSION 3.14.2) + mason_use(sqlite VERSION 3.24.0-min-size) mason_use(icu VERSION 58.1-min-size) elseif(MBGL_PLATFORM STREQUAL "ios") mason_use(icu VERSION 58.1-min-size) elseif(MBGL_PLATFORM STREQUAL "linux") mason_use(glfw VERSION 2018-06-27-0be4f3f) - mason_use(sqlite VERSION 3.14.2) + mason_use(sqlite VERSION 3.24.0-min-size) mason_use(libuv VERSION 1.9.1) mason_use(libpng VERSION 1.6.25) mason_use(libjpeg-turbo VERSION 1.5.0) diff --git a/cmake/mason.cmake b/cmake/mason.cmake index 6116067080..00d268421a 100644 --- a/cmake/mason.cmake +++ b/cmake/mason.cmake @@ -24,11 +24,11 @@ function(mason_detect_platform) # Android Studio only passes ANDROID_ABI, but we need to adjust that to the Mason if(MASON_PLATFORM STREQUAL "android" AND NOT MASON_PLATFORM_VERSION) if (ANDROID_ABI STREQUAL "armeabi-v7a") - set(MASON_PLATFORM_VERSION "arm-v7-9" PARENT_SCOPE) + set(MASON_PLATFORM_VERSION "arm-v7-14" PARENT_SCOPE) elseif (ANDROID_ABI STREQUAL "arm64-v8a") set(MASON_PLATFORM_VERSION "arm-v8-21" PARENT_SCOPE) elseif (ANDROID_ABI STREQUAL "x86") - set(MASON_PLATFORM_VERSION "x86-9" PARENT_SCOPE) + set(MASON_PLATFORM_VERSION "x86-14" PARENT_SCOPE) elseif (ANDROID_ABI STREQUAL "x86_64") set(MASON_PLATFORM_VERSION "x86-64-21" PARENT_SCOPE) else() diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index 10343ec305..000f24e1cd 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -49,8 +49,12 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(Invalid)) { #ifndef __QT__ // Only non-Qt platforms are setting a logger on the SQLite object. - EXPECT_EQ(1u, log.count({ EventSeverity::Info, Event::Database, static_cast(mapbox::sqlite::ResultCode::NotADB), - "statement aborts at 1: [PRAGMA user_version] file is encrypted or is not a database" }, true)); + // Checking two possibilities for the error string because it apparently changes between SQLite versions. + EXPECT_EQ(1u, + log.count({ EventSeverity::Info, Event::Database, static_cast(mapbox::sqlite::ResultCode::NotADB), + "statement aborts at 1: [PRAGMA user_version] file is encrypted or is not a database" }, true) + + log.count({ EventSeverity::Info, Event::Database, static_cast(mapbox::sqlite::ResultCode::NotADB), + "statement aborts at 1: [PRAGMA user_version] file is not a database" }, true)); #endif EXPECT_EQ(1u, log.count({ EventSeverity::Warning, Event::Database, -1, "Removing existing incompatible offline database" })); EXPECT_EQ(0u, log.uncheckedCount()); @@ -618,15 +622,15 @@ TEST(OfflineDatabase, BatchInsertionMapboxTileCountExceeded) { db.setOfflineMapboxTileCountLimit(1); OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; OfflineRegion region = db.createRegion(definition, OfflineRegionMetadata()); - + Response response; response.data = randomString(1024); std::list> resources; - + resources.emplace_back(Resource::style("http://example.com/"), response); resources.emplace_back(Resource::tile("mapbox://tiles/1", 1.0, 0, 0, 0, Tileset::Scheme::XYZ), response); resources.emplace_back(Resource::tile("mapbox://tiles/2", 1.0, 0, 0, 0, Tileset::Scheme::XYZ), response); - + OfflineRegionStatus status; try { db.putRegionResources(region.getID(), resources, status); @@ -634,7 +638,7 @@ TEST(OfflineDatabase, BatchInsertionMapboxTileCountExceeded) { } catch (const MapboxTileLimitExceededException&) { // Expected } - + EXPECT_EQ(status.completedTileCount, 1u); EXPECT_EQ(status.completedResourceCount, 2u); EXPECT_EQ(db.getRegionCompletedStatus(region.getID()).completedTileCount, 1u); -- cgit v1.2.1 From 63d4ac05f20190d7ac3df1f852840e9678b9e7dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 31 Jul 2018 19:42:09 +0200 Subject: [android] shutting down thread pool of the CustomGeometrySource when the source is destroyed --- .../style/sources/CustomGeometrySource.java | 83 +++++++++++++++++----- .../testapp/style/CustomGeometrySourceTest.kt | 68 ++++++++++++++++++ .../testapp/activity/style/GridSourceActivity.java | 12 ++-- platform/android/src/native_map_view.cpp | 4 +- .../src/style/sources/custom_geometry_source.cpp | 39 +++++++++- .../src/style/sources/custom_geometry_source.hpp | 5 ++ platform/android/src/style/sources/source.cpp | 7 +- platform/android/src/style/sources/source.hpp | 6 +- 8 files changed, 198 insertions(+), 26 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java index 1f6029e2a2..6c0b76f00e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/CustomGeometrySource.java @@ -15,18 +15,26 @@ import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; /** * Custom Vector Source, allows using FeatureCollections. - * */ @UiThread public class CustomGeometrySource extends Source { + public static final String THREAD_PREFIX = "CustomGeom"; + public static final int THREAD_POOL_LIMIT = 4; + private static final AtomicInteger poolCount = new AtomicInteger(); + private final Lock executorLock = new ReentrantLock(); private ExecutorService executor; private GeometryTileProvider provider; private final Map cancelledTileRequests = new ConcurrentHashMap<>(); @@ -34,7 +42,7 @@ public class CustomGeometrySource extends Source { /** * Create a CustomGeometrySource * - * @param id The source id. + * @param id The source id. * @param provider The tile provider that returns geometry data for this source. */ public CustomGeometrySource(String id, GeometryTileProvider provider) { @@ -45,21 +53,20 @@ public class CustomGeometrySource extends Source { * Create a CustomGeometrySource with non-default CustomGeometrySourceOptions. *

Supported options are minZoom, maxZoom, buffer, and tolerance.

* - * @param id The source id. + * @param id The source id. * @param provider The tile provider that returns geometry data for this source. - * @param options CustomGeometrySourceOptions. + * @param options CustomGeometrySourceOptions. */ public CustomGeometrySource(String id, GeometryTileProvider provider, CustomGeometrySourceOptions options) { super(); this.provider = provider; - executor = Executors.newFixedThreadPool(4); initialize(id, options); } /** - * Invalidate previously provided features within a given bounds at all zoom levels. - * Invoking this method will result in new requests to `GeometryTileProvider` for regions - * that contain, include, or intersect with the provided bounds. + * Invalidate previously provided features within a given bounds at all zoom levels. + * Invoking this method will result in new requests to `GeometryTileProvider` for regions + * that contain, include, or intersect with the provided bounds. * * @param bounds The region in which features should be invalidated at all zoom levels */ @@ -73,8 +80,8 @@ public class CustomGeometrySource extends Source { * in new requests to `GeometryTileProvider` for visible tiles. * * @param zoomLevel Tile zoom level. - * @param x Tile X coordinate. - * @param y Tile Y coordinate. + * @param x Tile X coordinate. + * @param y Tile Y coordinate. */ public void invalidateTile(int zoomLevel, int x, int y) { checkThread(); @@ -87,9 +94,9 @@ public class CustomGeometrySource extends Source { * background threads. * * @param zoomLevel Tile zoom level. - * @param x Tile X coordinate. - * @param y Tile Y coordinate. - * @param data Feature collection for the tile. + * @param x Tile X coordinate. + * @param y Tile Y coordinate. + * @param data Feature collection for the tile. */ public void setTileData(int zoomLevel, int x, int y, FeatureCollection data) { checkThread(); @@ -140,7 +147,15 @@ public class CustomGeometrySource extends Source { TileID tileID = new TileID(z, x, y); cancelledTileRequests.put(tileID, cancelFlag); GeometryTileRequest request = new GeometryTileRequest(tileID, provider, this, cancelFlag); - executor.execute(request); + + executorLock.lock(); + try { + if (executor != null && !executor.isShutdown()) { + executor.execute(request); + } + } finally { + executorLock.unlock(); + } } @WorkerThread @@ -152,6 +167,40 @@ public class CustomGeometrySource extends Source { } } + @Keep + private void startThreads() { + executorLock.lock(); + try { + if (executor != null && !executor.isShutdown()) { + executor.shutdownNow(); + } + + executor = Executors.newFixedThreadPool(THREAD_POOL_LIMIT, new ThreadFactory() { + final AtomicInteger threadCount = new AtomicInteger(); + final int poolId = poolCount.getAndIncrement(); + + @Override + public Thread newThread(@NonNull Runnable runnable) { + return new Thread( + runnable, + String.format(Locale.US, "%s-%d-%d", THREAD_PREFIX, poolId, threadCount.getAndIncrement())); + } + }); + } finally { + executorLock.unlock(); + } + } + + @Keep + private void releaseThreads() { + executorLock.lock(); + try { + executor.shutdownNow(); + } finally { + executorLock.unlock(); + } + } + private static class TileID { public int z; public int x; @@ -164,7 +213,7 @@ public class CustomGeometrySource extends Source { } public int hashCode() { - return Arrays.hashCode(new int[]{z, x, y}); + return Arrays.hashCode(new int[] {z, x, y}); } public boolean equals(Object object) { @@ -177,7 +226,7 @@ public class CustomGeometrySource extends Source { } if (object instanceof TileID) { - TileID other = (TileID)object; + TileID other = (TileID) object; return this.z == other.z && this.x == other.x && this.y == other.y; } return false; @@ -205,7 +254,7 @@ public class CustomGeometrySource extends Source { FeatureCollection data = provider.getFeaturesForBounds(LatLngBounds.from(id.z, id.x, id.y), id.z); CustomGeometrySource source = sourceRef.get(); - if (!isCancelled() && source != null && data != null) { + if (!isCancelled() && source != null && data != null) { source.setTileData(id, data); } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt new file mode 100644 index 0000000000..1496cb704d --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt @@ -0,0 +1,68 @@ +package com.mapbox.mapboxsdk.testapp.style + +import android.support.test.espresso.Espresso.onView +import android.support.test.espresso.matcher.ViewMatchers.isRoot +import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource +import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource.THREAD_POOL_LIMIT +import com.mapbox.mapboxsdk.style.sources.CustomGeometrySource.THREAD_PREFIX +import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke +import com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscape +import com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationPortrait +import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest +import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity +import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity.ID_GRID_LAYER +import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity.ID_GRID_SOURCE +import org.junit.Assert +import org.junit.Test + +class CustomGeometrySourceTest : BaseActivityTest() { + + override fun getActivityClass(): Class<*> = GridSourceActivity::class.java + + @Test + fun sourceNotLeakingThreadsTest() { + validateTestSetup() + waitAction(4000) + onView(isRoot()).perform(orientationLandscape()) + waitAction(2000) + onView(isRoot()).perform(orientationPortrait()) + waitAction(2000) + Assert.assertFalse("Threads should be shutdown when the source is destroyed.", + Thread.getAllStackTraces().keys.filter { + it.name.startsWith(THREAD_PREFIX) + }.count() > THREAD_POOL_LIMIT) + } + + @Test + fun threadsShutdownWhenSourceRemovedTest() { + validateTestSetup() + invoke(mapboxMap) { uiController, mapboxMap -> + mapboxMap.removeLayer(ID_GRID_LAYER) + uiController.loopMainThreadForAtLeast(3000) + mapboxMap.removeSource(ID_GRID_SOURCE) + uiController.loopMainThreadForAtLeast(1000) + Assert.assertTrue("There should be no threads running when the source is removed.", + Thread.getAllStackTraces().keys.filter { + it.name.startsWith(CustomGeometrySource.THREAD_PREFIX) + }.count() == 0) + } + } + + @Test + fun threadsRestartedWhenSourceReAddedTest() { + validateTestSetup() + invoke(mapboxMap) { uiController, mapboxMap -> + mapboxMap.removeLayer((rule.activity as GridSourceActivity).layer) + uiController.loopMainThreadForAtLeast(3000) + mapboxMap.removeSource(ID_GRID_SOURCE) + uiController.loopMainThreadForAtLeast(1000) + mapboxMap.addSource((rule.activity as GridSourceActivity).source) + mapboxMap.addLayer((rule.activity as GridSourceActivity).layer) + uiController.loopMainThreadForAtLeast(1000) + Assert.assertTrue("Threads should be restarted when the source is re-added to the map.", + Thread.getAllStackTraces().keys.filter { + it.name.startsWith(CustomGeometrySource.THREAD_PREFIX) + }.count() == CustomGeometrySource.THREAD_POOL_LIMIT) + } + } +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java index fdc3826fb1..195aa63edd 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GridSourceActivity.java @@ -30,12 +30,16 @@ import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.lineColor; */ public class GridSourceActivity extends AppCompatActivity implements OnMapReadyCallback { - private static final String ID_GRID_SOURCE = "grid_source"; - private static final String ID_GRID_LAYER = "grid_layer"; + public static final String ID_GRID_SOURCE = "grid_source"; + public static final String ID_GRID_LAYER = "grid_layer"; private MapView mapView; private MapboxMap mapboxMap; + // public for testing purposes + public CustomGeometrySource source; + public LineLayer layer; + /** * Implementation of GeometryTileProvider that returns features representing a zoom-dependent * grid. @@ -101,11 +105,11 @@ public class GridSourceActivity extends AppCompatActivity implements OnMapReadyC mapboxMap = map; // add source - CustomGeometrySource source = new CustomGeometrySource(ID_GRID_SOURCE, new GridProvider()); + source = new CustomGeometrySource(ID_GRID_SOURCE, new GridProvider()); mapboxMap.addSource(source); // add layer - LineLayer layer = new LineLayer(ID_GRID_LAYER, ID_GRID_SOURCE); + layer = new LineLayer(ID_GRID_LAYER, ID_GRID_SOURCE); layer.setProperties( lineColor(Color.parseColor("#000000")) ); diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 44b04fc538..8da44c10cb 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -892,7 +892,9 @@ void NativeMapView::removeSource(JNIEnv& env, jni::Object obj, jlong sou assert(sourcePtr != 0); mbgl::android::Source *source = reinterpret_cast(sourcePtr); - source->removeFromMap(env, obj, *map); + if (source->removeFromMap(env, obj, *map)) { + source->releaseJavaPeer(); + } } void NativeMapView::addImage(JNIEnv& env, jni::String name, jni::Object bitmap, jni::jfloat scale, jni::jboolean sdf) { diff --git a/platform/android/src/style/sources/custom_geometry_source.cpp b/platform/android/src/style/sources/custom_geometry_source.cpp index b38405a3b1..9c51f70ab5 100644 --- a/platform/android/src/style/sources/custom_geometry_source.cpp +++ b/platform/android/src/style/sources/custom_geometry_source.cpp @@ -54,7 +54,9 @@ namespace android { : Source(env, coreSource, createJavaPeer(env), frontend) { } - CustomGeometrySource::~CustomGeometrySource() = default; + CustomGeometrySource::~CustomGeometrySource() { + releaseThreads(); + } void CustomGeometrySource::fetchTile (const mbgl::CanonicalTileID& tileID) { android::UniqueEnv _env = android::AttachEnv(); @@ -78,6 +80,28 @@ namespace android { peer.Call(*_env, cancelTile, (int)tileID.z, (int)tileID.x, (int)tileID.y); }; + void CustomGeometrySource::startThreads() { + android::UniqueEnv _env = android::AttachEnv(); + + static auto startThreads = javaClass.GetMethod(*_env, "startThreads"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, *javaPeer, javaClass); + peer.Call(*_env, startThreads); + } + + void CustomGeometrySource::releaseThreads() { + android::UniqueEnv _env = android::AttachEnv(); + + static auto releaseThreads = javaClass.GetMethod(*_env, "releaseThreads"); + + assert(javaPeer); + + auto peer = jni::Cast(*_env, *javaPeer, javaClass); + peer.Call(*_env, releaseThreads); + }; + void CustomGeometrySource::setTileData(jni::JNIEnv& env, jni::jint z, jni::jint x, @@ -120,6 +144,19 @@ namespace android { return jni::Object(CustomGeometrySource::javaClass.New(env, constructor, reinterpret_cast(this)).Get()); } + void CustomGeometrySource::addToMap(JNIEnv& env, jni::Object obj, mbgl::Map& map, AndroidRendererFrontend& frontend) { + Source::addToMap(env, obj, map, frontend); + startThreads(); + } + + bool CustomGeometrySource::removeFromMap(JNIEnv& env, jni::Object source, mbgl::Map& map) { + bool successfullyRemoved = Source::removeFromMap(env, source, map); + if (successfullyRemoved) { + releaseThreads(); + } + return successfullyRemoved; + } + void CustomGeometrySource::registerNative(jni::JNIEnv& env) { // Lookup the class CustomGeometrySource::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); diff --git a/platform/android/src/style/sources/custom_geometry_source.hpp b/platform/android/src/style/sources/custom_geometry_source.hpp index 1dc1c07b4f..c38926a5b9 100644 --- a/platform/android/src/style/sources/custom_geometry_source.hpp +++ b/platform/android/src/style/sources/custom_geometry_source.hpp @@ -28,8 +28,13 @@ public: ~CustomGeometrySource(); + bool removeFromMap(JNIEnv&, jni::Object, mbgl::Map&) override; + void addToMap(JNIEnv&, jni::Object, mbgl::Map&, AndroidRendererFrontend&) override; + void fetchTile(const mbgl::CanonicalTileID& tileID); void cancelTile(const mbgl::CanonicalTileID& tileID); + void startThreads(); + void releaseThreads(); void setTileData(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y, jni::Object jf); void invalidateTile(jni::JNIEnv& env, jni::jint z, jni::jint x, jni::jint y); diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp index 5f68e40467..8f14ebc43e 100644 --- a/platform/android/src/style/sources/source.cpp +++ b/platform/android/src/style/sources/source.cpp @@ -109,7 +109,7 @@ namespace android { rendererFrontend = &frontend; } - void Source::removeFromMap(JNIEnv&, jni::Object, mbgl::Map& map) { + bool Source::removeFromMap(JNIEnv&, jni::Object, mbgl::Map& map) { // Cannot remove if not attached yet if (ownedSource) { throw std::runtime_error("Cannot remove detached source"); @@ -119,6 +119,11 @@ namespace android { ownedSource = map.getStyle().removeSource(source.getID()); // The source may not be removed if any layers still reference it + return ownedSource != nullptr; + } + + void Source::releaseJavaPeer() { + // We can't release the peer if the source was not removed from the map if (!ownedSource) { return; } diff --git a/platform/android/src/style/sources/source.hpp b/platform/android/src/style/sources/source.hpp index 718f60b381..6b906eb9c0 100644 --- a/platform/android/src/style/sources/source.hpp +++ b/platform/android/src/style/sources/source.hpp @@ -35,9 +35,11 @@ public: virtual ~Source(); - void addToMap(JNIEnv&, jni::Object, mbgl::Map&, AndroidRendererFrontend&); + virtual void addToMap(JNIEnv&, jni::Object, mbgl::Map&, AndroidRendererFrontend&); - void removeFromMap(JNIEnv&, jni::Object, mbgl::Map&); + virtual bool removeFromMap(JNIEnv&, jni::Object, mbgl::Map&); + + void releaseJavaPeer(); jni::String getId(jni::JNIEnv&); -- cgit v1.2.1 From fdc287ec3608850654196e3b3a682ca3c5039676 Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Fri, 10 Aug 2018 10:00:24 -0700 Subject: typo fix (#12593) --- .../src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 0719412b4c..276e25bd53 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -433,7 +433,7 @@ public final class MapboxMap { } /** - * Removes the source, preserving the reverence for re-use + * Removes the source, preserving the reference for re-use * * @param source the source to remove * @return the source -- cgit v1.2.1 From 044213dca8e5ee9148b77e37bf4f15ed1589ac2f Mon Sep 17 00:00:00 2001 From: tobrun Date: Mon, 13 Aug 2018 12:42:03 +0200 Subject: [android] - use uncoverted bearing value for latlngbounds calculation --- .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 2 +- .../testapp/geometry/LatLngBoundsTest.java | 32 ++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 276e25bd53..97e2e50525 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -1601,7 +1601,7 @@ public final class MapboxMap { public CameraPosition getCameraForLatLngBounds(@NonNull LatLngBounds latLngBounds, @NonNull @Size(value = 4) int[] padding) { // we use current camera tilt/bearing value to provide expected transformations as #11993 - return getCameraForLatLngBounds(latLngBounds, padding, transform.getBearing(), transform.getTilt()); + return getCameraForLatLngBounds(latLngBounds, padding, transform.getRawBearing(), transform.getTilt()); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/LatLngBoundsTest.java index 738f1e203f..7aaca370b2 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/LatLngBoundsTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/geometry/LatLngBoundsTest.java @@ -7,13 +7,18 @@ import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction; import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest; import com.mapbox.mapboxsdk.testapp.activity.feature.QueryRenderedFeaturesBoxHighlightActivity; +import com.mapbox.mapboxsdk.testapp.utils.TestConstants; import org.junit.Test; +import static junit.framework.Assert.assertEquals; + /** * Instrumentation test to validate integration of LatLngBounds */ public class LatLngBoundsTest extends BaseActivityTest { + private static final double MAP_BEARING = 50; + @Override protected Class getActivityClass() { return QueryRenderedFeaturesBoxHighlightActivity.class; @@ -31,4 +36,31 @@ public class LatLngBoundsTest extends BaseActivityTest { mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0)); }); } + + @Test + public void testLatLngBoundsBearing() { + // regression test for #12549 + validateTestSetup(); + MapboxMapAction.invoke(mapboxMap, (uiController, mapboxMap) -> { + LatLngBounds bounds = new LatLngBounds.Builder() + .include(new LatLng(48.8589506, 2.2773457)) + .include(new LatLng(47.2383171, -1.6309316)) + .build(); + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0)); + mapboxMap.moveCamera(CameraUpdateFactory.bearingTo(MAP_BEARING)); + assertEquals( + "Initial bearing should match for latlngbounds", + mapboxMap.getCameraPosition().bearing, + MAP_BEARING, + TestConstants.BEARING_DELTA + ); + + mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0)); + assertEquals("Bearing should match after resetting latlngbounds", + mapboxMap.getCameraPosition().bearing, + MAP_BEARING, + TestConstants.BEARING_DELTA); + }); + } + } \ No newline at end of file -- cgit v1.2.1 From 8554f175ab9c909552cdc90e761dd0caf0520072 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Mon, 23 Jul 2018 13:50:04 -0700 Subject: [docs] Changelog entries for symbol-placement: line-center --- platform/ios/CHANGELOG.md | 1 + platform/macos/CHANGELOG.md | 1 + platform/node/CHANGELOG.md | 1 + 3 files changed, 3 insertions(+) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 303d8160bf..59d5cac39b 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -12,6 +12,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ### Styles and rendering * Added an `MGLMapView.preferredFramesPerSecond` property that controls the rate at which the map view is rendered. The default rate now adapts to device capabilities to provide a smoother experience. ([#12501](https://github.com/mapbox/mapbox-gl-native/issues/12501)) +* Added a new option to `MGLSymbolPlacement`, `MGLSymbolPlacementLineCenter`, that places the label relative to the center of the geometry. ([#12337](https://github.com/mapbox/mapbox-gl-native/pull/12337)) ### Other changes diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 001b3792d5..bfc94b28ad 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -6,6 +6,7 @@ * Token string syntax (`"{token}"`) in `MGLSymbolStyleLayer` `text` and `iconImageName` properties is now correctly converted to the appropriate `NSExpression` equivalent. ([#11659](https://github.com/mapbox/mapbox-gl-native/issues/11659)) * Fixed a crash when switching between two styles having layers with the same identifier but different layer types. ([#12432](https://github.com/mapbox/mapbox-gl-native/issues/12432)) +* * Added a new option to `MGLSymbolPlacement`, `MGLSymbolPlacementLineCenter`, that places the label relative to the center of the geometry. ([#12337](https://github.com/mapbox/mapbox-gl-native/pull/12337)) # 0.9.0 - July 18, 2018 diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md index d2b6c76ab1..8ce4756814 100644 --- a/platform/node/CHANGELOG.md +++ b/platform/node/CHANGELOG.md @@ -1,6 +1,7 @@ # master - The `Map` constructor now accepts a `mode` option which can be either `"static"` (default) or `"tile"`. It must be set to `"tile"` when rendering individual tiles in order for the symbols to match across tiles. - Remove unnecessary memory use when collision debug mode is not enabled ([#12294](https://github.com/mapbox/mapbox-gl-native/issues/12294)) +- Added support for rendering `symbol-placement: line-center` ([#12337](https://github.com/mapbox/mapbox-gl-native/pull/12337)) # 3.5.8 - October 19, 2017 - Fixes an issue that causes memory leaks when not deleting the frontend object -- cgit v1.2.1 From 3c8acb228e0ff1124ce8ca6c710dc46cf99d87fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Mon, 13 Aug 2018 18:09:47 +0200 Subject: [android] temporarily disable CustomGeometrySource tests --- .../com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt index 1496cb704d..b60a4cff67 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CustomGeometrySourceTest.kt @@ -13,6 +13,7 @@ import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity.ID_GRID_LAYER import com.mapbox.mapboxsdk.testapp.activity.style.GridSourceActivity.ID_GRID_SOURCE import org.junit.Assert +import org.junit.Ignore import org.junit.Test class CustomGeometrySourceTest : BaseActivityTest() { @@ -34,6 +35,7 @@ class CustomGeometrySourceTest : BaseActivityTest() { } @Test + @Ignore fun threadsShutdownWhenSourceRemovedTest() { validateTestSetup() invoke(mapboxMap) { uiController, mapboxMap -> @@ -49,6 +51,7 @@ class CustomGeometrySourceTest : BaseActivityTest() { } @Test + @Ignore fun threadsRestartedWhenSourceReAddedTest() { validateTestSetup() invoke(mapboxMap) { uiController, mapboxMap -> -- cgit v1.2.1 From b2f60a4bf2fb95c107bb94543ba6345779970e98 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 30 Jul 2018 08:38:14 -0700 Subject: [core] Eliminate setProperty & co. --- cmake/core-files.cmake | 2 - include/mbgl/style/conversion/layer.hpp | 2 - include/mbgl/style/layer.hpp | 6 +- include/mbgl/style/layers/background_layer.hpp | 4 + include/mbgl/style/layers/circle_layer.hpp | 4 + include/mbgl/style/layers/custom_layer.hpp | 4 + include/mbgl/style/layers/fill_extrusion_layer.hpp | 4 + include/mbgl/style/layers/fill_layer.hpp | 4 + include/mbgl/style/layers/heatmap_layer.hpp | 4 + include/mbgl/style/layers/hillshade_layer.hpp | 4 + include/mbgl/style/layers/layer.hpp.ejs | 4 + include/mbgl/style/layers/line_layer.hpp | 4 + include/mbgl/style/layers/raster_layer.hpp | 4 + include/mbgl/style/layers/symbol_layer.hpp | 4 + platform/android/src/style/layers/layer.cpp | 4 +- platform/node/src/node_map.cpp | 4 +- platform/qt/src/qmapboxgl.cpp | 14 +- platform/qt/src/qmapboxgl_p.hpp | 2 +- scripts/generate-style-code.js | 3 - src/mbgl/style/conversion/json.hpp | 2 + src/mbgl/style/conversion/layer.cpp | 23 +- .../style/conversion/make_property_setters.hpp | 239 ------- .../style/conversion/make_property_setters.hpp.ejs | 46 -- src/mbgl/style/conversion/property_setter.hpp | 71 -- src/mbgl/style/layers/background_layer.cpp | 97 +++ src/mbgl/style/layers/circle_layer.cpp | 265 ++++++++ src/mbgl/style/layers/custom_layer.cpp | 10 + src/mbgl/style/layers/fill_extrusion_layer.cpp | 181 ++++++ src/mbgl/style/layers/fill_layer.cpp | 181 ++++++ src/mbgl/style/layers/heatmap_layer.cpp | 137 +++- src/mbgl/style/layers/hillshade_layer.cpp | 160 +++++ src/mbgl/style/layers/layer.cpp.ejs | 68 +- src/mbgl/style/layers/line_layer.cpp | 288 ++++++++ src/mbgl/style/layers/raster_layer.cpp | 202 ++++++ src/mbgl/style/layers/symbol_layer.cpp | 724 +++++++++++++++++++++ 35 files changed, 2374 insertions(+), 401 deletions(-) delete mode 100644 src/mbgl/style/conversion/make_property_setters.hpp delete mode 100644 src/mbgl/style/conversion/make_property_setters.hpp.ejs delete mode 100644 src/mbgl/style/conversion/property_setter.hpp diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index 2cfcb16771..d35e2c66ca 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -436,9 +436,7 @@ set(MBGL_CORE_FILES src/mbgl/style/conversion/json.hpp src/mbgl/style/conversion/layer.cpp src/mbgl/style/conversion/light.cpp - src/mbgl/style/conversion/make_property_setters.hpp src/mbgl/style/conversion/position.cpp - src/mbgl/style/conversion/property_setter.hpp src/mbgl/style/conversion/source.cpp src/mbgl/style/conversion/stringify.hpp src/mbgl/style/conversion/tileset.cpp diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp index 1c0e2e2f07..2df6c9e381 100644 --- a/include/mbgl/style/conversion/layer.hpp +++ b/include/mbgl/style/conversion/layer.hpp @@ -15,8 +15,6 @@ public: optional> operator()(const Convertible& value, Error& error) const; }; -optional setLayoutProperty(Layer& layer, const std::string& name, const Convertible& value); -optional setPaintProperty(Layer& layer, const std::string& name, const Convertible& value); optional setPaintProperties(Layer& layer, const Convertible& value); } // namespace conversion diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index b5a4b63d2e..fee9f9121e 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -98,7 +99,6 @@ public: return std::forward(visitor)(*as()); } - // Not reachable, but placate GCC. assert(false); throw new std::runtime_error("unknown layer type"); @@ -117,6 +117,10 @@ public: virtual void setMinZoom(float) = 0; virtual void setMaxZoom(float) = 0; + // Dynamic properties + virtual optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) = 0; + virtual optional setPaintProperty(const std::string& name, const conversion::Convertible& value) = 0; + // Private implementation class Impl; Immutable baseImpl; diff --git a/include/mbgl/style/layers/background_layer.hpp b/include/mbgl/style/layers/background_layer.hpp index eab2681fec..76230df12c 100644 --- a/include/mbgl/style/layers/background_layer.hpp +++ b/include/mbgl/style/layers/background_layer.hpp @@ -25,6 +25,10 @@ public: void setMinZoom(float) final; void setMaxZoom(float) final; + // Dynamic properties + optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; + optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + // Paint properties static PropertyValue getDefaultBackgroundColor(); diff --git a/include/mbgl/style/layers/circle_layer.hpp b/include/mbgl/style/layers/circle_layer.hpp index 89ef926221..cde691c893 100644 --- a/include/mbgl/style/layers/circle_layer.hpp +++ b/include/mbgl/style/layers/circle_layer.hpp @@ -33,6 +33,10 @@ public: void setMinZoom(float) final; void setMaxZoom(float) final; + // Dynamic properties + optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; + optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + // Paint properties static PropertyValue getDefaultCircleRadius(); diff --git a/include/mbgl/style/layers/custom_layer.hpp b/include/mbgl/style/layers/custom_layer.hpp index fbe3a4a6c2..4b4c770489 100644 --- a/include/mbgl/style/layers/custom_layer.hpp +++ b/include/mbgl/style/layers/custom_layer.hpp @@ -75,6 +75,10 @@ public: void setMinZoom(float) final; void setMaxZoom(float) final; + // Dynamic properties + optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; + optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + // Private implementation class Impl; diff --git a/include/mbgl/style/layers/fill_extrusion_layer.hpp b/include/mbgl/style/layers/fill_extrusion_layer.hpp index 742bac8c7e..e72fcade61 100644 --- a/include/mbgl/style/layers/fill_extrusion_layer.hpp +++ b/include/mbgl/style/layers/fill_extrusion_layer.hpp @@ -33,6 +33,10 @@ public: void setMinZoom(float) final; void setMaxZoom(float) final; + // Dynamic properties + optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; + optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + // Paint properties static PropertyValue getDefaultFillExtrusionOpacity(); diff --git a/include/mbgl/style/layers/fill_layer.hpp b/include/mbgl/style/layers/fill_layer.hpp index d0b2a25bfe..430d7a011f 100644 --- a/include/mbgl/style/layers/fill_layer.hpp +++ b/include/mbgl/style/layers/fill_layer.hpp @@ -33,6 +33,10 @@ public: void setMinZoom(float) final; void setMaxZoom(float) final; + // Dynamic properties + optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; + optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + // Paint properties static PropertyValue getDefaultFillAntialias(); diff --git a/include/mbgl/style/layers/heatmap_layer.hpp b/include/mbgl/style/layers/heatmap_layer.hpp index 53fd24aa6c..fd0051f44c 100644 --- a/include/mbgl/style/layers/heatmap_layer.hpp +++ b/include/mbgl/style/layers/heatmap_layer.hpp @@ -34,6 +34,10 @@ public: void setMinZoom(float) final; void setMaxZoom(float) final; + // Dynamic properties + optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; + optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + // Paint properties static PropertyValue getDefaultHeatmapRadius(); diff --git a/include/mbgl/style/layers/hillshade_layer.hpp b/include/mbgl/style/layers/hillshade_layer.hpp index 214576b120..89d0ae686f 100644 --- a/include/mbgl/style/layers/hillshade_layer.hpp +++ b/include/mbgl/style/layers/hillshade_layer.hpp @@ -28,6 +28,10 @@ public: void setMinZoom(float) final; void setMaxZoom(float) final; + // Dynamic properties + optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; + optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + // Paint properties static PropertyValue getDefaultHillshadeIlluminationDirection(); diff --git a/include/mbgl/style/layers/layer.hpp.ejs b/include/mbgl/style/layers/layer.hpp.ejs index 9d52973af4..db7052387c 100644 --- a/include/mbgl/style/layers/layer.hpp.ejs +++ b/include/mbgl/style/layers/layer.hpp.ejs @@ -53,6 +53,10 @@ public: void setMinZoom(float) final; void setMaxZoom(float) final; + // Dynamic properties + optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; + optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + <% if (layoutProperties.length) { -%> // Layout properties diff --git a/include/mbgl/style/layers/line_layer.hpp b/include/mbgl/style/layers/line_layer.hpp index 26e3b81fc9..fe4cd7c0d1 100644 --- a/include/mbgl/style/layers/line_layer.hpp +++ b/include/mbgl/style/layers/line_layer.hpp @@ -35,6 +35,10 @@ public: void setMinZoom(float) final; void setMaxZoom(float) final; + // Dynamic properties + optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; + optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + // Layout properties static PropertyValue getDefaultLineCap(); diff --git a/include/mbgl/style/layers/raster_layer.hpp b/include/mbgl/style/layers/raster_layer.hpp index c133c23484..fcc35412a0 100644 --- a/include/mbgl/style/layers/raster_layer.hpp +++ b/include/mbgl/style/layers/raster_layer.hpp @@ -28,6 +28,10 @@ public: void setMinZoom(float) final; void setMaxZoom(float) final; + // Dynamic properties + optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; + optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + // Paint properties static PropertyValue getDefaultRasterOpacity(); diff --git a/include/mbgl/style/layers/symbol_layer.hpp b/include/mbgl/style/layers/symbol_layer.hpp index 8c0b45d796..fa0b0c4e4e 100644 --- a/include/mbgl/style/layers/symbol_layer.hpp +++ b/include/mbgl/style/layers/symbol_layer.hpp @@ -35,6 +35,10 @@ public: void setMinZoom(float) final; void setMaxZoom(float) final; + // Dynamic properties + optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) final; + optional setPaintProperty(const std::string& name, const conversion::Convertible& value) final; + // Layout properties static PropertyValue getDefaultSymbolPlacement(); diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp index c7a6bcd3a3..c3ae9e40cd 100644 --- a/platform/android/src/style/layers/layer.cpp +++ b/platform/android/src/style/layers/layer.cpp @@ -91,7 +91,7 @@ namespace android { void Layer::setLayoutProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) { // Convert and set property - optional error = mbgl::style::conversion::setLayoutProperty(layer, jni::Make(env, jname), Value(env, jvalue)); + optional error = layer.setLayoutProperty(jni::Make(env, jname), Value(env, jvalue)); if (error) { mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make(env, jname) + " " + error->message); return; @@ -100,7 +100,7 @@ namespace android { void Layer::setPaintProperty(jni::JNIEnv& env, jni::String jname, jni::Object<> jvalue) { // Convert and set property - optional error = mbgl::style::conversion::setPaintProperty(layer, jni::Make(env, jname), Value(env, jvalue)); + optional error = layer.setPaintProperty(jni::Make(env, jname), Value(env, jvalue)); if (error) { mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make(env, jname) + " " + error->message); return; diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp index 4bcd1d97bc..0cc93d7e95 100644 --- a/platform/node/src/node_map.cpp +++ b/platform/node/src/node_map.cpp @@ -822,7 +822,7 @@ void NodeMap::SetLayoutProperty(const Nan::FunctionCallbackInfo& info return Nan::ThrowTypeError("Second argument must be a string"); } - mbgl::optional error = setLayoutProperty(*layer, *Nan::Utf8String(info[1]), Convertible(info[2])); + mbgl::optional error = layer->setLayoutProperty(*Nan::Utf8String(info[1]), Convertible(info[2])); if (error) { return Nan::ThrowTypeError(error->message.c_str()); } @@ -854,7 +854,7 @@ void NodeMap::SetPaintProperty(const Nan::FunctionCallbackInfo& info) return Nan::ThrowTypeError("Second argument must be a string"); } - mbgl::optional error = setPaintProperty(*layer, *Nan::Utf8String(info[1]), Convertible(info[2])); + mbgl::optional error = layer->setPaintProperty(*Nan::Utf8String(info[1]), Convertible(info[2])); if (error) { return Nan::ThrowTypeError(error->message.c_str()); } diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index 459eacba4b..480174810c 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -1017,7 +1017,7 @@ void QMapboxGL::removeAnnotation(QMapbox::AnnotationID id) */ bool QMapboxGL::setLayoutProperty(const QString& layer, const QString& propertyName, const QVariant& value) { - return d_ptr->setProperty(&mbgl::style::conversion::setLayoutProperty, layer, propertyName, value); + return d_ptr->setProperty(&mbgl::style::Layer::setLayoutProperty, layer, propertyName, value); } /*! @@ -1077,7 +1077,7 @@ bool QMapboxGL::setLayoutProperty(const QString& layer, const QString& propertyN bool QMapboxGL::setPaintProperty(const QString& layer, const QString& propertyName, const QVariant& value) { - return d_ptr->setProperty(&mbgl::style::conversion::setPaintProperty, layer, propertyName, value); + return d_ptr->setProperty(&mbgl::style::Layer::setPaintProperty, layer, propertyName, value); } /*! @@ -1379,7 +1379,7 @@ void QMapboxGL::addCustomLayer(const QString &id, } void initialize() { - ptr->initialize(); + ptr->initialize(); } void render(const mbgl::style::CustomLayerRenderParameters& params) { @@ -1922,16 +1922,16 @@ bool QMapboxGLPrivate::setProperty(const PropertySetter& setter, const QString& if (!document.HasParseError()) { // Treat value as a valid JSON. const mbgl::JSValue* jsonValue = &document; - result = setter(*layerObject, propertyString, jsonValue); + result = (layerObject->*setter)(propertyString, jsonValue); } else { - result = setter(*layerObject, propertyString, value); + result = (layerObject->*setter)(propertyString, value); } } else { - result = setter(*layerObject, propertyString, value); + result = (layerObject->*setter)(propertyString, value); } if (result) { - qWarning() << "Error setting paint property" << name << "on layer" << layer << ":" << QString::fromStdString(result->message); + qWarning() << "Error setting property" << name << "on layer" << layer << ":" << QString::fromStdString(result->message); return false; } diff --git a/platform/qt/src/qmapboxgl_p.hpp b/platform/qt/src/qmapboxgl_p.hpp index 80789ac8f1..b94f4de194 100644 --- a/platform/qt/src/qmapboxgl_p.hpp +++ b/platform/qt/src/qmapboxgl_p.hpp @@ -37,7 +37,7 @@ public: void render(); void setFramebufferObject(quint32 fbo, const QSize& size); - using PropertySetter = std::function(mbgl::style::Layer&, const std::string&, const mbgl::style::conversion::Convertible&)>; + using PropertySetter = mbgl::optional (mbgl::style::Layer::*)(const std::string&, const mbgl::style::conversion::Convertible&); bool setProperty(const PropertySetter& setter, const QString& layer, const QString& name, const QVariant& value); mbgl::EdgeInsets margins; diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index db37a9b96f..9a7b2842f7 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -192,9 +192,6 @@ for (const layer of layers) { writeIfModified(`src/mbgl/style/layers/${layerFileName}_layer_properties.cpp`, propertiesCpp(layer)); } -const propertySettersHpp = ejs.compile(fs.readFileSync('src/mbgl/style/conversion/make_property_setters.hpp.ejs', 'utf8'), {strict: true}); -writeIfModified('src/mbgl/style/conversion/make_property_setters.hpp', propertySettersHpp({layers: layers})); - // Light const lightProperties = Object.keys(spec[`light`]).reduce((memo, name) => { var property = spec[`light`][name]; diff --git a/src/mbgl/style/conversion/json.hpp b/src/mbgl/style/conversion/json.hpp index 7dd2378f6b..a823f6d383 100644 --- a/src/mbgl/style/conversion/json.hpp +++ b/src/mbgl/style/conversion/json.hpp @@ -1,3 +1,5 @@ +#pragma once + #include #include diff --git a/src/mbgl/style/conversion/layer.cpp b/src/mbgl/style/conversion/layer.cpp index e18ad923f2..d36ca494da 100644 --- a/src/mbgl/style/conversion/layer.cpp +++ b/src/mbgl/style/conversion/layer.cpp @@ -1,7 +1,6 @@ #include #include #include -#include #include #include #include @@ -16,24 +15,6 @@ namespace mbgl { namespace style { namespace conversion { -optional setLayoutProperty(Layer& layer, const std::string& name, const Convertible& value) { - static const auto setters = makeLayoutPropertySetters(); - auto it = setters.find(name); - if (it == setters.end()) { - return Error { "property not found" }; - } - return it->second(layer, value); -} - -optional setPaintProperty(Layer& layer, const std::string& name, const Convertible& value) { - static const auto setters = makePaintPropertySetters(); - auto it = setters.find(name); - if (it == setters.end()) { - return Error { "property not found" }; - } - return it->second(layer, value); -} - optional setPaintProperties(Layer& layer, const Convertible& value) { auto paintValue = objectMember(value, "paint"); if (!paintValue) { @@ -43,7 +24,7 @@ optional setPaintProperties(Layer& layer, const Convertible& value) { return { { "paint must be an object" } }; } return eachMember(*paintValue, [&] (const std::string& k, const Convertible& v) { - return setPaintProperty(layer, k, v); + return layer.setPaintProperty(k, v); }); } @@ -210,7 +191,7 @@ optional> Converter>::operator()(c return nullopt; } optional error_ = eachMember(*layoutValue, [&] (const std::string& k, const Convertible& v) { - return setLayoutProperty(*layer, k, v); + return layer->setLayoutProperty(k, v); }); if (error_) { error = *error_; diff --git a/src/mbgl/style/conversion/make_property_setters.hpp b/src/mbgl/style/conversion/make_property_setters.hpp deleted file mode 100644 index ada0d53002..0000000000 --- a/src/mbgl/style/conversion/make_property_setters.hpp +++ /dev/null @@ -1,239 +0,0 @@ -#pragma once - -// This file is generated. Edit make_property_setters.hpp.ejs, then run `make style-code`. - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace mbgl { -namespace style { -namespace conversion { - -inline auto makeLayoutPropertySetters() { - std::unordered_map result; - - result["visibility"] = &setVisibility; - - - result["line-cap"] = &setProperty, &LineLayer::setLineCap, false, false>; - result["line-join"] = &setProperty, &LineLayer::setLineJoin, true, false>; - result["line-miter-limit"] = &setProperty, &LineLayer::setLineMiterLimit, false, false>; - result["line-round-limit"] = &setProperty, &LineLayer::setLineRoundLimit, false, false>; - - result["symbol-placement"] = &setProperty, &SymbolLayer::setSymbolPlacement, false, false>; - result["symbol-spacing"] = &setProperty, &SymbolLayer::setSymbolSpacing, false, false>; - result["symbol-avoid-edges"] = &setProperty, &SymbolLayer::setSymbolAvoidEdges, false, false>; - result["icon-allow-overlap"] = &setProperty, &SymbolLayer::setIconAllowOverlap, false, false>; - result["icon-ignore-placement"] = &setProperty, &SymbolLayer::setIconIgnorePlacement, false, false>; - result["icon-optional"] = &setProperty, &SymbolLayer::setIconOptional, false, false>; - result["icon-rotation-alignment"] = &setProperty, &SymbolLayer::setIconRotationAlignment, false, false>; - result["icon-size"] = &setProperty, &SymbolLayer::setIconSize, true, false>; - result["icon-text-fit"] = &setProperty, &SymbolLayer::setIconTextFit, false, false>; - result["icon-text-fit-padding"] = &setProperty>, &SymbolLayer::setIconTextFitPadding, false, false>; - result["icon-image"] = &setProperty, &SymbolLayer::setIconImage, true, true>; - result["icon-rotate"] = &setProperty, &SymbolLayer::setIconRotate, true, false>; - result["icon-padding"] = &setProperty, &SymbolLayer::setIconPadding, false, false>; - result["icon-keep-upright"] = &setProperty, &SymbolLayer::setIconKeepUpright, false, false>; - result["icon-offset"] = &setProperty>, &SymbolLayer::setIconOffset, true, false>; - result["icon-anchor"] = &setProperty, &SymbolLayer::setIconAnchor, true, false>; - result["icon-pitch-alignment"] = &setProperty, &SymbolLayer::setIconPitchAlignment, false, false>; - result["text-pitch-alignment"] = &setProperty, &SymbolLayer::setTextPitchAlignment, false, false>; - result["text-rotation-alignment"] = &setProperty, &SymbolLayer::setTextRotationAlignment, false, false>; - result["text-field"] = &setProperty, &SymbolLayer::setTextField, true, true>; - result["text-font"] = &setProperty>, &SymbolLayer::setTextFont, true, false>; - result["text-size"] = &setProperty, &SymbolLayer::setTextSize, true, false>; - result["text-max-width"] = &setProperty, &SymbolLayer::setTextMaxWidth, true, false>; - result["text-line-height"] = &setProperty, &SymbolLayer::setTextLineHeight, false, false>; - result["text-letter-spacing"] = &setProperty, &SymbolLayer::setTextLetterSpacing, true, false>; - result["text-justify"] = &setProperty, &SymbolLayer::setTextJustify, true, false>; - result["text-anchor"] = &setProperty, &SymbolLayer::setTextAnchor, true, false>; - result["text-max-angle"] = &setProperty, &SymbolLayer::setTextMaxAngle, false, false>; - result["text-rotate"] = &setProperty, &SymbolLayer::setTextRotate, true, false>; - result["text-padding"] = &setProperty, &SymbolLayer::setTextPadding, false, false>; - result["text-keep-upright"] = &setProperty, &SymbolLayer::setTextKeepUpright, false, false>; - result["text-transform"] = &setProperty, &SymbolLayer::setTextTransform, true, false>; - result["text-offset"] = &setProperty>, &SymbolLayer::setTextOffset, true, false>; - result["text-allow-overlap"] = &setProperty, &SymbolLayer::setTextAllowOverlap, false, false>; - result["text-ignore-placement"] = &setProperty, &SymbolLayer::setTextIgnorePlacement, false, false>; - result["text-optional"] = &setProperty, &SymbolLayer::setTextOptional, false, false>; - - - - - - - - return result; -} - -inline auto makePaintPropertySetters() { - std::unordered_map result; - - result["fill-antialias"] = &setProperty, &FillLayer::setFillAntialias, false, false>; - result["fill-antialias-transition"] = &setTransition; - result["fill-opacity"] = &setProperty, &FillLayer::setFillOpacity, true, false>; - result["fill-opacity-transition"] = &setTransition; - result["fill-color"] = &setProperty, &FillLayer::setFillColor, true, false>; - result["fill-color-transition"] = &setTransition; - result["fill-outline-color"] = &setProperty, &FillLayer::setFillOutlineColor, true, false>; - result["fill-outline-color-transition"] = &setTransition; - result["fill-translate"] = &setProperty>, &FillLayer::setFillTranslate, false, false>; - result["fill-translate-transition"] = &setTransition; - result["fill-translate-anchor"] = &setProperty, &FillLayer::setFillTranslateAnchor, false, false>; - result["fill-translate-anchor-transition"] = &setTransition; - result["fill-pattern"] = &setProperty, &FillLayer::setFillPattern, false, false>; - result["fill-pattern-transition"] = &setTransition; - - result["line-opacity"] = &setProperty, &LineLayer::setLineOpacity, true, false>; - result["line-opacity-transition"] = &setTransition; - result["line-color"] = &setProperty, &LineLayer::setLineColor, true, false>; - result["line-color-transition"] = &setTransition; - result["line-translate"] = &setProperty>, &LineLayer::setLineTranslate, false, false>; - result["line-translate-transition"] = &setTransition; - result["line-translate-anchor"] = &setProperty, &LineLayer::setLineTranslateAnchor, false, false>; - result["line-translate-anchor-transition"] = &setTransition; - result["line-width"] = &setProperty, &LineLayer::setLineWidth, true, false>; - result["line-width-transition"] = &setTransition; - result["line-gap-width"] = &setProperty, &LineLayer::setLineGapWidth, true, false>; - result["line-gap-width-transition"] = &setTransition; - result["line-offset"] = &setProperty, &LineLayer::setLineOffset, true, false>; - result["line-offset-transition"] = &setTransition; - result["line-blur"] = &setProperty, &LineLayer::setLineBlur, true, false>; - result["line-blur-transition"] = &setTransition; - result["line-dasharray"] = &setProperty>, &LineLayer::setLineDasharray, false, false>; - result["line-dasharray-transition"] = &setTransition; - result["line-pattern"] = &setProperty, &LineLayer::setLinePattern, false, false>; - result["line-pattern-transition"] = &setTransition; - - result["icon-opacity"] = &setProperty, &SymbolLayer::setIconOpacity, true, false>; - result["icon-opacity-transition"] = &setTransition; - result["icon-color"] = &setProperty, &SymbolLayer::setIconColor, true, false>; - result["icon-color-transition"] = &setTransition; - result["icon-halo-color"] = &setProperty, &SymbolLayer::setIconHaloColor, true, false>; - result["icon-halo-color-transition"] = &setTransition; - result["icon-halo-width"] = &setProperty, &SymbolLayer::setIconHaloWidth, true, false>; - result["icon-halo-width-transition"] = &setTransition; - result["icon-halo-blur"] = &setProperty, &SymbolLayer::setIconHaloBlur, true, false>; - result["icon-halo-blur-transition"] = &setTransition; - result["icon-translate"] = &setProperty>, &SymbolLayer::setIconTranslate, false, false>; - result["icon-translate-transition"] = &setTransition; - result["icon-translate-anchor"] = &setProperty, &SymbolLayer::setIconTranslateAnchor, false, false>; - result["icon-translate-anchor-transition"] = &setTransition; - result["text-opacity"] = &setProperty, &SymbolLayer::setTextOpacity, true, false>; - result["text-opacity-transition"] = &setTransition; - result["text-color"] = &setProperty, &SymbolLayer::setTextColor, true, false>; - result["text-color-transition"] = &setTransition; - result["text-halo-color"] = &setProperty, &SymbolLayer::setTextHaloColor, true, false>; - result["text-halo-color-transition"] = &setTransition; - result["text-halo-width"] = &setProperty, &SymbolLayer::setTextHaloWidth, true, false>; - result["text-halo-width-transition"] = &setTransition; - result["text-halo-blur"] = &setProperty, &SymbolLayer::setTextHaloBlur, true, false>; - result["text-halo-blur-transition"] = &setTransition; - result["text-translate"] = &setProperty>, &SymbolLayer::setTextTranslate, false, false>; - result["text-translate-transition"] = &setTransition; - result["text-translate-anchor"] = &setProperty, &SymbolLayer::setTextTranslateAnchor, false, false>; - result["text-translate-anchor-transition"] = &setTransition; - - result["circle-radius"] = &setProperty, &CircleLayer::setCircleRadius, true, false>; - result["circle-radius-transition"] = &setTransition; - result["circle-color"] = &setProperty, &CircleLayer::setCircleColor, true, false>; - result["circle-color-transition"] = &setTransition; - result["circle-blur"] = &setProperty, &CircleLayer::setCircleBlur, true, false>; - result["circle-blur-transition"] = &setTransition; - result["circle-opacity"] = &setProperty, &CircleLayer::setCircleOpacity, true, false>; - result["circle-opacity-transition"] = &setTransition; - result["circle-translate"] = &setProperty>, &CircleLayer::setCircleTranslate, false, false>; - result["circle-translate-transition"] = &setTransition; - result["circle-translate-anchor"] = &setProperty, &CircleLayer::setCircleTranslateAnchor, false, false>; - result["circle-translate-anchor-transition"] = &setTransition; - result["circle-pitch-scale"] = &setProperty, &CircleLayer::setCirclePitchScale, false, false>; - result["circle-pitch-scale-transition"] = &setTransition; - result["circle-pitch-alignment"] = &setProperty, &CircleLayer::setCirclePitchAlignment, false, false>; - result["circle-pitch-alignment-transition"] = &setTransition; - result["circle-stroke-width"] = &setProperty, &CircleLayer::setCircleStrokeWidth, true, false>; - result["circle-stroke-width-transition"] = &setTransition; - result["circle-stroke-color"] = &setProperty, &CircleLayer::setCircleStrokeColor, true, false>; - result["circle-stroke-color-transition"] = &setTransition; - result["circle-stroke-opacity"] = &setProperty, &CircleLayer::setCircleStrokeOpacity, true, false>; - result["circle-stroke-opacity-transition"] = &setTransition; - - result["heatmap-radius"] = &setProperty, &HeatmapLayer::setHeatmapRadius, true, false>; - result["heatmap-radius-transition"] = &setTransition; - result["heatmap-weight"] = &setProperty, &HeatmapLayer::setHeatmapWeight, true, false>; - result["heatmap-weight-transition"] = &setTransition; - result["heatmap-intensity"] = &setProperty, &HeatmapLayer::setHeatmapIntensity, false, false>; - result["heatmap-intensity-transition"] = &setTransition; - result["heatmap-color"] = &setProperty; - result["heatmap-color-transition"] = &setTransition; - result["heatmap-opacity"] = &setProperty, &HeatmapLayer::setHeatmapOpacity, false, false>; - result["heatmap-opacity-transition"] = &setTransition; - - result["fill-extrusion-opacity"] = &setProperty, &FillExtrusionLayer::setFillExtrusionOpacity, false, false>; - result["fill-extrusion-opacity-transition"] = &setTransition; - result["fill-extrusion-color"] = &setProperty, &FillExtrusionLayer::setFillExtrusionColor, true, false>; - result["fill-extrusion-color-transition"] = &setTransition; - result["fill-extrusion-translate"] = &setProperty>, &FillExtrusionLayer::setFillExtrusionTranslate, false, false>; - result["fill-extrusion-translate-transition"] = &setTransition; - result["fill-extrusion-translate-anchor"] = &setProperty, &FillExtrusionLayer::setFillExtrusionTranslateAnchor, false, false>; - result["fill-extrusion-translate-anchor-transition"] = &setTransition; - result["fill-extrusion-pattern"] = &setProperty, &FillExtrusionLayer::setFillExtrusionPattern, false, false>; - result["fill-extrusion-pattern-transition"] = &setTransition; - result["fill-extrusion-height"] = &setProperty, &FillExtrusionLayer::setFillExtrusionHeight, true, false>; - result["fill-extrusion-height-transition"] = &setTransition; - result["fill-extrusion-base"] = &setProperty, &FillExtrusionLayer::setFillExtrusionBase, true, false>; - result["fill-extrusion-base-transition"] = &setTransition; - - result["raster-opacity"] = &setProperty, &RasterLayer::setRasterOpacity, false, false>; - result["raster-opacity-transition"] = &setTransition; - result["raster-hue-rotate"] = &setProperty, &RasterLayer::setRasterHueRotate, false, false>; - result["raster-hue-rotate-transition"] = &setTransition; - result["raster-brightness-min"] = &setProperty, &RasterLayer::setRasterBrightnessMin, false, false>; - result["raster-brightness-min-transition"] = &setTransition; - result["raster-brightness-max"] = &setProperty, &RasterLayer::setRasterBrightnessMax, false, false>; - result["raster-brightness-max-transition"] = &setTransition; - result["raster-saturation"] = &setProperty, &RasterLayer::setRasterSaturation, false, false>; - result["raster-saturation-transition"] = &setTransition; - result["raster-contrast"] = &setProperty, &RasterLayer::setRasterContrast, false, false>; - result["raster-contrast-transition"] = &setTransition; - result["raster-resampling"] = &setProperty, &RasterLayer::setRasterResampling, false, false>; - result["raster-resampling-transition"] = &setTransition; - result["raster-fade-duration"] = &setProperty, &RasterLayer::setRasterFadeDuration, false, false>; - result["raster-fade-duration-transition"] = &setTransition; - - result["hillshade-illumination-direction"] = &setProperty, &HillshadeLayer::setHillshadeIlluminationDirection, false, false>; - result["hillshade-illumination-direction-transition"] = &setTransition; - result["hillshade-illumination-anchor"] = &setProperty, &HillshadeLayer::setHillshadeIlluminationAnchor, false, false>; - result["hillshade-illumination-anchor-transition"] = &setTransition; - result["hillshade-exaggeration"] = &setProperty, &HillshadeLayer::setHillshadeExaggeration, false, false>; - result["hillshade-exaggeration-transition"] = &setTransition; - result["hillshade-shadow-color"] = &setProperty, &HillshadeLayer::setHillshadeShadowColor, false, false>; - result["hillshade-shadow-color-transition"] = &setTransition; - result["hillshade-highlight-color"] = &setProperty, &HillshadeLayer::setHillshadeHighlightColor, false, false>; - result["hillshade-highlight-color-transition"] = &setTransition; - result["hillshade-accent-color"] = &setProperty, &HillshadeLayer::setHillshadeAccentColor, false, false>; - result["hillshade-accent-color-transition"] = &setTransition; - - result["background-color"] = &setProperty, &BackgroundLayer::setBackgroundColor, false, false>; - result["background-color-transition"] = &setTransition; - result["background-pattern"] = &setProperty, &BackgroundLayer::setBackgroundPattern, false, false>; - result["background-pattern-transition"] = &setTransition; - result["background-opacity"] = &setProperty, &BackgroundLayer::setBackgroundOpacity, false, false>; - result["background-opacity-transition"] = &setTransition; - - return result; -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/conversion/make_property_setters.hpp.ejs b/src/mbgl/style/conversion/make_property_setters.hpp.ejs deleted file mode 100644 index fbf2f93fd6..0000000000 --- a/src/mbgl/style/conversion/make_property_setters.hpp.ejs +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -// This file is generated. Edit make_property_setters.hpp.ejs, then run `make style-code`. - -#include - -<% for (const layer of locals.layers) { -%> -#include _layer.hpp> -<% } -%> - -#include - -namespace mbgl { -namespace style { -namespace conversion { - -inline auto makeLayoutPropertySetters() { - std::unordered_map result; - - result["visibility"] = &setVisibility; - -<% for (const layer of locals.layers) { -%> -<% for (const property of layer.layoutProperties) { -%> - result["<%- property.name %>"] = &setProperty<<%- camelize(layer.type) %>Layer, <%- propertyValueType(property) %>, &<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>, <%- property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven' %>, <%- property.name === 'icon-image' || property.name === 'text-field' %>>; -<% } -%> - -<% } -%> - return result; -} - -inline auto makePaintPropertySetters() { - std::unordered_map result; - -<% for (const layer of locals.layers) { -%> -<% for (const property of layer.paintProperties) { -%> - result["<%- property.name %>"] = &setProperty<<%- camelize(layer.type) %>Layer, <%- propertyValueType(property) %>, &<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>, <%- property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven' %>, <%- property.name === 'icon-image' || property.name === 'text-field' %>>; - result["<%- property.name %>-transition"] = &setTransition<<%- camelize(layer.type) %>Layer, &<%- camelize(layer.type) %>Layer::set<%- camelize(property.name) %>Transition>; -<% } -%> - -<% } -%> - return result; -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/conversion/property_setter.hpp b/src/mbgl/style/conversion/property_setter.hpp deleted file mode 100644 index 3c5c65f96a..0000000000 --- a/src/mbgl/style/conversion/property_setter.hpp +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace mbgl { -namespace style { -namespace conversion { - -using PropertySetter = optional (*) (Layer&, const Convertible&); - -template -optional setProperty(Layer& layer, const Convertible& value) { - auto* typedLayer = layer.as(); - if (!typedLayer) { - return Error { "layer doesn't support this property" }; - } - - Error error; - optional typedValue = convert(value, error, allowDataExpressions, convertTokens); - if (!typedValue) { - return error; - } - - (typedLayer->*setter)(*typedValue); - return nullopt; -} - -template -optional setTransition(Layer& layer, const Convertible& value) { - auto* typedLayer = layer.as(); - if (!typedLayer) { - return Error { "layer doesn't support this property" }; - } - - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - (typedLayer->*setter)(*transition); - return nullopt; -} - -inline optional setVisibility(Layer& layer, const Convertible& value) { - if (isUndefined(value)) { - layer.setVisibility(VisibilityType::Visible); - return nullopt; - } - - Error error; - optional visibility = convert(value, error); - if (!visibility) { - return error; - } - - layer.setVisibility(*visibility); - return nullopt; -} - -} // namespace conversion -} // namespace style -} // namespace mbgl diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index 66ab46c078..837d557722 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -3,6 +3,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include namespace mbgl { namespace style { @@ -149,5 +155,96 @@ TransitionOptions BackgroundLayer::getBackgroundOpacityTransition() const { return impl().paint.template get().options; } +using namespace conversion; + +optional BackgroundLayer::setPaintProperty(const std::string& name, const Convertible& value) { + + if (name == "background-color") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setBackgroundColor(*typedValue); + return nullopt; + } + if (name == "background-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setBackgroundColorTransition(*transition); + return nullopt; + } + + if (name == "background-pattern") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setBackgroundPattern(*typedValue); + return nullopt; + } + if (name == "background-pattern-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setBackgroundPatternTransition(*transition); + return nullopt; + } + + if (name == "background-opacity") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setBackgroundOpacity(*typedValue); + return nullopt; + } + if (name == "background-opacity-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setBackgroundOpacityTransition(*transition); + return nullopt; + } + + return Error { "layer doesn't support this property" }; +} + +optional BackgroundLayer::setLayoutProperty(const std::string& name, const Convertible& value) { + if (name == "visibility") { + if (isUndefined(value)) { + setVisibility(VisibilityType::Visible); + return nullopt; + } + + Error error; + optional visibility = convert(value, error); + if (!visibility) { + return error; + } + + setVisibility(*visibility); + return nullopt; + } + + + return Error { "layer doesn't support this property" }; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index d435ce89e1..3f769e935c 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -3,6 +3,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include namespace mbgl { namespace style { @@ -393,5 +399,264 @@ TransitionOptions CircleLayer::getCircleStrokeOpacityTransition() const { return impl().paint.template get().options; } +using namespace conversion; + +optional CircleLayer::setPaintProperty(const std::string& name, const Convertible& value) { + + if (name == "circle-radius") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setCircleRadius(*typedValue); + return nullopt; + } + if (name == "circle-radius-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setCircleRadiusTransition(*transition); + return nullopt; + } + + if (name == "circle-color") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setCircleColor(*typedValue); + return nullopt; + } + if (name == "circle-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setCircleColorTransition(*transition); + return nullopt; + } + + if (name == "circle-blur") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setCircleBlur(*typedValue); + return nullopt; + } + if (name == "circle-blur-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setCircleBlurTransition(*transition); + return nullopt; + } + + if (name == "circle-opacity") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setCircleOpacity(*typedValue); + return nullopt; + } + if (name == "circle-opacity-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setCircleOpacityTransition(*transition); + return nullopt; + } + + if (name == "circle-translate") { + Error error; + optional>> typedValue = convert>>(value, error, false, false); + if (!typedValue) { + return error; + } + + setCircleTranslate(*typedValue); + return nullopt; + } + if (name == "circle-translate-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setCircleTranslateTransition(*transition); + return nullopt; + } + + if (name == "circle-translate-anchor") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setCircleTranslateAnchor(*typedValue); + return nullopt; + } + if (name == "circle-translate-anchor-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setCircleTranslateAnchorTransition(*transition); + return nullopt; + } + + if (name == "circle-pitch-scale") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setCirclePitchScale(*typedValue); + return nullopt; + } + if (name == "circle-pitch-scale-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setCirclePitchScaleTransition(*transition); + return nullopt; + } + + if (name == "circle-pitch-alignment") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setCirclePitchAlignment(*typedValue); + return nullopt; + } + if (name == "circle-pitch-alignment-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setCirclePitchAlignmentTransition(*transition); + return nullopt; + } + + if (name == "circle-stroke-width") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setCircleStrokeWidth(*typedValue); + return nullopt; + } + if (name == "circle-stroke-width-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setCircleStrokeWidthTransition(*transition); + return nullopt; + } + + if (name == "circle-stroke-color") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setCircleStrokeColor(*typedValue); + return nullopt; + } + if (name == "circle-stroke-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setCircleStrokeColorTransition(*transition); + return nullopt; + } + + if (name == "circle-stroke-opacity") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setCircleStrokeOpacity(*typedValue); + return nullopt; + } + if (name == "circle-stroke-opacity-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setCircleStrokeOpacityTransition(*transition); + return nullopt; + } + + return Error { "layer doesn't support this property" }; +} + +optional CircleLayer::setLayoutProperty(const std::string& name, const Convertible& value) { + if (name == "visibility") { + if (isUndefined(value)) { + setVisibility(VisibilityType::Visible); + return nullopt; + } + + Error error; + optional visibility = convert(value, error); + if (!visibility) { + return error; + } + + setVisibility(*visibility); + return nullopt; + } + + + return Error { "layer doesn't support this property" }; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/custom_layer.cpp b/src/mbgl/style/layers/custom_layer.cpp index 0e51a70e50..d1ac1a705c 100644 --- a/src/mbgl/style/layers/custom_layer.cpp +++ b/src/mbgl/style/layers/custom_layer.cpp @@ -50,6 +50,16 @@ void CustomLayer::setMaxZoom(float maxZoom) { baseImpl = std::move(impl_); } +using namespace conversion; + +optional CustomLayer::setPaintProperty(const std::string&, const Convertible&) { + return Error { "layer doesn't support this property" }; +} + +optional CustomLayer::setLayoutProperty(const std::string&, const Convertible&) { + return Error { "layer doesn't support this property" }; +} + template <> bool Layer::is() const { return getType() == LayerType::Custom; diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index 829a24f354..b48e51c566 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -3,6 +3,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include namespace mbgl { namespace style { @@ -285,5 +291,180 @@ TransitionOptions FillExtrusionLayer::getFillExtrusionBaseTransition() const { return impl().paint.template get().options; } +using namespace conversion; + +optional FillExtrusionLayer::setPaintProperty(const std::string& name, const Convertible& value) { + + if (name == "fill-extrusion-opacity") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setFillExtrusionOpacity(*typedValue); + return nullopt; + } + if (name == "fill-extrusion-opacity-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillExtrusionOpacityTransition(*transition); + return nullopt; + } + + if (name == "fill-extrusion-color") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setFillExtrusionColor(*typedValue); + return nullopt; + } + if (name == "fill-extrusion-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillExtrusionColorTransition(*transition); + return nullopt; + } + + if (name == "fill-extrusion-translate") { + Error error; + optional>> typedValue = convert>>(value, error, false, false); + if (!typedValue) { + return error; + } + + setFillExtrusionTranslate(*typedValue); + return nullopt; + } + if (name == "fill-extrusion-translate-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillExtrusionTranslateTransition(*transition); + return nullopt; + } + + if (name == "fill-extrusion-translate-anchor") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setFillExtrusionTranslateAnchor(*typedValue); + return nullopt; + } + if (name == "fill-extrusion-translate-anchor-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillExtrusionTranslateAnchorTransition(*transition); + return nullopt; + } + + if (name == "fill-extrusion-pattern") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setFillExtrusionPattern(*typedValue); + return nullopt; + } + if (name == "fill-extrusion-pattern-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillExtrusionPatternTransition(*transition); + return nullopt; + } + + if (name == "fill-extrusion-height") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setFillExtrusionHeight(*typedValue); + return nullopt; + } + if (name == "fill-extrusion-height-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillExtrusionHeightTransition(*transition); + return nullopt; + } + + if (name == "fill-extrusion-base") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setFillExtrusionBase(*typedValue); + return nullopt; + } + if (name == "fill-extrusion-base-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillExtrusionBaseTransition(*transition); + return nullopt; + } + + return Error { "layer doesn't support this property" }; +} + +optional FillExtrusionLayer::setLayoutProperty(const std::string& name, const Convertible& value) { + if (name == "visibility") { + if (isUndefined(value)) { + setVisibility(VisibilityType::Visible); + return nullopt; + } + + Error error; + optional visibility = convert(value, error); + if (!visibility) { + return error; + } + + setVisibility(*visibility); + return nullopt; + } + + + return Error { "layer doesn't support this property" }; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index 8eebd54e3c..04c3bcef3f 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -3,6 +3,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include namespace mbgl { namespace style { @@ -285,5 +291,180 @@ TransitionOptions FillLayer::getFillPatternTransition() const { return impl().paint.template get().options; } +using namespace conversion; + +optional FillLayer::setPaintProperty(const std::string& name, const Convertible& value) { + + if (name == "fill-antialias") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setFillAntialias(*typedValue); + return nullopt; + } + if (name == "fill-antialias-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillAntialiasTransition(*transition); + return nullopt; + } + + if (name == "fill-opacity") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setFillOpacity(*typedValue); + return nullopt; + } + if (name == "fill-opacity-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillOpacityTransition(*transition); + return nullopt; + } + + if (name == "fill-color") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setFillColor(*typedValue); + return nullopt; + } + if (name == "fill-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillColorTransition(*transition); + return nullopt; + } + + if (name == "fill-outline-color") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setFillOutlineColor(*typedValue); + return nullopt; + } + if (name == "fill-outline-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillOutlineColorTransition(*transition); + return nullopt; + } + + if (name == "fill-translate") { + Error error; + optional>> typedValue = convert>>(value, error, false, false); + if (!typedValue) { + return error; + } + + setFillTranslate(*typedValue); + return nullopt; + } + if (name == "fill-translate-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillTranslateTransition(*transition); + return nullopt; + } + + if (name == "fill-translate-anchor") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setFillTranslateAnchor(*typedValue); + return nullopt; + } + if (name == "fill-translate-anchor-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillTranslateAnchorTransition(*transition); + return nullopt; + } + + if (name == "fill-pattern") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setFillPattern(*typedValue); + return nullopt; + } + if (name == "fill-pattern-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setFillPatternTransition(*transition); + return nullopt; + } + + return Error { "layer doesn't support this property" }; +} + +optional FillLayer::setLayoutProperty(const std::string& name, const Convertible& value) { + if (name == "visibility") { + if (isUndefined(value)) { + setVisibility(VisibilityType::Visible); + return nullopt; + } + + Error error; + optional visibility = convert(value, error); + if (!visibility) { + return error; + } + + setVisibility(*visibility); + return nullopt; + } + + + return Error { "layer doesn't support this property" }; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index 21016ee509..443b94c2ce 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -3,9 +3,11 @@ #include #include #include -// for constructing default heatmap-color ramp expression from style JSON #include #include +#include +#include +#include #include namespace mbgl { @@ -237,5 +239,138 @@ TransitionOptions HeatmapLayer::getHeatmapOpacityTransition() const { return impl().paint.template get().options; } +using namespace conversion; + +optional HeatmapLayer::setPaintProperty(const std::string& name, const Convertible& value) { + + if (name == "heatmap-radius") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setHeatmapRadius(*typedValue); + return nullopt; + } + if (name == "heatmap-radius-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setHeatmapRadiusTransition(*transition); + return nullopt; + } + + if (name == "heatmap-weight") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setHeatmapWeight(*typedValue); + return nullopt; + } + if (name == "heatmap-weight-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setHeatmapWeightTransition(*transition); + return nullopt; + } + + if (name == "heatmap-intensity") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setHeatmapIntensity(*typedValue); + return nullopt; + } + if (name == "heatmap-intensity-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setHeatmapIntensityTransition(*transition); + return nullopt; + } + + if (name == "heatmap-color") { + Error error; + optional typedValue = convert(value, error, false, false); + if (!typedValue) { + return error; + } + + setHeatmapColor(*typedValue); + return nullopt; + } + if (name == "heatmap-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setHeatmapColorTransition(*transition); + return nullopt; + } + + if (name == "heatmap-opacity") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setHeatmapOpacity(*typedValue); + return nullopt; + } + if (name == "heatmap-opacity-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setHeatmapOpacityTransition(*transition); + return nullopt; + } + + return Error { "layer doesn't support this property" }; +} + +optional HeatmapLayer::setLayoutProperty(const std::string& name, const Convertible& value) { + if (name == "visibility") { + if (isUndefined(value)) { + setVisibility(VisibilityType::Visible); + return nullopt; + } + + Error error; + optional visibility = convert(value, error); + if (!visibility) { + return error; + } + + setVisibility(*visibility); + return nullopt; + } + + + return Error { "layer doesn't support this property" }; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp index e352ae090c..2d8c837baa 100644 --- a/src/mbgl/style/layers/hillshade_layer.cpp +++ b/src/mbgl/style/layers/hillshade_layer.cpp @@ -3,6 +3,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include namespace mbgl { namespace style { @@ -236,5 +242,159 @@ TransitionOptions HillshadeLayer::getHillshadeAccentColorTransition() const { return impl().paint.template get().options; } +using namespace conversion; + +optional HillshadeLayer::setPaintProperty(const std::string& name, const Convertible& value) { + + if (name == "hillshade-illumination-direction") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setHillshadeIlluminationDirection(*typedValue); + return nullopt; + } + if (name == "hillshade-illumination-direction-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setHillshadeIlluminationDirectionTransition(*transition); + return nullopt; + } + + if (name == "hillshade-illumination-anchor") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setHillshadeIlluminationAnchor(*typedValue); + return nullopt; + } + if (name == "hillshade-illumination-anchor-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setHillshadeIlluminationAnchorTransition(*transition); + return nullopt; + } + + if (name == "hillshade-exaggeration") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setHillshadeExaggeration(*typedValue); + return nullopt; + } + if (name == "hillshade-exaggeration-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setHillshadeExaggerationTransition(*transition); + return nullopt; + } + + if (name == "hillshade-shadow-color") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setHillshadeShadowColor(*typedValue); + return nullopt; + } + if (name == "hillshade-shadow-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setHillshadeShadowColorTransition(*transition); + return nullopt; + } + + if (name == "hillshade-highlight-color") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setHillshadeHighlightColor(*typedValue); + return nullopt; + } + if (name == "hillshade-highlight-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setHillshadeHighlightColorTransition(*transition); + return nullopt; + } + + if (name == "hillshade-accent-color") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setHillshadeAccentColor(*typedValue); + return nullopt; + } + if (name == "hillshade-accent-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setHillshadeAccentColorTransition(*transition); + return nullopt; + } + + return Error { "layer doesn't support this property" }; +} + +optional HillshadeLayer::setLayoutProperty(const std::string& name, const Convertible& value) { + if (name == "visibility") { + if (isUndefined(value)) { + setVisibility(VisibilityType::Visible); + return nullopt; + } + + Error error; + optional visibility = convert(value, error); + if (!visibility) { + return error; + } + + setVisibility(*visibility); + return nullopt; + } + + + return Error { "layer doesn't support this property" }; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index a9b6d9d02d..7555054bdb 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -8,12 +8,12 @@ #include _layer.hpp> #include _layer_impl.hpp> #include -<% if (type === 'heatmap') { -%> -// for constructing default heatmap-color ramp expression from style JSON #include #include +#include +#include +#include #include -<% } -%> namespace mbgl { namespace style { @@ -175,5 +175,67 @@ TransitionOptions <%- camelize(type) %>Layer::get<%- camelize(property.name) %>T } <% } -%> +using namespace conversion; + +optional <%- camelize(type) %>Layer::setPaintProperty(const std::string& name, const Convertible& value) { + <% for (const property of paintProperties) { %> + if (name == "<%- property.name %>") { + Error error; + optional<<%- propertyValueType(property) %>> typedValue = convert<<%- propertyValueType(property) %>>(value, error, <%- property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven' %>, <%- property.name === 'icon-image' || property.name === 'text-field' %>); + if (!typedValue) { + return error; + } + + set<%- camelize(property.name) %>(*typedValue); + return nullopt; + } + if (name == "<%- property.name %>-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + set<%- camelize(property.name) %>Transition(*transition); + return nullopt; + } + <% } -%> + + return Error { "layer doesn't support this property" }; +} + +optional <%- camelize(type) %>Layer::setLayoutProperty(const std::string& name, const Convertible& value) { + if (name == "visibility") { + if (isUndefined(value)) { + setVisibility(VisibilityType::Visible); + return nullopt; + } + + Error error; + optional visibility = convert(value, error); + if (!visibility) { + return error; + } + + setVisibility(*visibility); + return nullopt; + } + + <% for (const property of layoutProperties) { %> + if (name == "<%- property.name %>") { + Error error; + optional<<%- propertyValueType(property) %>> typedValue = convert<<%- propertyValueType(property) %>>(value, error, <%- property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven' %>, <%- property.name === 'icon-image' || property.name === 'text-field' %>); + if (!typedValue) { + return error; + } + + set<%- camelize(property.name) %>(*typedValue); + return nullopt; + } + <% } -%> + + return Error { "layer doesn't support this property" }; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index 0cda849c0f..c3203f84e4 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -3,6 +3,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include namespace mbgl { namespace style { @@ -431,5 +437,287 @@ TransitionOptions LineLayer::getLinePatternTransition() const { return impl().paint.template get().options; } +using namespace conversion; + +optional LineLayer::setPaintProperty(const std::string& name, const Convertible& value) { + + if (name == "line-opacity") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setLineOpacity(*typedValue); + return nullopt; + } + if (name == "line-opacity-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setLineOpacityTransition(*transition); + return nullopt; + } + + if (name == "line-color") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setLineColor(*typedValue); + return nullopt; + } + if (name == "line-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setLineColorTransition(*transition); + return nullopt; + } + + if (name == "line-translate") { + Error error; + optional>> typedValue = convert>>(value, error, false, false); + if (!typedValue) { + return error; + } + + setLineTranslate(*typedValue); + return nullopt; + } + if (name == "line-translate-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setLineTranslateTransition(*transition); + return nullopt; + } + + if (name == "line-translate-anchor") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setLineTranslateAnchor(*typedValue); + return nullopt; + } + if (name == "line-translate-anchor-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setLineTranslateAnchorTransition(*transition); + return nullopt; + } + + if (name == "line-width") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setLineWidth(*typedValue); + return nullopt; + } + if (name == "line-width-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setLineWidthTransition(*transition); + return nullopt; + } + + if (name == "line-gap-width") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setLineGapWidth(*typedValue); + return nullopt; + } + if (name == "line-gap-width-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setLineGapWidthTransition(*transition); + return nullopt; + } + + if (name == "line-offset") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setLineOffset(*typedValue); + return nullopt; + } + if (name == "line-offset-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setLineOffsetTransition(*transition); + return nullopt; + } + + if (name == "line-blur") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setLineBlur(*typedValue); + return nullopt; + } + if (name == "line-blur-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setLineBlurTransition(*transition); + return nullopt; + } + + if (name == "line-dasharray") { + Error error; + optional>> typedValue = convert>>(value, error, false, false); + if (!typedValue) { + return error; + } + + setLineDasharray(*typedValue); + return nullopt; + } + if (name == "line-dasharray-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setLineDasharrayTransition(*transition); + return nullopt; + } + + if (name == "line-pattern") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setLinePattern(*typedValue); + return nullopt; + } + if (name == "line-pattern-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setLinePatternTransition(*transition); + return nullopt; + } + + return Error { "layer doesn't support this property" }; +} + +optional LineLayer::setLayoutProperty(const std::string& name, const Convertible& value) { + if (name == "visibility") { + if (isUndefined(value)) { + setVisibility(VisibilityType::Visible); + return nullopt; + } + + Error error; + optional visibility = convert(value, error); + if (!visibility) { + return error; + } + + setVisibility(*visibility); + return nullopt; + } + + + if (name == "line-cap") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setLineCap(*typedValue); + return nullopt; + } + + if (name == "line-join") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setLineJoin(*typedValue); + return nullopt; + } + + if (name == "line-miter-limit") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setLineMiterLimit(*typedValue); + return nullopt; + } + + if (name == "line-round-limit") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setLineRoundLimit(*typedValue); + return nullopt; + } + + return Error { "layer doesn't support this property" }; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index e5b03df0f6..0eba8ef886 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -3,6 +3,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include namespace mbgl { namespace style { @@ -290,5 +296,201 @@ TransitionOptions RasterLayer::getRasterFadeDurationTransition() const { return impl().paint.template get().options; } +using namespace conversion; + +optional RasterLayer::setPaintProperty(const std::string& name, const Convertible& value) { + + if (name == "raster-opacity") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setRasterOpacity(*typedValue); + return nullopt; + } + if (name == "raster-opacity-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setRasterOpacityTransition(*transition); + return nullopt; + } + + if (name == "raster-hue-rotate") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setRasterHueRotate(*typedValue); + return nullopt; + } + if (name == "raster-hue-rotate-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setRasterHueRotateTransition(*transition); + return nullopt; + } + + if (name == "raster-brightness-min") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setRasterBrightnessMin(*typedValue); + return nullopt; + } + if (name == "raster-brightness-min-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setRasterBrightnessMinTransition(*transition); + return nullopt; + } + + if (name == "raster-brightness-max") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setRasterBrightnessMax(*typedValue); + return nullopt; + } + if (name == "raster-brightness-max-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setRasterBrightnessMaxTransition(*transition); + return nullopt; + } + + if (name == "raster-saturation") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setRasterSaturation(*typedValue); + return nullopt; + } + if (name == "raster-saturation-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setRasterSaturationTransition(*transition); + return nullopt; + } + + if (name == "raster-contrast") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setRasterContrast(*typedValue); + return nullopt; + } + if (name == "raster-contrast-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setRasterContrastTransition(*transition); + return nullopt; + } + + if (name == "raster-resampling") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setRasterResampling(*typedValue); + return nullopt; + } + if (name == "raster-resampling-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setRasterResamplingTransition(*transition); + return nullopt; + } + + if (name == "raster-fade-duration") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setRasterFadeDuration(*typedValue); + return nullopt; + } + if (name == "raster-fade-duration-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setRasterFadeDurationTransition(*transition); + return nullopt; + } + + return Error { "layer doesn't support this property" }; +} + +optional RasterLayer::setLayoutProperty(const std::string& name, const Convertible& value) { + if (name == "visibility") { + if (isUndefined(value)) { + setVisibility(VisibilityType::Visible); + return nullopt; + } + + Error error; + optional visibility = convert(value, error); + if (!visibility) { + return error; + } + + setVisibility(*visibility); + return nullopt; + } + + + return Error { "layer doesn't support this property" }; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index c416c6a6c5..bb5b317a38 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -3,6 +3,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include namespace mbgl { namespace style { @@ -1051,5 +1057,723 @@ TransitionOptions SymbolLayer::getTextTranslateAnchorTransition() const { return impl().paint.template get().options; } +using namespace conversion; + +optional SymbolLayer::setPaintProperty(const std::string& name, const Convertible& value) { + + if (name == "icon-opacity") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setIconOpacity(*typedValue); + return nullopt; + } + if (name == "icon-opacity-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setIconOpacityTransition(*transition); + return nullopt; + } + + if (name == "icon-color") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setIconColor(*typedValue); + return nullopt; + } + if (name == "icon-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setIconColorTransition(*transition); + return nullopt; + } + + if (name == "icon-halo-color") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setIconHaloColor(*typedValue); + return nullopt; + } + if (name == "icon-halo-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setIconHaloColorTransition(*transition); + return nullopt; + } + + if (name == "icon-halo-width") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setIconHaloWidth(*typedValue); + return nullopt; + } + if (name == "icon-halo-width-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setIconHaloWidthTransition(*transition); + return nullopt; + } + + if (name == "icon-halo-blur") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setIconHaloBlur(*typedValue); + return nullopt; + } + if (name == "icon-halo-blur-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setIconHaloBlurTransition(*transition); + return nullopt; + } + + if (name == "icon-translate") { + Error error; + optional>> typedValue = convert>>(value, error, false, false); + if (!typedValue) { + return error; + } + + setIconTranslate(*typedValue); + return nullopt; + } + if (name == "icon-translate-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setIconTranslateTransition(*transition); + return nullopt; + } + + if (name == "icon-translate-anchor") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setIconTranslateAnchor(*typedValue); + return nullopt; + } + if (name == "icon-translate-anchor-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setIconTranslateAnchorTransition(*transition); + return nullopt; + } + + if (name == "text-opacity") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextOpacity(*typedValue); + return nullopt; + } + if (name == "text-opacity-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setTextOpacityTransition(*transition); + return nullopt; + } + + if (name == "text-color") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextColor(*typedValue); + return nullopt; + } + if (name == "text-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setTextColorTransition(*transition); + return nullopt; + } + + if (name == "text-halo-color") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextHaloColor(*typedValue); + return nullopt; + } + if (name == "text-halo-color-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setTextHaloColorTransition(*transition); + return nullopt; + } + + if (name == "text-halo-width") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextHaloWidth(*typedValue); + return nullopt; + } + if (name == "text-halo-width-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setTextHaloWidthTransition(*transition); + return nullopt; + } + + if (name == "text-halo-blur") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextHaloBlur(*typedValue); + return nullopt; + } + if (name == "text-halo-blur-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setTextHaloBlurTransition(*transition); + return nullopt; + } + + if (name == "text-translate") { + Error error; + optional>> typedValue = convert>>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextTranslate(*typedValue); + return nullopt; + } + if (name == "text-translate-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setTextTranslateTransition(*transition); + return nullopt; + } + + if (name == "text-translate-anchor") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextTranslateAnchor(*typedValue); + return nullopt; + } + if (name == "text-translate-anchor-transition") { + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + setTextTranslateAnchorTransition(*transition); + return nullopt; + } + + return Error { "layer doesn't support this property" }; +} + +optional SymbolLayer::setLayoutProperty(const std::string& name, const Convertible& value) { + if (name == "visibility") { + if (isUndefined(value)) { + setVisibility(VisibilityType::Visible); + return nullopt; + } + + Error error; + optional visibility = convert(value, error); + if (!visibility) { + return error; + } + + setVisibility(*visibility); + return nullopt; + } + + + if (name == "symbol-placement") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setSymbolPlacement(*typedValue); + return nullopt; + } + + if (name == "symbol-spacing") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setSymbolSpacing(*typedValue); + return nullopt; + } + + if (name == "symbol-avoid-edges") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setSymbolAvoidEdges(*typedValue); + return nullopt; + } + + if (name == "icon-allow-overlap") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setIconAllowOverlap(*typedValue); + return nullopt; + } + + if (name == "icon-ignore-placement") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setIconIgnorePlacement(*typedValue); + return nullopt; + } + + if (name == "icon-optional") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setIconOptional(*typedValue); + return nullopt; + } + + if (name == "icon-rotation-alignment") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setIconRotationAlignment(*typedValue); + return nullopt; + } + + if (name == "icon-size") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setIconSize(*typedValue); + return nullopt; + } + + if (name == "icon-text-fit") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setIconTextFit(*typedValue); + return nullopt; + } + + if (name == "icon-text-fit-padding") { + Error error; + optional>> typedValue = convert>>(value, error, false, false); + if (!typedValue) { + return error; + } + + setIconTextFitPadding(*typedValue); + return nullopt; + } + + if (name == "icon-image") { + Error error; + optional> typedValue = convert>(value, error, true, true); + if (!typedValue) { + return error; + } + + setIconImage(*typedValue); + return nullopt; + } + + if (name == "icon-rotate") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setIconRotate(*typedValue); + return nullopt; + } + + if (name == "icon-padding") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setIconPadding(*typedValue); + return nullopt; + } + + if (name == "icon-keep-upright") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setIconKeepUpright(*typedValue); + return nullopt; + } + + if (name == "icon-offset") { + Error error; + optional>> typedValue = convert>>(value, error, true, false); + if (!typedValue) { + return error; + } + + setIconOffset(*typedValue); + return nullopt; + } + + if (name == "icon-anchor") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setIconAnchor(*typedValue); + return nullopt; + } + + if (name == "icon-pitch-alignment") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setIconPitchAlignment(*typedValue); + return nullopt; + } + + if (name == "text-pitch-alignment") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextPitchAlignment(*typedValue); + return nullopt; + } + + if (name == "text-rotation-alignment") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextRotationAlignment(*typedValue); + return nullopt; + } + + if (name == "text-field") { + Error error; + optional> typedValue = convert>(value, error, true, true); + if (!typedValue) { + return error; + } + + setTextField(*typedValue); + return nullopt; + } + + if (name == "text-font") { + Error error; + optional>> typedValue = convert>>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextFont(*typedValue); + return nullopt; + } + + if (name == "text-size") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextSize(*typedValue); + return nullopt; + } + + if (name == "text-max-width") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextMaxWidth(*typedValue); + return nullopt; + } + + if (name == "text-line-height") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextLineHeight(*typedValue); + return nullopt; + } + + if (name == "text-letter-spacing") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextLetterSpacing(*typedValue); + return nullopt; + } + + if (name == "text-justify") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextJustify(*typedValue); + return nullopt; + } + + if (name == "text-anchor") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextAnchor(*typedValue); + return nullopt; + } + + if (name == "text-max-angle") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextMaxAngle(*typedValue); + return nullopt; + } + + if (name == "text-rotate") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextRotate(*typedValue); + return nullopt; + } + + if (name == "text-padding") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextPadding(*typedValue); + return nullopt; + } + + if (name == "text-keep-upright") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextKeepUpright(*typedValue); + return nullopt; + } + + if (name == "text-transform") { + Error error; + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextTransform(*typedValue); + return nullopt; + } + + if (name == "text-offset") { + Error error; + optional>> typedValue = convert>>(value, error, true, false); + if (!typedValue) { + return error; + } + + setTextOffset(*typedValue); + return nullopt; + } + + if (name == "text-allow-overlap") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextAllowOverlap(*typedValue); + return nullopt; + } + + if (name == "text-ignore-placement") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextIgnorePlacement(*typedValue); + return nullopt; + } + + if (name == "text-optional") { + Error error; + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { + return error; + } + + setTextOptional(*typedValue); + return nullopt; + } + + return Error { "layer doesn't support this property" }; +} + } // namespace style } // namespace mbgl -- cgit v1.2.1 From 58202eaf80bdfe1273396d2abe6b1fee8fed937a Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 10 Aug 2018 11:27:25 -0700 Subject: [core] Optimize generated set{Paint,Layout}Property code --- cmake/core-files.cmake | 1 + src/mbgl/style/layers/background_layer.cpp | 124 +- src/mbgl/style/layers/circle_layer.cpp | 405 ++++--- src/mbgl/style/layers/fill_extrusion_layer.cpp | 257 +++-- src/mbgl/style/layers/fill_layer.cpp | 261 +++-- src/mbgl/style/layers/heatmap_layer.cpp | 202 ++-- src/mbgl/style/layers/heatmap_layer_properties.hpp | 3 +- src/mbgl/style/layers/hillshade_layer.cpp | 237 ++-- src/mbgl/style/layers/layer.cpp.ejs | 125 +- src/mbgl/style/layers/layer_properties.hpp.ejs | 3 +- src/mbgl/style/layers/line_layer.cpp | 423 ++++--- src/mbgl/style/layers/raster_layer.cpp | 308 +++-- src/mbgl/style/layers/symbol_layer.cpp | 1193 ++++++++++++-------- src/mbgl/util/fnv_hash.hpp | 11 + 14 files changed, 2261 insertions(+), 1292 deletions(-) create mode 100644 src/mbgl/util/fnv_hash.hpp diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index d35e2c66ca..e875f5b142 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -707,6 +707,7 @@ set(MBGL_CORE_FILES src/mbgl/util/dtoa.cpp src/mbgl/util/dtoa.hpp src/mbgl/util/event.cpp + src/mbgl/util/fnv_hash.hpp src/mbgl/util/font_stack.cpp src/mbgl/util/geo.cpp src/mbgl/util/geojson_impl.cpp diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index 837d557722..88e175cb7c 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -158,70 +159,115 @@ TransitionOptions BackgroundLayer::getBackgroundOpacityTransition() const { using namespace conversion; optional BackgroundLayer::setPaintProperty(const std::string& name, const Convertible& value) { + enum class Property { + Unknown, + BackgroundColor, + BackgroundPattern, + BackgroundOpacity, + BackgroundColorTransition, + BackgroundPatternTransition, + BackgroundOpacityTransition, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + case util::hashFNV1a("background-color"): + if (name == "background-color") { + property = Property::BackgroundColor; + } + break; + case util::hashFNV1a("background-color-transition"): + if (name == "background-color-transition") { + property = Property::BackgroundColorTransition; + } + break; + case util::hashFNV1a("background-pattern"): + if (name == "background-pattern") { + property = Property::BackgroundPattern; + } + break; + case util::hashFNV1a("background-pattern-transition"): + if (name == "background-pattern-transition") { + property = Property::BackgroundPatternTransition; + } + break; + case util::hashFNV1a("background-opacity"): + if (name == "background-opacity") { + property = Property::BackgroundOpacity; + } + break; + case util::hashFNV1a("background-opacity-transition"): + if (name == "background-opacity-transition") { + property = Property::BackgroundOpacityTransition; + } + break; - if (name == "background-color") { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + if (property == Property::BackgroundColor) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setBackgroundColor(*typedValue); return nullopt; - } - if (name == "background-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setBackgroundColorTransition(*transition); - return nullopt; + } - if (name == "background-pattern") { + if (property == Property::BackgroundPattern) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setBackgroundPattern(*typedValue); return nullopt; - } - if (name == "background-pattern-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setBackgroundPatternTransition(*transition); - return nullopt; + } - if (name == "background-opacity") { + if (property == Property::BackgroundOpacity) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setBackgroundOpacity(*typedValue); return nullopt; + } - if (name == "background-opacity-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } + + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + if (property == Property::BackgroundColorTransition) { + setBackgroundColorTransition(*transition); + return nullopt; + } + + if (property == Property::BackgroundPatternTransition) { + setBackgroundPatternTransition(*transition); + return nullopt; + } + + if (property == Property::BackgroundOpacityTransition) { setBackgroundOpacityTransition(*transition); return nullopt; } + return Error { "layer doesn't support this property" }; } @@ -242,7 +288,21 @@ optional BackgroundLayer::setLayoutProperty(const std::string& name, cons return nullopt; } + enum class Property { + Unknown, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + return Error { "layer doesn't support this property" }; } diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 3f769e935c..eb3227da37 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -402,238 +403,316 @@ TransitionOptions CircleLayer::getCircleStrokeOpacityTransition() const { using namespace conversion; optional CircleLayer::setPaintProperty(const std::string& name, const Convertible& value) { - - if (name == "circle-radius") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; + enum class Property { + Unknown, + CircleRadius, + CircleColor, + CircleBlur, + CircleOpacity, + CircleTranslate, + CircleTranslateAnchor, + CirclePitchScale, + CirclePitchAlignment, + CircleStrokeWidth, + CircleStrokeColor, + CircleStrokeOpacity, + CircleRadiusTransition, + CircleColorTransition, + CircleBlurTransition, + CircleOpacityTransition, + CircleTranslateTransition, + CircleTranslateAnchorTransition, + CirclePitchScaleTransition, + CirclePitchAlignmentTransition, + CircleStrokeWidthTransition, + CircleStrokeColorTransition, + CircleStrokeOpacityTransition, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + case util::hashFNV1a("circle-radius"): + if (name == "circle-radius") { + property = Property::CircleRadius; } - - setCircleRadius(*typedValue); - return nullopt; - } - if (name == "circle-radius-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + break; + case util::hashFNV1a("circle-radius-transition"): + if (name == "circle-radius-transition") { + property = Property::CircleRadiusTransition; } - - setCircleRadiusTransition(*transition); - return nullopt; - } - - if (name == "circle-color") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; + break; + case util::hashFNV1a("circle-color"): + if (name == "circle-color") { + property = Property::CircleColor; } - - setCircleColor(*typedValue); - return nullopt; - } - if (name == "circle-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + break; + case util::hashFNV1a("circle-color-transition"): + if (name == "circle-color-transition") { + property = Property::CircleColorTransition; + } + break; + case util::hashFNV1a("circle-blur"): + if (name == "circle-blur") { + property = Property::CircleBlur; + } + break; + case util::hashFNV1a("circle-blur-transition"): + if (name == "circle-blur-transition") { + property = Property::CircleBlurTransition; + } + break; + case util::hashFNV1a("circle-opacity"): + if (name == "circle-opacity") { + property = Property::CircleOpacity; + } + break; + case util::hashFNV1a("circle-opacity-transition"): + if (name == "circle-opacity-transition") { + property = Property::CircleOpacityTransition; + } + break; + case util::hashFNV1a("circle-translate"): + if (name == "circle-translate") { + property = Property::CircleTranslate; + } + break; + case util::hashFNV1a("circle-translate-transition"): + if (name == "circle-translate-transition") { + property = Property::CircleTranslateTransition; + } + break; + case util::hashFNV1a("circle-translate-anchor"): + if (name == "circle-translate-anchor") { + property = Property::CircleTranslateAnchor; + } + break; + case util::hashFNV1a("circle-translate-anchor-transition"): + if (name == "circle-translate-anchor-transition") { + property = Property::CircleTranslateAnchorTransition; + } + break; + case util::hashFNV1a("circle-pitch-scale"): + if (name == "circle-pitch-scale") { + property = Property::CirclePitchScale; } + break; + case util::hashFNV1a("circle-pitch-scale-transition"): + if (name == "circle-pitch-scale-transition") { + property = Property::CirclePitchScaleTransition; + } + break; + case util::hashFNV1a("circle-pitch-alignment"): + if (name == "circle-pitch-alignment") { + property = Property::CirclePitchAlignment; + } + break; + case util::hashFNV1a("circle-pitch-alignment-transition"): + if (name == "circle-pitch-alignment-transition") { + property = Property::CirclePitchAlignmentTransition; + } + break; + case util::hashFNV1a("circle-stroke-width"): + if (name == "circle-stroke-width") { + property = Property::CircleStrokeWidth; + } + break; + case util::hashFNV1a("circle-stroke-width-transition"): + if (name == "circle-stroke-width-transition") { + property = Property::CircleStrokeWidthTransition; + } + break; + case util::hashFNV1a("circle-stroke-color"): + if (name == "circle-stroke-color") { + property = Property::CircleStrokeColor; + } + break; + case util::hashFNV1a("circle-stroke-color-transition"): + if (name == "circle-stroke-color-transition") { + property = Property::CircleStrokeColorTransition; + } + break; + case util::hashFNV1a("circle-stroke-opacity"): + if (name == "circle-stroke-opacity") { + property = Property::CircleStrokeOpacity; + } + break; + case util::hashFNV1a("circle-stroke-opacity-transition"): + if (name == "circle-stroke-opacity-transition") { + property = Property::CircleStrokeOpacityTransition; + } + break; + + } - setCircleColorTransition(*transition); - return nullopt; + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; } - - if (name == "circle-blur") { + + + if (property == Property::CircleRadius || property == Property::CircleBlur || property == Property::CircleOpacity || property == Property::CircleStrokeWidth || property == Property::CircleStrokeOpacity) { Error error; optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - - setCircleBlur(*typedValue); - return nullopt; - } - if (name == "circle-blur-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::CircleRadius) { + setCircleRadius(*typedValue); + return nullopt; } - - setCircleBlurTransition(*transition); - return nullopt; + + if (property == Property::CircleBlur) { + setCircleBlur(*typedValue); + return nullopt; + } + + if (property == Property::CircleOpacity) { + setCircleOpacity(*typedValue); + return nullopt; + } + + if (property == Property::CircleStrokeWidth) { + setCircleStrokeWidth(*typedValue); + return nullopt; + } + + if (property == Property::CircleStrokeOpacity) { + setCircleStrokeOpacity(*typedValue); + return nullopt; + } + } - if (name == "circle-opacity") { + if (property == Property::CircleColor || property == Property::CircleStrokeColor) { Error error; - optional> typedValue = convert>(value, error, true, false); + optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - - setCircleOpacity(*typedValue); - return nullopt; - } - if (name == "circle-opacity-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::CircleColor) { + setCircleColor(*typedValue); + return nullopt; } - - setCircleOpacityTransition(*transition); - return nullopt; + + if (property == Property::CircleStrokeColor) { + setCircleStrokeColor(*typedValue); + return nullopt; + } + } - if (name == "circle-translate") { + if (property == Property::CircleTranslate) { Error error; optional>> typedValue = convert>>(value, error, false, false); if (!typedValue) { return error; } - + setCircleTranslate(*typedValue); return nullopt; - } - if (name == "circle-translate-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setCircleTranslateTransition(*transition); - return nullopt; + } - if (name == "circle-translate-anchor") { + if (property == Property::CircleTranslateAnchor) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setCircleTranslateAnchor(*typedValue); return nullopt; - } - if (name == "circle-translate-anchor-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setCircleTranslateAnchorTransition(*transition); - return nullopt; + } - if (name == "circle-pitch-scale") { + if (property == Property::CirclePitchScale) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setCirclePitchScale(*typedValue); return nullopt; - } - if (name == "circle-pitch-scale-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setCirclePitchScaleTransition(*transition); - return nullopt; + } - if (name == "circle-pitch-alignment") { + if (property == Property::CirclePitchAlignment) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setCirclePitchAlignment(*typedValue); return nullopt; + } - if (name == "circle-pitch-alignment-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } + - setCirclePitchAlignmentTransition(*transition); + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + if (property == Property::CircleRadiusTransition) { + setCircleRadiusTransition(*transition); return nullopt; } - if (name == "circle-stroke-width") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setCircleStrokeWidth(*typedValue); + if (property == Property::CircleColorTransition) { + setCircleColorTransition(*transition); return nullopt; } - if (name == "circle-stroke-width-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setCircleStrokeWidthTransition(*transition); + + if (property == Property::CircleBlurTransition) { + setCircleBlurTransition(*transition); return nullopt; } - if (name == "circle-stroke-color") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setCircleStrokeColor(*typedValue); + if (property == Property::CircleOpacityTransition) { + setCircleOpacityTransition(*transition); return nullopt; } - if (name == "circle-stroke-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setCircleStrokeColorTransition(*transition); + + if (property == Property::CircleTranslateTransition) { + setCircleTranslateTransition(*transition); return nullopt; } - if (name == "circle-stroke-opacity") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setCircleStrokeOpacity(*typedValue); + if (property == Property::CircleTranslateAnchorTransition) { + setCircleTranslateAnchorTransition(*transition); return nullopt; } - if (name == "circle-stroke-opacity-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + + if (property == Property::CirclePitchScaleTransition) { + setCirclePitchScaleTransition(*transition); + return nullopt; + } + + if (property == Property::CirclePitchAlignmentTransition) { + setCirclePitchAlignmentTransition(*transition); + return nullopt; + } + + if (property == Property::CircleStrokeWidthTransition) { + setCircleStrokeWidthTransition(*transition); + return nullopt; + } + + if (property == Property::CircleStrokeColorTransition) { + setCircleStrokeColorTransition(*transition); + return nullopt; + } + + if (property == Property::CircleStrokeOpacityTransition) { setCircleStrokeOpacityTransition(*transition); return nullopt; } + return Error { "layer doesn't support this property" }; } @@ -654,7 +733,21 @@ optional CircleLayer::setLayoutProperty(const std::string& name, const Co return nullopt; } + enum class Property { + Unknown, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + return Error { "layer doesn't support this property" }; } diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index b48e51c566..33f5bbe87c 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -294,154 +295,226 @@ TransitionOptions FillExtrusionLayer::getFillExtrusionBaseTransition() const { using namespace conversion; optional FillExtrusionLayer::setPaintProperty(const std::string& name, const Convertible& value) { + enum class Property { + Unknown, + FillExtrusionOpacity, + FillExtrusionColor, + FillExtrusionTranslate, + FillExtrusionTranslateAnchor, + FillExtrusionPattern, + FillExtrusionHeight, + FillExtrusionBase, + FillExtrusionOpacityTransition, + FillExtrusionColorTransition, + FillExtrusionTranslateTransition, + FillExtrusionTranslateAnchorTransition, + FillExtrusionPatternTransition, + FillExtrusionHeightTransition, + FillExtrusionBaseTransition, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + case util::hashFNV1a("fill-extrusion-opacity"): + if (name == "fill-extrusion-opacity") { + property = Property::FillExtrusionOpacity; + } + break; + case util::hashFNV1a("fill-extrusion-opacity-transition"): + if (name == "fill-extrusion-opacity-transition") { + property = Property::FillExtrusionOpacityTransition; + } + break; + case util::hashFNV1a("fill-extrusion-color"): + if (name == "fill-extrusion-color") { + property = Property::FillExtrusionColor; + } + break; + case util::hashFNV1a("fill-extrusion-color-transition"): + if (name == "fill-extrusion-color-transition") { + property = Property::FillExtrusionColorTransition; + } + break; + case util::hashFNV1a("fill-extrusion-translate"): + if (name == "fill-extrusion-translate") { + property = Property::FillExtrusionTranslate; + } + break; + case util::hashFNV1a("fill-extrusion-translate-transition"): + if (name == "fill-extrusion-translate-transition") { + property = Property::FillExtrusionTranslateTransition; + } + break; + case util::hashFNV1a("fill-extrusion-translate-anchor"): + if (name == "fill-extrusion-translate-anchor") { + property = Property::FillExtrusionTranslateAnchor; + } + break; + case util::hashFNV1a("fill-extrusion-translate-anchor-transition"): + if (name == "fill-extrusion-translate-anchor-transition") { + property = Property::FillExtrusionTranslateAnchorTransition; + } + break; + case util::hashFNV1a("fill-extrusion-pattern"): + if (name == "fill-extrusion-pattern") { + property = Property::FillExtrusionPattern; + } + break; + case util::hashFNV1a("fill-extrusion-pattern-transition"): + if (name == "fill-extrusion-pattern-transition") { + property = Property::FillExtrusionPatternTransition; + } + break; + case util::hashFNV1a("fill-extrusion-height"): + if (name == "fill-extrusion-height") { + property = Property::FillExtrusionHeight; + } + break; + case util::hashFNV1a("fill-extrusion-height-transition"): + if (name == "fill-extrusion-height-transition") { + property = Property::FillExtrusionHeightTransition; + } + break; + case util::hashFNV1a("fill-extrusion-base"): + if (name == "fill-extrusion-base") { + property = Property::FillExtrusionBase; + } + break; + case util::hashFNV1a("fill-extrusion-base-transition"): + if (name == "fill-extrusion-base-transition") { + property = Property::FillExtrusionBaseTransition; + } + break; - if (name == "fill-extrusion-opacity") { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + if (property == Property::FillExtrusionOpacity) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setFillExtrusionOpacity(*typedValue); return nullopt; - } - if (name == "fill-extrusion-opacity-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setFillExtrusionOpacityTransition(*transition); - return nullopt; + } - if (name == "fill-extrusion-color") { + if (property == Property::FillExtrusionColor) { Error error; optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - + setFillExtrusionColor(*typedValue); return nullopt; - } - if (name == "fill-extrusion-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setFillExtrusionColorTransition(*transition); - return nullopt; + } - if (name == "fill-extrusion-translate") { + if (property == Property::FillExtrusionTranslate) { Error error; optional>> typedValue = convert>>(value, error, false, false); if (!typedValue) { return error; } - + setFillExtrusionTranslate(*typedValue); return nullopt; - } - if (name == "fill-extrusion-translate-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setFillExtrusionTranslateTransition(*transition); - return nullopt; + } - if (name == "fill-extrusion-translate-anchor") { + if (property == Property::FillExtrusionTranslateAnchor) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setFillExtrusionTranslateAnchor(*typedValue); return nullopt; - } - if (name == "fill-extrusion-translate-anchor-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setFillExtrusionTranslateAnchorTransition(*transition); - return nullopt; + } - if (name == "fill-extrusion-pattern") { + if (property == Property::FillExtrusionPattern) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setFillExtrusionPattern(*typedValue); return nullopt; - } - if (name == "fill-extrusion-pattern-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setFillExtrusionPatternTransition(*transition); - return nullopt; + } - if (name == "fill-extrusion-height") { + if (property == Property::FillExtrusionHeight || property == Property::FillExtrusionBase) { Error error; optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } + + if (property == Property::FillExtrusionHeight) { + setFillExtrusionHeight(*typedValue); + return nullopt; + } + + if (property == Property::FillExtrusionBase) { + setFillExtrusionBase(*typedValue); + return nullopt; + } + + } + - setFillExtrusionHeight(*typedValue); + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + if (property == Property::FillExtrusionOpacityTransition) { + setFillExtrusionOpacityTransition(*transition); return nullopt; } - if (name == "fill-extrusion-height-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setFillExtrusionHeightTransition(*transition); + + if (property == Property::FillExtrusionColorTransition) { + setFillExtrusionColorTransition(*transition); return nullopt; } - if (name == "fill-extrusion-base") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setFillExtrusionBase(*typedValue); + if (property == Property::FillExtrusionTranslateTransition) { + setFillExtrusionTranslateTransition(*transition); return nullopt; } - if (name == "fill-extrusion-base-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + + if (property == Property::FillExtrusionTranslateAnchorTransition) { + setFillExtrusionTranslateAnchorTransition(*transition); + return nullopt; + } + + if (property == Property::FillExtrusionPatternTransition) { + setFillExtrusionPatternTransition(*transition); + return nullopt; + } + + if (property == Property::FillExtrusionHeightTransition) { + setFillExtrusionHeightTransition(*transition); + return nullopt; + } + + if (property == Property::FillExtrusionBaseTransition) { setFillExtrusionBaseTransition(*transition); return nullopt; } + return Error { "layer doesn't support this property" }; } @@ -462,7 +535,21 @@ optional FillExtrusionLayer::setLayoutProperty(const std::string& name, c return nullopt; } + enum class Property { + Unknown, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + return Error { "layer doesn't support this property" }; } diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index 04c3bcef3f..c2756dc90e 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -294,154 +295,226 @@ TransitionOptions FillLayer::getFillPatternTransition() const { using namespace conversion; optional FillLayer::setPaintProperty(const std::string& name, const Convertible& value) { + enum class Property { + Unknown, + FillAntialias, + FillOpacity, + FillColor, + FillOutlineColor, + FillTranslate, + FillTranslateAnchor, + FillPattern, + FillAntialiasTransition, + FillOpacityTransition, + FillColorTransition, + FillOutlineColorTransition, + FillTranslateTransition, + FillTranslateAnchorTransition, + FillPatternTransition, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + case util::hashFNV1a("fill-antialias"): + if (name == "fill-antialias") { + property = Property::FillAntialias; + } + break; + case util::hashFNV1a("fill-antialias-transition"): + if (name == "fill-antialias-transition") { + property = Property::FillAntialiasTransition; + } + break; + case util::hashFNV1a("fill-opacity"): + if (name == "fill-opacity") { + property = Property::FillOpacity; + } + break; + case util::hashFNV1a("fill-opacity-transition"): + if (name == "fill-opacity-transition") { + property = Property::FillOpacityTransition; + } + break; + case util::hashFNV1a("fill-color"): + if (name == "fill-color") { + property = Property::FillColor; + } + break; + case util::hashFNV1a("fill-color-transition"): + if (name == "fill-color-transition") { + property = Property::FillColorTransition; + } + break; + case util::hashFNV1a("fill-outline-color"): + if (name == "fill-outline-color") { + property = Property::FillOutlineColor; + } + break; + case util::hashFNV1a("fill-outline-color-transition"): + if (name == "fill-outline-color-transition") { + property = Property::FillOutlineColorTransition; + } + break; + case util::hashFNV1a("fill-translate"): + if (name == "fill-translate") { + property = Property::FillTranslate; + } + break; + case util::hashFNV1a("fill-translate-transition"): + if (name == "fill-translate-transition") { + property = Property::FillTranslateTransition; + } + break; + case util::hashFNV1a("fill-translate-anchor"): + if (name == "fill-translate-anchor") { + property = Property::FillTranslateAnchor; + } + break; + case util::hashFNV1a("fill-translate-anchor-transition"): + if (name == "fill-translate-anchor-transition") { + property = Property::FillTranslateAnchorTransition; + } + break; + case util::hashFNV1a("fill-pattern"): + if (name == "fill-pattern") { + property = Property::FillPattern; + } + break; + case util::hashFNV1a("fill-pattern-transition"): + if (name == "fill-pattern-transition") { + property = Property::FillPatternTransition; + } + break; - if (name == "fill-antialias") { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + if (property == Property::FillAntialias) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setFillAntialias(*typedValue); return nullopt; - } - if (name == "fill-antialias-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setFillAntialiasTransition(*transition); - return nullopt; + } - if (name == "fill-opacity") { + if (property == Property::FillOpacity) { Error error; optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - + setFillOpacity(*typedValue); return nullopt; + } - if (name == "fill-opacity-transition") { + + if (property == Property::FillColor || property == Property::FillOutlineColor) { Error error; - optional transition = convert(value, error); - if (!transition) { + optional> typedValue = convert>(value, error, true, false); + if (!typedValue) { return error; } - - setFillOpacityTransition(*transition); - return nullopt; + + if (property == Property::FillColor) { + setFillColor(*typedValue); + return nullopt; + } + + if (property == Property::FillOutlineColor) { + setFillOutlineColor(*typedValue); + return nullopt; + } + } - if (name == "fill-color") { + if (property == Property::FillTranslate) { Error error; - optional> typedValue = convert>(value, error, true, false); + optional>> typedValue = convert>>(value, error, false, false); if (!typedValue) { return error; } - - setFillColor(*typedValue); + + setFillTranslate(*typedValue); return nullopt; + } - if (name == "fill-color-transition") { + + if (property == Property::FillTranslateAnchor) { Error error; - optional transition = convert(value, error); - if (!transition) { + optional> typedValue = convert>(value, error, false, false); + if (!typedValue) { return error; } - - setFillColorTransition(*transition); + + setFillTranslateAnchor(*typedValue); return nullopt; + } - if (name == "fill-outline-color") { + if (property == Property::FillPattern) { Error error; - optional> typedValue = convert>(value, error, true, false); + optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setFillOutlineColor(*typedValue); + + setFillPattern(*typedValue); return nullopt; + } - if (name == "fill-outline-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } + - setFillOutlineColorTransition(*transition); + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + if (property == Property::FillAntialiasTransition) { + setFillAntialiasTransition(*transition); return nullopt; } - if (name == "fill-translate") { - Error error; - optional>> typedValue = convert>>(value, error, false, false); - if (!typedValue) { - return error; - } - - setFillTranslate(*typedValue); + if (property == Property::FillOpacityTransition) { + setFillOpacityTransition(*transition); return nullopt; } - if (name == "fill-translate-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setFillTranslateTransition(*transition); + + if (property == Property::FillColorTransition) { + setFillColorTransition(*transition); return nullopt; } - if (name == "fill-translate-anchor") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setFillTranslateAnchor(*typedValue); + if (property == Property::FillOutlineColorTransition) { + setFillOutlineColorTransition(*transition); return nullopt; } - if (name == "fill-translate-anchor-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setFillTranslateAnchorTransition(*transition); + + if (property == Property::FillTranslateTransition) { + setFillTranslateTransition(*transition); return nullopt; } - if (name == "fill-pattern") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setFillPattern(*typedValue); + if (property == Property::FillTranslateAnchorTransition) { + setFillTranslateAnchorTransition(*transition); return nullopt; } - if (name == "fill-pattern-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + + if (property == Property::FillPatternTransition) { setFillPatternTransition(*transition); return nullopt; } + return Error { "layer doesn't support this property" }; } @@ -462,7 +535,21 @@ optional FillLayer::setLayoutProperty(const std::string& name, const Conv return nullopt; } + enum class Property { + Unknown, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + return Error { "layer doesn't support this property" }; } diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index 443b94c2ce..69499e7d4a 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -242,112 +243,163 @@ TransitionOptions HeatmapLayer::getHeatmapOpacityTransition() const { using namespace conversion; optional HeatmapLayer::setPaintProperty(const std::string& name, const Convertible& value) { - - if (name == "heatmap-radius") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; + enum class Property { + Unknown, + HeatmapRadius, + HeatmapWeight, + HeatmapIntensity, + HeatmapColor, + HeatmapOpacity, + HeatmapRadiusTransition, + HeatmapWeightTransition, + HeatmapIntensityTransition, + HeatmapColorTransition, + HeatmapOpacityTransition, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + case util::hashFNV1a("heatmap-radius"): + if (name == "heatmap-radius") { + property = Property::HeatmapRadius; } - - setHeatmapRadius(*typedValue); - return nullopt; - } - if (name == "heatmap-radius-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + break; + case util::hashFNV1a("heatmap-radius-transition"): + if (name == "heatmap-radius-transition") { + property = Property::HeatmapRadiusTransition; + } + break; + case util::hashFNV1a("heatmap-weight"): + if (name == "heatmap-weight") { + property = Property::HeatmapWeight; } + break; + case util::hashFNV1a("heatmap-weight-transition"): + if (name == "heatmap-weight-transition") { + property = Property::HeatmapWeightTransition; + } + break; + case util::hashFNV1a("heatmap-intensity"): + if (name == "heatmap-intensity") { + property = Property::HeatmapIntensity; + } + break; + case util::hashFNV1a("heatmap-intensity-transition"): + if (name == "heatmap-intensity-transition") { + property = Property::HeatmapIntensityTransition; + } + break; + case util::hashFNV1a("heatmap-color"): + if (name == "heatmap-color") { + property = Property::HeatmapColor; + } + break; + case util::hashFNV1a("heatmap-color-transition"): + if (name == "heatmap-color-transition") { + property = Property::HeatmapColorTransition; + } + break; + case util::hashFNV1a("heatmap-opacity"): + if (name == "heatmap-opacity") { + property = Property::HeatmapOpacity; + } + break; + case util::hashFNV1a("heatmap-opacity-transition"): + if (name == "heatmap-opacity-transition") { + property = Property::HeatmapOpacityTransition; + } + break; + + } - setHeatmapRadiusTransition(*transition); - return nullopt; + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; } - - if (name == "heatmap-weight") { + + + if (property == Property::HeatmapRadius || property == Property::HeatmapWeight) { Error error; optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - - setHeatmapWeight(*typedValue); - return nullopt; - } - if (name == "heatmap-weight-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::HeatmapRadius) { + setHeatmapRadius(*typedValue); + return nullopt; } - - setHeatmapWeightTransition(*transition); - return nullopt; + + if (property == Property::HeatmapWeight) { + setHeatmapWeight(*typedValue); + return nullopt; + } + } - if (name == "heatmap-intensity") { + if (property == Property::HeatmapIntensity || property == Property::HeatmapOpacity) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setHeatmapIntensity(*typedValue); - return nullopt; - } - if (name == "heatmap-intensity-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::HeatmapIntensity) { + setHeatmapIntensity(*typedValue); + return nullopt; } - - setHeatmapIntensityTransition(*transition); - return nullopt; + + if (property == Property::HeatmapOpacity) { + setHeatmapOpacity(*typedValue); + return nullopt; + } + } - if (name == "heatmap-color") { + if (property == Property::HeatmapColor) { Error error; optional typedValue = convert(value, error, false, false); if (!typedValue) { return error; } - + setHeatmapColor(*typedValue); return nullopt; + } - if (name == "heatmap-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } + - setHeatmapColorTransition(*transition); + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + if (property == Property::HeatmapRadiusTransition) { + setHeatmapRadiusTransition(*transition); return nullopt; } - if (name == "heatmap-opacity") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setHeatmapOpacity(*typedValue); + if (property == Property::HeatmapWeightTransition) { + setHeatmapWeightTransition(*transition); return nullopt; } - if (name == "heatmap-opacity-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + + if (property == Property::HeatmapIntensityTransition) { + setHeatmapIntensityTransition(*transition); + return nullopt; + } + + if (property == Property::HeatmapColorTransition) { + setHeatmapColorTransition(*transition); + return nullopt; + } + + if (property == Property::HeatmapOpacityTransition) { setHeatmapOpacityTransition(*transition); return nullopt; } + return Error { "layer doesn't support this property" }; } @@ -368,7 +420,21 @@ optional HeatmapLayer::setLayoutProperty(const std::string& name, const C return nullopt; } + enum class Property { + Unknown, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + return Error { "layer doesn't support this property" }; } diff --git a/src/mbgl/style/layers/heatmap_layer_properties.hpp b/src/mbgl/style/layers/heatmap_layer_properties.hpp index fe7257a78a..4d49a52c72 100644 --- a/src/mbgl/style/layers/heatmap_layer_properties.hpp +++ b/src/mbgl/style/layers/heatmap_layer_properties.hpp @@ -24,7 +24,8 @@ struct HeatmapIntensity : PaintProperty { static float defaultValue() { return 1; } }; -using HeatmapColor = ColorRampProperty; +struct HeatmapColor : ColorRampProperty { +}; struct HeatmapOpacity : PaintProperty { static float defaultValue() { return 1; } diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp index 2d8c837baa..9ccdd1567b 100644 --- a/src/mbgl/style/layers/hillshade_layer.cpp +++ b/src/mbgl/style/layers/hillshade_layer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -245,133 +246,185 @@ TransitionOptions HillshadeLayer::getHillshadeAccentColorTransition() const { using namespace conversion; optional HillshadeLayer::setPaintProperty(const std::string& name, const Convertible& value) { + enum class Property { + Unknown, + HillshadeIlluminationDirection, + HillshadeIlluminationAnchor, + HillshadeExaggeration, + HillshadeShadowColor, + HillshadeHighlightColor, + HillshadeAccentColor, + HillshadeIlluminationDirectionTransition, + HillshadeIlluminationAnchorTransition, + HillshadeExaggerationTransition, + HillshadeShadowColorTransition, + HillshadeHighlightColorTransition, + HillshadeAccentColorTransition, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + case util::hashFNV1a("hillshade-illumination-direction"): + if (name == "hillshade-illumination-direction") { + property = Property::HillshadeIlluminationDirection; + } + break; + case util::hashFNV1a("hillshade-illumination-direction-transition"): + if (name == "hillshade-illumination-direction-transition") { + property = Property::HillshadeIlluminationDirectionTransition; + } + break; + case util::hashFNV1a("hillshade-illumination-anchor"): + if (name == "hillshade-illumination-anchor") { + property = Property::HillshadeIlluminationAnchor; + } + break; + case util::hashFNV1a("hillshade-illumination-anchor-transition"): + if (name == "hillshade-illumination-anchor-transition") { + property = Property::HillshadeIlluminationAnchorTransition; + } + break; + case util::hashFNV1a("hillshade-exaggeration"): + if (name == "hillshade-exaggeration") { + property = Property::HillshadeExaggeration; + } + break; + case util::hashFNV1a("hillshade-exaggeration-transition"): + if (name == "hillshade-exaggeration-transition") { + property = Property::HillshadeExaggerationTransition; + } + break; + case util::hashFNV1a("hillshade-shadow-color"): + if (name == "hillshade-shadow-color") { + property = Property::HillshadeShadowColor; + } + break; + case util::hashFNV1a("hillshade-shadow-color-transition"): + if (name == "hillshade-shadow-color-transition") { + property = Property::HillshadeShadowColorTransition; + } + break; + case util::hashFNV1a("hillshade-highlight-color"): + if (name == "hillshade-highlight-color") { + property = Property::HillshadeHighlightColor; + } + break; + case util::hashFNV1a("hillshade-highlight-color-transition"): + if (name == "hillshade-highlight-color-transition") { + property = Property::HillshadeHighlightColorTransition; + } + break; + case util::hashFNV1a("hillshade-accent-color"): + if (name == "hillshade-accent-color") { + property = Property::HillshadeAccentColor; + } + break; + case util::hashFNV1a("hillshade-accent-color-transition"): + if (name == "hillshade-accent-color-transition") { + property = Property::HillshadeAccentColorTransition; + } + break; - if (name == "hillshade-illumination-direction") { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + if (property == Property::HillshadeIlluminationDirection || property == Property::HillshadeExaggeration) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setHillshadeIlluminationDirection(*typedValue); - return nullopt; - } - if (name == "hillshade-illumination-direction-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::HillshadeIlluminationDirection) { + setHillshadeIlluminationDirection(*typedValue); + return nullopt; } - - setHillshadeIlluminationDirectionTransition(*transition); - return nullopt; + + if (property == Property::HillshadeExaggeration) { + setHillshadeExaggeration(*typedValue); + return nullopt; + } + } - if (name == "hillshade-illumination-anchor") { + if (property == Property::HillshadeIlluminationAnchor) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setHillshadeIlluminationAnchor(*typedValue); return nullopt; - } - if (name == "hillshade-illumination-anchor-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setHillshadeIlluminationAnchorTransition(*transition); - return nullopt; + } - if (name == "hillshade-exaggeration") { + if (property == Property::HillshadeShadowColor || property == Property::HillshadeHighlightColor || property == Property::HillshadeAccentColor) { Error error; - optional> typedValue = convert>(value, error, false, false); + optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setHillshadeExaggeration(*typedValue); - return nullopt; - } - if (name == "hillshade-exaggeration-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::HillshadeShadowColor) { + setHillshadeShadowColor(*typedValue); + return nullopt; } - - setHillshadeExaggerationTransition(*transition); - return nullopt; + + if (property == Property::HillshadeHighlightColor) { + setHillshadeHighlightColor(*typedValue); + return nullopt; + } + + if (property == Property::HillshadeAccentColor) { + setHillshadeAccentColor(*typedValue); + return nullopt; + } + } - if (name == "hillshade-shadow-color") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - setHillshadeShadowColor(*typedValue); + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + + if (property == Property::HillshadeIlluminationDirectionTransition) { + setHillshadeIlluminationDirectionTransition(*transition); return nullopt; } - if (name == "hillshade-shadow-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setHillshadeShadowColorTransition(*transition); + + if (property == Property::HillshadeIlluminationAnchorTransition) { + setHillshadeIlluminationAnchorTransition(*transition); return nullopt; } - if (name == "hillshade-highlight-color") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setHillshadeHighlightColor(*typedValue); + if (property == Property::HillshadeExaggerationTransition) { + setHillshadeExaggerationTransition(*transition); return nullopt; } - if (name == "hillshade-highlight-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setHillshadeHighlightColorTransition(*transition); + + if (property == Property::HillshadeShadowColorTransition) { + setHillshadeShadowColorTransition(*transition); return nullopt; } - if (name == "hillshade-accent-color") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setHillshadeAccentColor(*typedValue); + if (property == Property::HillshadeHighlightColorTransition) { + setHillshadeHighlightColorTransition(*transition); return nullopt; } - if (name == "hillshade-accent-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + + if (property == Property::HillshadeAccentColorTransition) { setHillshadeAccentColorTransition(*transition); return nullopt; } + return Error { "layer doesn't support this property" }; } @@ -392,7 +445,21 @@ optional HillshadeLayer::setLayoutProperty(const std::string& name, const return nullopt; } + enum class Property { + Unknown, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + return Error { "layer doesn't support this property" }; } diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index 7555054bdb..8a6db749cf 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -14,6 +14,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -178,28 +179,78 @@ TransitionOptions <%- camelize(type) %>Layer::get<%- camelize(property.name) %>T using namespace conversion; optional <%- camelize(type) %>Layer::setPaintProperty(const std::string& name, const Convertible& value) { - <% for (const property of paintProperties) { %> - if (name == "<%- property.name %>") { - Error error; - optional<<%- propertyValueType(property) %>> typedValue = convert<<%- propertyValueType(property) %>>(value, error, <%- property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven' %>, <%- property.name === 'icon-image' || property.name === 'text-field' %>); - if (!typedValue) { - return error; + enum class Property { + Unknown, +<% for (const property of paintProperties) { -%> + <%- camelize(property.name) %>, +<% } -%> +<% for (const property of paintProperties) { -%> + <%- camelize(property.name) %>Transition, +<% } -%> + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + <% for (const property of paintProperties) { -%> +case util::hashFNV1a("<%- property.name %>"): + if (name == "<%- property.name %>") { + property = Property::<%- camelize(property.name) %>; } + break; + case util::hashFNV1a("<%- property.name %>-transition"): + if (name == "<%- property.name %>-transition") { + property = Property::<%- camelize(property.name) %>Transition; + } + break; + <% } %> + } - set<%- camelize(property.name) %>(*typedValue); - return nullopt; + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; } - if (name == "<%- property.name %>-transition") { + + <% + const paintConversions = {}; + for (const property of paintProperties) { + const dataDriven = property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven'; + const convertTokens = property.name === 'icon-image' || property.name === 'text-field'; + const conversion = `optional<${propertyValueType(property)}> typedValue = convert<${propertyValueType(property)}>(value, error, ${dataDriven}, ${convertTokens})`; + paintConversions[conversion] = paintConversions[conversion] || []; + paintConversions[conversion].push(property); + } + -%> + <% for (const key in paintConversions) { + const properties = paintConversions[key]; + %> + if (<%- properties.map(p => `property == Property::${camelize(p.name)}`).join(' || ') %>) { Error error; - optional transition = convert(value, error); - if (!transition) { + <%- key %>; + if (!typedValue) { return error; } + <% if (properties.length == 1) { %> + set<%- camelize(properties[0].name) %>(*typedValue); + return nullopt; + <% } else for (const property of properties) { %> + if (property == Property::<%- camelize(property.name) %>) { + set<%- camelize(property.name) %>(*typedValue); + return nullopt; + } + <% } %> + } + <% } %> + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; + } + <% for (const property of paintProperties) { %> + if (property == Property::<%- camelize(property.name) %>Transition) { set<%- camelize(property.name) %>Transition(*transition); return nullopt; } - <% } -%> + <% } %> return Error { "layer doesn't support this property" }; } @@ -221,18 +272,58 @@ optional <%- camelize(type) %>Layer::setLayoutProperty(const std::string& return nullopt; } + enum class Property { + Unknown, +<% for (const property of layoutProperties) { -%> + <%- camelize(property.name) %>, +<% } -%> + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { <% for (const property of layoutProperties) { %> - if (name == "<%- property.name %>") { + case util::hashFNV1a("<%- property.name %>"): + if (name == "<%- property.name %>") { + property = Property::<%- camelize(property.name) %>; + } + break; + <% } %> + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + <% + const layoutConversions = {}; + for (const property of layoutProperties) { + const dataDriven = property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven'; + const convertTokens = property.name === 'icon-image' || property.name === 'text-field'; + const conversion = `optional<${propertyValueType(property)}> typedValue = convert<${propertyValueType(property)}>(value, error, ${dataDriven}, ${convertTokens})`; + layoutConversions[conversion] = layoutConversions[conversion] || []; + layoutConversions[conversion].push(property); + } + -%> + <% for (const key in layoutConversions) { + const properties = layoutConversions[key]; + %> + if (<%- properties.map(p => `property == Property::${camelize(p.name)}`).join(' || ') %>) { Error error; - optional<<%- propertyValueType(property) %>> typedValue = convert<<%- propertyValueType(property) %>>(value, error, <%- property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven' %>, <%- property.name === 'icon-image' || property.name === 'text-field' %>); + <%- key %>; if (!typedValue) { return error; } - - set<%- camelize(property.name) %>(*typedValue); + <% if (properties.length == 1) { %> + set<%- camelize(properties[0].name) %>(*typedValue); return nullopt; + <% } else for (const property of properties) { %> + if (property == Property::<%- camelize(property.name) %>) { + set<%- camelize(property.name) %>(*typedValue); + return nullopt; + } + <% } %> } - <% } -%> + <% } %> return Error { "layer doesn't support this property" }; } diff --git a/src/mbgl/style/layers/layer_properties.hpp.ejs b/src/mbgl/style/layers/layer_properties.hpp.ejs index 5b774933a6..694d9a62b7 100644 --- a/src/mbgl/style/layers/layer_properties.hpp.ejs +++ b/src/mbgl/style/layers/layer_properties.hpp.ejs @@ -26,7 +26,8 @@ struct <%- camelize(property.name) %> : <%- layoutPropertyType(property, type) % <% } -%> <% for (const property of paintProperties) { -%> <% if (property['property-type'] === 'color-ramp') { -%> -using <%- camelize(property.name) %> = ColorRampProperty; +struct <%- camelize(property.name) %> : ColorRampProperty { +}; <% } else { -%> struct <%- camelize(property.name) %> : <%- paintPropertyType(property, type) %> { static <%- evaluatedType(property) %> defaultValue() { return <%- defaultValue(property) %>; } diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index c3203f84e4..cc6bfdde37 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -440,217 +441,292 @@ TransitionOptions LineLayer::getLinePatternTransition() const { using namespace conversion; optional LineLayer::setPaintProperty(const std::string& name, const Convertible& value) { + enum class Property { + Unknown, + LineOpacity, + LineColor, + LineTranslate, + LineTranslateAnchor, + LineWidth, + LineGapWidth, + LineOffset, + LineBlur, + LineDasharray, + LinePattern, + LineOpacityTransition, + LineColorTransition, + LineTranslateTransition, + LineTranslateAnchorTransition, + LineWidthTransition, + LineGapWidthTransition, + LineOffsetTransition, + LineBlurTransition, + LineDasharrayTransition, + LinePatternTransition, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + case util::hashFNV1a("line-opacity"): + if (name == "line-opacity") { + property = Property::LineOpacity; + } + break; + case util::hashFNV1a("line-opacity-transition"): + if (name == "line-opacity-transition") { + property = Property::LineOpacityTransition; + } + break; + case util::hashFNV1a("line-color"): + if (name == "line-color") { + property = Property::LineColor; + } + break; + case util::hashFNV1a("line-color-transition"): + if (name == "line-color-transition") { + property = Property::LineColorTransition; + } + break; + case util::hashFNV1a("line-translate"): + if (name == "line-translate") { + property = Property::LineTranslate; + } + break; + case util::hashFNV1a("line-translate-transition"): + if (name == "line-translate-transition") { + property = Property::LineTranslateTransition; + } + break; + case util::hashFNV1a("line-translate-anchor"): + if (name == "line-translate-anchor") { + property = Property::LineTranslateAnchor; + } + break; + case util::hashFNV1a("line-translate-anchor-transition"): + if (name == "line-translate-anchor-transition") { + property = Property::LineTranslateAnchorTransition; + } + break; + case util::hashFNV1a("line-width"): + if (name == "line-width") { + property = Property::LineWidth; + } + break; + case util::hashFNV1a("line-width-transition"): + if (name == "line-width-transition") { + property = Property::LineWidthTransition; + } + break; + case util::hashFNV1a("line-gap-width"): + if (name == "line-gap-width") { + property = Property::LineGapWidth; + } + break; + case util::hashFNV1a("line-gap-width-transition"): + if (name == "line-gap-width-transition") { + property = Property::LineGapWidthTransition; + } + break; + case util::hashFNV1a("line-offset"): + if (name == "line-offset") { + property = Property::LineOffset; + } + break; + case util::hashFNV1a("line-offset-transition"): + if (name == "line-offset-transition") { + property = Property::LineOffsetTransition; + } + break; + case util::hashFNV1a("line-blur"): + if (name == "line-blur") { + property = Property::LineBlur; + } + break; + case util::hashFNV1a("line-blur-transition"): + if (name == "line-blur-transition") { + property = Property::LineBlurTransition; + } + break; + case util::hashFNV1a("line-dasharray"): + if (name == "line-dasharray") { + property = Property::LineDasharray; + } + break; + case util::hashFNV1a("line-dasharray-transition"): + if (name == "line-dasharray-transition") { + property = Property::LineDasharrayTransition; + } + break; + case util::hashFNV1a("line-pattern"): + if (name == "line-pattern") { + property = Property::LinePattern; + } + break; + case util::hashFNV1a("line-pattern-transition"): + if (name == "line-pattern-transition") { + property = Property::LinePatternTransition; + } + break; - if (name == "line-opacity") { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + if (property == Property::LineOpacity || property == Property::LineWidth || property == Property::LineGapWidth || property == Property::LineOffset || property == Property::LineBlur) { Error error; optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - - setLineOpacity(*typedValue); - return nullopt; - } - if (name == "line-opacity-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::LineOpacity) { + setLineOpacity(*typedValue); + return nullopt; } - - setLineOpacityTransition(*transition); - return nullopt; + + if (property == Property::LineWidth) { + setLineWidth(*typedValue); + return nullopt; + } + + if (property == Property::LineGapWidth) { + setLineGapWidth(*typedValue); + return nullopt; + } + + if (property == Property::LineOffset) { + setLineOffset(*typedValue); + return nullopt; + } + + if (property == Property::LineBlur) { + setLineBlur(*typedValue); + return nullopt; + } + } - if (name == "line-color") { + if (property == Property::LineColor) { Error error; optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - + setLineColor(*typedValue); return nullopt; - } - if (name == "line-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setLineColorTransition(*transition); - return nullopt; + } - if (name == "line-translate") { + if (property == Property::LineTranslate) { Error error; optional>> typedValue = convert>>(value, error, false, false); if (!typedValue) { return error; } - + setLineTranslate(*typedValue); return nullopt; - } - if (name == "line-translate-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setLineTranslateTransition(*transition); - return nullopt; + } - if (name == "line-translate-anchor") { + if (property == Property::LineTranslateAnchor) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setLineTranslateAnchor(*typedValue); return nullopt; + } - if (name == "line-translate-anchor-transition") { + + if (property == Property::LineDasharray) { Error error; - optional transition = convert(value, error); - if (!transition) { + optional>> typedValue = convert>>(value, error, false, false); + if (!typedValue) { return error; } - - setLineTranslateAnchorTransition(*transition); + + setLineDasharray(*typedValue); return nullopt; + } - if (name == "line-width") { + if (property == Property::LinePattern) { Error error; - optional> typedValue = convert>(value, error, true, false); + optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setLineWidth(*typedValue); + + setLinePattern(*typedValue); return nullopt; + } - if (name == "line-width-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } + - setLineWidthTransition(*transition); - return nullopt; + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; } - if (name == "line-gap-width") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setLineGapWidth(*typedValue); + if (property == Property::LineOpacityTransition) { + setLineOpacityTransition(*transition); return nullopt; } - if (name == "line-gap-width-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setLineGapWidthTransition(*transition); + + if (property == Property::LineColorTransition) { + setLineColorTransition(*transition); return nullopt; } - if (name == "line-offset") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setLineOffset(*typedValue); + if (property == Property::LineTranslateTransition) { + setLineTranslateTransition(*transition); return nullopt; } - if (name == "line-offset-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setLineOffsetTransition(*transition); + + if (property == Property::LineTranslateAnchorTransition) { + setLineTranslateAnchorTransition(*transition); return nullopt; } - if (name == "line-blur") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setLineBlur(*typedValue); + if (property == Property::LineWidthTransition) { + setLineWidthTransition(*transition); return nullopt; } - if (name == "line-blur-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setLineBlurTransition(*transition); + + if (property == Property::LineGapWidthTransition) { + setLineGapWidthTransition(*transition); return nullopt; } - if (name == "line-dasharray") { - Error error; - optional>> typedValue = convert>>(value, error, false, false); - if (!typedValue) { - return error; - } - - setLineDasharray(*typedValue); + if (property == Property::LineOffsetTransition) { + setLineOffsetTransition(*transition); return nullopt; } - if (name == "line-dasharray-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setLineDasharrayTransition(*transition); + + if (property == Property::LineBlurTransition) { + setLineBlurTransition(*transition); return nullopt; } - if (name == "line-pattern") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setLinePattern(*typedValue); + if (property == Property::LineDasharrayTransition) { + setLineDasharrayTransition(*transition); return nullopt; } - if (name == "line-pattern-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + + if (property == Property::LinePatternTransition) { setLinePatternTransition(*transition); return nullopt; } + return Error { "layer doesn't support this property" }; } @@ -671,51 +747,92 @@ optional LineLayer::setLayoutProperty(const std::string& name, const Conv return nullopt; } + enum class Property { + Unknown, + LineCap, + LineJoin, + LineMiterLimit, + LineRoundLimit, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + + case util::hashFNV1a("line-cap"): + if (name == "line-cap") { + property = Property::LineCap; + } + break; - if (name == "line-cap") { + case util::hashFNV1a("line-join"): + if (name == "line-join") { + property = Property::LineJoin; + } + break; + + case util::hashFNV1a("line-miter-limit"): + if (name == "line-miter-limit") { + property = Property::LineMiterLimit; + } + break; + + case util::hashFNV1a("line-round-limit"): + if (name == "line-round-limit") { + property = Property::LineRoundLimit; + } + break; + + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + if (property == Property::LineCap) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - + setLineCap(*typedValue); return nullopt; + } - if (name == "line-join") { + if (property == Property::LineJoin) { Error error; optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - + setLineJoin(*typedValue); return nullopt; + } - if (name == "line-miter-limit") { + if (property == Property::LineMiterLimit || property == Property::LineRoundLimit) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setLineMiterLimit(*typedValue); - return nullopt; - } - - if (name == "line-round-limit") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + + if (property == Property::LineMiterLimit) { + setLineMiterLimit(*typedValue); + return nullopt; } - - setLineRoundLimit(*typedValue); - return nullopt; + + if (property == Property::LineRoundLimit) { + setLineRoundLimit(*typedValue); + return nullopt; + } + } + return Error { "layer doesn't support this property" }; } diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index 0eba8ef886..da3f7f8a18 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -299,175 +300,220 @@ TransitionOptions RasterLayer::getRasterFadeDurationTransition() const { using namespace conversion; optional RasterLayer::setPaintProperty(const std::string& name, const Convertible& value) { - - if (name == "raster-opacity") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + enum class Property { + Unknown, + RasterOpacity, + RasterHueRotate, + RasterBrightnessMin, + RasterBrightnessMax, + RasterSaturation, + RasterContrast, + RasterResampling, + RasterFadeDuration, + RasterOpacityTransition, + RasterHueRotateTransition, + RasterBrightnessMinTransition, + RasterBrightnessMaxTransition, + RasterSaturationTransition, + RasterContrastTransition, + RasterResamplingTransition, + RasterFadeDurationTransition, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + case util::hashFNV1a("raster-opacity"): + if (name == "raster-opacity") { + property = Property::RasterOpacity; } - - setRasterOpacity(*typedValue); - return nullopt; - } - if (name == "raster-opacity-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + break; + case util::hashFNV1a("raster-opacity-transition"): + if (name == "raster-opacity-transition") { + property = Property::RasterOpacityTransition; + } + break; + case util::hashFNV1a("raster-hue-rotate"): + if (name == "raster-hue-rotate") { + property = Property::RasterHueRotate; + } + break; + case util::hashFNV1a("raster-hue-rotate-transition"): + if (name == "raster-hue-rotate-transition") { + property = Property::RasterHueRotateTransition; + } + break; + case util::hashFNV1a("raster-brightness-min"): + if (name == "raster-brightness-min") { + property = Property::RasterBrightnessMin; + } + break; + case util::hashFNV1a("raster-brightness-min-transition"): + if (name == "raster-brightness-min-transition") { + property = Property::RasterBrightnessMinTransition; + } + break; + case util::hashFNV1a("raster-brightness-max"): + if (name == "raster-brightness-max") { + property = Property::RasterBrightnessMax; + } + break; + case util::hashFNV1a("raster-brightness-max-transition"): + if (name == "raster-brightness-max-transition") { + property = Property::RasterBrightnessMaxTransition; + } + break; + case util::hashFNV1a("raster-saturation"): + if (name == "raster-saturation") { + property = Property::RasterSaturation; } + break; + case util::hashFNV1a("raster-saturation-transition"): + if (name == "raster-saturation-transition") { + property = Property::RasterSaturationTransition; + } + break; + case util::hashFNV1a("raster-contrast"): + if (name == "raster-contrast") { + property = Property::RasterContrast; + } + break; + case util::hashFNV1a("raster-contrast-transition"): + if (name == "raster-contrast-transition") { + property = Property::RasterContrastTransition; + } + break; + case util::hashFNV1a("raster-resampling"): + if (name == "raster-resampling") { + property = Property::RasterResampling; + } + break; + case util::hashFNV1a("raster-resampling-transition"): + if (name == "raster-resampling-transition") { + property = Property::RasterResamplingTransition; + } + break; + case util::hashFNV1a("raster-fade-duration"): + if (name == "raster-fade-duration") { + property = Property::RasterFadeDuration; + } + break; + case util::hashFNV1a("raster-fade-duration-transition"): + if (name == "raster-fade-duration-transition") { + property = Property::RasterFadeDurationTransition; + } + break; + + } - setRasterOpacityTransition(*transition); - return nullopt; + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; } - - if (name == "raster-hue-rotate") { + + + if (property == Property::RasterOpacity || property == Property::RasterHueRotate || property == Property::RasterBrightnessMin || property == Property::RasterBrightnessMax || property == Property::RasterSaturation || property == Property::RasterContrast || property == Property::RasterFadeDuration) { Error error; optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setRasterHueRotate(*typedValue); - return nullopt; - } - if (name == "raster-hue-rotate-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::RasterOpacity) { + setRasterOpacity(*typedValue); + return nullopt; } - - setRasterHueRotateTransition(*transition); - return nullopt; + + if (property == Property::RasterHueRotate) { + setRasterHueRotate(*typedValue); + return nullopt; + } + + if (property == Property::RasterBrightnessMin) { + setRasterBrightnessMin(*typedValue); + return nullopt; + } + + if (property == Property::RasterBrightnessMax) { + setRasterBrightnessMax(*typedValue); + return nullopt; + } + + if (property == Property::RasterSaturation) { + setRasterSaturation(*typedValue); + return nullopt; + } + + if (property == Property::RasterContrast) { + setRasterContrast(*typedValue); + return nullopt; + } + + if (property == Property::RasterFadeDuration) { + setRasterFadeDuration(*typedValue); + return nullopt; + } + } - if (name == "raster-brightness-min") { + if (property == Property::RasterResampling) { Error error; - optional> typedValue = convert>(value, error, false, false); + optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setRasterBrightnessMin(*typedValue); + + setRasterResampling(*typedValue); return nullopt; + } - if (name == "raster-brightness-min-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } + - setRasterBrightnessMinTransition(*transition); - return nullopt; + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; } - if (name == "raster-brightness-max") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setRasterBrightnessMax(*typedValue); + if (property == Property::RasterOpacityTransition) { + setRasterOpacityTransition(*transition); return nullopt; } - if (name == "raster-brightness-max-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setRasterBrightnessMaxTransition(*transition); + + if (property == Property::RasterHueRotateTransition) { + setRasterHueRotateTransition(*transition); return nullopt; } - if (name == "raster-saturation") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setRasterSaturation(*typedValue); + if (property == Property::RasterBrightnessMinTransition) { + setRasterBrightnessMinTransition(*transition); return nullopt; } - if (name == "raster-saturation-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setRasterSaturationTransition(*transition); + + if (property == Property::RasterBrightnessMaxTransition) { + setRasterBrightnessMaxTransition(*transition); return nullopt; } - if (name == "raster-contrast") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setRasterContrast(*typedValue); + if (property == Property::RasterSaturationTransition) { + setRasterSaturationTransition(*transition); return nullopt; } - if (name == "raster-contrast-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + + if (property == Property::RasterContrastTransition) { setRasterContrastTransition(*transition); return nullopt; } - if (name == "raster-resampling") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setRasterResampling(*typedValue); - return nullopt; - } - if (name == "raster-resampling-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + if (property == Property::RasterResamplingTransition) { setRasterResamplingTransition(*transition); return nullopt; } - if (name == "raster-fade-duration") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setRasterFadeDuration(*typedValue); - return nullopt; - } - if (name == "raster-fade-duration-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + if (property == Property::RasterFadeDurationTransition) { setRasterFadeDurationTransition(*transition); return nullopt; } + return Error { "layer doesn't support this property" }; } @@ -488,7 +534,21 @@ optional RasterLayer::setLayoutProperty(const std::string& name, const Co return nullopt; } + enum class Property { + Unknown, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + return Error { "layer doesn't support this property" }; } diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index bb5b317a38..e7cba19ea5 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -1060,301 +1061,372 @@ TransitionOptions SymbolLayer::getTextTranslateAnchorTransition() const { using namespace conversion; optional SymbolLayer::setPaintProperty(const std::string& name, const Convertible& value) { + enum class Property { + Unknown, + IconOpacity, + IconColor, + IconHaloColor, + IconHaloWidth, + IconHaloBlur, + IconTranslate, + IconTranslateAnchor, + TextOpacity, + TextColor, + TextHaloColor, + TextHaloWidth, + TextHaloBlur, + TextTranslate, + TextTranslateAnchor, + IconOpacityTransition, + IconColorTransition, + IconHaloColorTransition, + IconHaloWidthTransition, + IconHaloBlurTransition, + IconTranslateTransition, + IconTranslateAnchorTransition, + TextOpacityTransition, + TextColorTransition, + TextHaloColorTransition, + TextHaloWidthTransition, + TextHaloBlurTransition, + TextTranslateTransition, + TextTranslateAnchorTransition, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { + case util::hashFNV1a("icon-opacity"): + if (name == "icon-opacity") { + property = Property::IconOpacity; + } + break; + case util::hashFNV1a("icon-opacity-transition"): + if (name == "icon-opacity-transition") { + property = Property::IconOpacityTransition; + } + break; + case util::hashFNV1a("icon-color"): + if (name == "icon-color") { + property = Property::IconColor; + } + break; + case util::hashFNV1a("icon-color-transition"): + if (name == "icon-color-transition") { + property = Property::IconColorTransition; + } + break; + case util::hashFNV1a("icon-halo-color"): + if (name == "icon-halo-color") { + property = Property::IconHaloColor; + } + break; + case util::hashFNV1a("icon-halo-color-transition"): + if (name == "icon-halo-color-transition") { + property = Property::IconHaloColorTransition; + } + break; + case util::hashFNV1a("icon-halo-width"): + if (name == "icon-halo-width") { + property = Property::IconHaloWidth; + } + break; + case util::hashFNV1a("icon-halo-width-transition"): + if (name == "icon-halo-width-transition") { + property = Property::IconHaloWidthTransition; + } + break; + case util::hashFNV1a("icon-halo-blur"): + if (name == "icon-halo-blur") { + property = Property::IconHaloBlur; + } + break; + case util::hashFNV1a("icon-halo-blur-transition"): + if (name == "icon-halo-blur-transition") { + property = Property::IconHaloBlurTransition; + } + break; + case util::hashFNV1a("icon-translate"): + if (name == "icon-translate") { + property = Property::IconTranslate; + } + break; + case util::hashFNV1a("icon-translate-transition"): + if (name == "icon-translate-transition") { + property = Property::IconTranslateTransition; + } + break; + case util::hashFNV1a("icon-translate-anchor"): + if (name == "icon-translate-anchor") { + property = Property::IconTranslateAnchor; + } + break; + case util::hashFNV1a("icon-translate-anchor-transition"): + if (name == "icon-translate-anchor-transition") { + property = Property::IconTranslateAnchorTransition; + } + break; + case util::hashFNV1a("text-opacity"): + if (name == "text-opacity") { + property = Property::TextOpacity; + } + break; + case util::hashFNV1a("text-opacity-transition"): + if (name == "text-opacity-transition") { + property = Property::TextOpacityTransition; + } + break; + case util::hashFNV1a("text-color"): + if (name == "text-color") { + property = Property::TextColor; + } + break; + case util::hashFNV1a("text-color-transition"): + if (name == "text-color-transition") { + property = Property::TextColorTransition; + } + break; + case util::hashFNV1a("text-halo-color"): + if (name == "text-halo-color") { + property = Property::TextHaloColor; + } + break; + case util::hashFNV1a("text-halo-color-transition"): + if (name == "text-halo-color-transition") { + property = Property::TextHaloColorTransition; + } + break; + case util::hashFNV1a("text-halo-width"): + if (name == "text-halo-width") { + property = Property::TextHaloWidth; + } + break; + case util::hashFNV1a("text-halo-width-transition"): + if (name == "text-halo-width-transition") { + property = Property::TextHaloWidthTransition; + } + break; + case util::hashFNV1a("text-halo-blur"): + if (name == "text-halo-blur") { + property = Property::TextHaloBlur; + } + break; + case util::hashFNV1a("text-halo-blur-transition"): + if (name == "text-halo-blur-transition") { + property = Property::TextHaloBlurTransition; + } + break; + case util::hashFNV1a("text-translate"): + if (name == "text-translate") { + property = Property::TextTranslate; + } + break; + case util::hashFNV1a("text-translate-transition"): + if (name == "text-translate-transition") { + property = Property::TextTranslateTransition; + } + break; + case util::hashFNV1a("text-translate-anchor"): + if (name == "text-translate-anchor") { + property = Property::TextTranslateAnchor; + } + break; + case util::hashFNV1a("text-translate-anchor-transition"): + if (name == "text-translate-anchor-transition") { + property = Property::TextTranslateAnchorTransition; + } + break; - if (name == "icon-opacity") { + } + + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; + } + + + if (property == Property::IconOpacity || property == Property::IconHaloWidth || property == Property::IconHaloBlur || property == Property::TextOpacity || property == Property::TextHaloWidth || property == Property::TextHaloBlur) { Error error; optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - - setIconOpacity(*typedValue); - return nullopt; - } - if (name == "icon-opacity-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::IconOpacity) { + setIconOpacity(*typedValue); + return nullopt; } - - setIconOpacityTransition(*transition); - return nullopt; + + if (property == Property::IconHaloWidth) { + setIconHaloWidth(*typedValue); + return nullopt; + } + + if (property == Property::IconHaloBlur) { + setIconHaloBlur(*typedValue); + return nullopt; + } + + if (property == Property::TextOpacity) { + setTextOpacity(*typedValue); + return nullopt; + } + + if (property == Property::TextHaloWidth) { + setTextHaloWidth(*typedValue); + return nullopt; + } + + if (property == Property::TextHaloBlur) { + setTextHaloBlur(*typedValue); + return nullopt; + } + } - if (name == "icon-color") { + if (property == Property::IconColor || property == Property::IconHaloColor || property == Property::TextColor || property == Property::TextHaloColor) { Error error; optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - - setIconColor(*typedValue); - return nullopt; - } - if (name == "icon-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::IconColor) { + setIconColor(*typedValue); + return nullopt; } - - setIconColorTransition(*transition); - return nullopt; + + if (property == Property::IconHaloColor) { + setIconHaloColor(*typedValue); + return nullopt; + } + + if (property == Property::TextColor) { + setTextColor(*typedValue); + return nullopt; + } + + if (property == Property::TextHaloColor) { + setTextHaloColor(*typedValue); + return nullopt; + } + } - if (name == "icon-halo-color") { + if (property == Property::IconTranslate || property == Property::TextTranslate) { Error error; - optional> typedValue = convert>(value, error, true, false); + optional>> typedValue = convert>>(value, error, false, false); if (!typedValue) { return error; } - - setIconHaloColor(*typedValue); - return nullopt; - } - if (name == "icon-halo-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::IconTranslate) { + setIconTranslate(*typedValue); + return nullopt; } - - setIconHaloColorTransition(*transition); - return nullopt; + + if (property == Property::TextTranslate) { + setTextTranslate(*typedValue); + return nullopt; + } + } - if (name == "icon-halo-width") { + if (property == Property::IconTranslateAnchor || property == Property::TextTranslateAnchor) { Error error; - optional> typedValue = convert>(value, error, true, false); + optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setIconHaloWidth(*typedValue); - return nullopt; - } - if (name == "icon-halo-width-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; + + if (property == Property::IconTranslateAnchor) { + setIconTranslateAnchor(*typedValue); + return nullopt; } - - setIconHaloWidthTransition(*transition); - return nullopt; + + if (property == Property::TextTranslateAnchor) { + setTextTranslateAnchor(*typedValue); + return nullopt; + } + } - if (name == "icon-halo-blur") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - setIconHaloBlur(*typedValue); - return nullopt; + Error error; + optional transition = convert(value, error); + if (!transition) { + return error; } - if (name == "icon-halo-blur-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setIconHaloBlurTransition(*transition); + + if (property == Property::IconOpacityTransition) { + setIconOpacityTransition(*transition); return nullopt; } - if (name == "icon-translate") { - Error error; - optional>> typedValue = convert>>(value, error, false, false); - if (!typedValue) { - return error; - } - - setIconTranslate(*typedValue); + if (property == Property::IconColorTransition) { + setIconColorTransition(*transition); return nullopt; } - if (name == "icon-translate-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setIconTranslateTransition(*transition); + + if (property == Property::IconHaloColorTransition) { + setIconHaloColorTransition(*transition); return nullopt; } - if (name == "icon-translate-anchor") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setIconTranslateAnchor(*typedValue); + if (property == Property::IconHaloWidthTransition) { + setIconHaloWidthTransition(*transition); return nullopt; } - if (name == "icon-translate-anchor-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setIconTranslateAnchorTransition(*transition); + + if (property == Property::IconHaloBlurTransition) { + setIconHaloBlurTransition(*transition); return nullopt; } - if (name == "text-opacity") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setTextOpacity(*typedValue); + if (property == Property::IconTranslateTransition) { + setIconTranslateTransition(*transition); return nullopt; } - if (name == "text-opacity-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - - setTextOpacityTransition(*transition); + + if (property == Property::IconTranslateAnchorTransition) { + setIconTranslateAnchorTransition(*transition); return nullopt; } - if (name == "text-color") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setTextColor(*typedValue); + if (property == Property::TextOpacityTransition) { + setTextOpacityTransition(*transition); return nullopt; } - if (name == "text-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + + if (property == Property::TextColorTransition) { setTextColorTransition(*transition); return nullopt; } - if (name == "text-halo-color") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setTextHaloColor(*typedValue); - return nullopt; - } - if (name == "text-halo-color-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + if (property == Property::TextHaloColorTransition) { setTextHaloColorTransition(*transition); return nullopt; } - if (name == "text-halo-width") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setTextHaloWidth(*typedValue); - return nullopt; - } - if (name == "text-halo-width-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + if (property == Property::TextHaloWidthTransition) { setTextHaloWidthTransition(*transition); return nullopt; } - if (name == "text-halo-blur") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; - } - - setTextHaloBlur(*typedValue); - return nullopt; - } - if (name == "text-halo-blur-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + if (property == Property::TextHaloBlurTransition) { setTextHaloBlurTransition(*transition); return nullopt; } - if (name == "text-translate") { - Error error; - optional>> typedValue = convert>>(value, error, false, false); - if (!typedValue) { - return error; - } - - setTextTranslate(*typedValue); - return nullopt; - } - if (name == "text-translate-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + if (property == Property::TextTranslateTransition) { setTextTranslateTransition(*transition); return nullopt; } - if (name == "text-translate-anchor") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; - } - - setTextTranslateAnchor(*typedValue); - return nullopt; - } - if (name == "text-translate-anchor-transition") { - Error error; - optional transition = convert(value, error); - if (!transition) { - return error; - } - + if (property == Property::TextTranslateAnchorTransition) { setTextTranslateAnchorTransition(*transition); return nullopt; } + return Error { "layer doesn't support this property" }; } @@ -1375,403 +1447,558 @@ optional SymbolLayer::setLayoutProperty(const std::string& name, const Co return nullopt; } + enum class Property { + Unknown, + SymbolPlacement, + SymbolSpacing, + SymbolAvoidEdges, + IconAllowOverlap, + IconIgnorePlacement, + IconOptional, + IconRotationAlignment, + IconSize, + IconTextFit, + IconTextFitPadding, + IconImage, + IconRotate, + IconPadding, + IconKeepUpright, + IconOffset, + IconAnchor, + IconPitchAlignment, + TextPitchAlignment, + TextRotationAlignment, + TextField, + TextFont, + TextSize, + TextMaxWidth, + TextLineHeight, + TextLetterSpacing, + TextJustify, + TextAnchor, + TextMaxAngle, + TextRotate, + TextPadding, + TextKeepUpright, + TextTransform, + TextOffset, + TextAllowOverlap, + TextIgnorePlacement, + TextOptional, + }; + + Property property = Property::Unknown; + switch (util::hashFNV1a(name.c_str())) { - if (name == "symbol-placement") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("symbol-placement"): + if (name == "symbol-placement") { + property = Property::SymbolPlacement; } - - setSymbolPlacement(*typedValue); - return nullopt; - } + break; - if (name == "symbol-spacing") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("symbol-spacing"): + if (name == "symbol-spacing") { + property = Property::SymbolSpacing; } - - setSymbolSpacing(*typedValue); - return nullopt; - } + break; - if (name == "symbol-avoid-edges") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("symbol-avoid-edges"): + if (name == "symbol-avoid-edges") { + property = Property::SymbolAvoidEdges; } - - setSymbolAvoidEdges(*typedValue); - return nullopt; - } + break; - if (name == "icon-allow-overlap") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-allow-overlap"): + if (name == "icon-allow-overlap") { + property = Property::IconAllowOverlap; } - - setIconAllowOverlap(*typedValue); - return nullopt; - } + break; - if (name == "icon-ignore-placement") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-ignore-placement"): + if (name == "icon-ignore-placement") { + property = Property::IconIgnorePlacement; } - - setIconIgnorePlacement(*typedValue); - return nullopt; - } + break; - if (name == "icon-optional") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-optional"): + if (name == "icon-optional") { + property = Property::IconOptional; } - - setIconOptional(*typedValue); - return nullopt; - } + break; - if (name == "icon-rotation-alignment") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-rotation-alignment"): + if (name == "icon-rotation-alignment") { + property = Property::IconRotationAlignment; } - - setIconRotationAlignment(*typedValue); - return nullopt; - } + break; - if (name == "icon-size") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-size"): + if (name == "icon-size") { + property = Property::IconSize; } - - setIconSize(*typedValue); - return nullopt; - } + break; - if (name == "icon-text-fit") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-text-fit"): + if (name == "icon-text-fit") { + property = Property::IconTextFit; } - - setIconTextFit(*typedValue); - return nullopt; - } + break; - if (name == "icon-text-fit-padding") { - Error error; - optional>> typedValue = convert>>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-text-fit-padding"): + if (name == "icon-text-fit-padding") { + property = Property::IconTextFitPadding; } - - setIconTextFitPadding(*typedValue); - return nullopt; - } + break; - if (name == "icon-image") { - Error error; - optional> typedValue = convert>(value, error, true, true); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-image"): + if (name == "icon-image") { + property = Property::IconImage; } - - setIconImage(*typedValue); - return nullopt; - } + break; - if (name == "icon-rotate") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-rotate"): + if (name == "icon-rotate") { + property = Property::IconRotate; } - - setIconRotate(*typedValue); - return nullopt; - } + break; - if (name == "icon-padding") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-padding"): + if (name == "icon-padding") { + property = Property::IconPadding; } - - setIconPadding(*typedValue); - return nullopt; - } + break; - if (name == "icon-keep-upright") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-keep-upright"): + if (name == "icon-keep-upright") { + property = Property::IconKeepUpright; } - - setIconKeepUpright(*typedValue); - return nullopt; - } + break; - if (name == "icon-offset") { - Error error; - optional>> typedValue = convert>>(value, error, true, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-offset"): + if (name == "icon-offset") { + property = Property::IconOffset; } - - setIconOffset(*typedValue); - return nullopt; - } + break; - if (name == "icon-anchor") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-anchor"): + if (name == "icon-anchor") { + property = Property::IconAnchor; } - - setIconAnchor(*typedValue); - return nullopt; - } + break; - if (name == "icon-pitch-alignment") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("icon-pitch-alignment"): + if (name == "icon-pitch-alignment") { + property = Property::IconPitchAlignment; } - - setIconPitchAlignment(*typedValue); - return nullopt; - } + break; - if (name == "text-pitch-alignment") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("text-pitch-alignment"): + if (name == "text-pitch-alignment") { + property = Property::TextPitchAlignment; } - - setTextPitchAlignment(*typedValue); - return nullopt; - } + break; - if (name == "text-rotation-alignment") { - Error error; - optional> typedValue = convert>(value, error, false, false); - if (!typedValue) { - return error; + case util::hashFNV1a("text-rotation-alignment"): + if (name == "text-rotation-alignment") { + property = Property::TextRotationAlignment; } - - setTextRotationAlignment(*typedValue); - return nullopt; - } + break; - if (name == "text-field") { - Error error; - optional> typedValue = convert>(value, error, true, true); - if (!typedValue) { - return error; + case util::hashFNV1a("text-field"): + if (name == "text-field") { + property = Property::TextField; } - - setTextField(*typedValue); - return nullopt; - } + break; - if (name == "text-font") { - Error error; - optional>> typedValue = convert>>(value, error, true, false); - if (!typedValue) { - return error; + case util::hashFNV1a("text-font"): + if (name == "text-font") { + property = Property::TextFont; } - - setTextFont(*typedValue); - return nullopt; - } + break; - if (name == "text-size") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; + case util::hashFNV1a("text-size"): + if (name == "text-size") { + property = Property::TextSize; } - - setTextSize(*typedValue); - return nullopt; - } + break; - if (name == "text-max-width") { - Error error; - optional> typedValue = convert>(value, error, true, false); - if (!typedValue) { - return error; + case util::hashFNV1a("text-max-width"): + if (name == "text-max-width") { + property = Property::TextMaxWidth; + } + break; + + case util::hashFNV1a("text-line-height"): + if (name == "text-line-height") { + property = Property::TextLineHeight; + } + break; + + case util::hashFNV1a("text-letter-spacing"): + if (name == "text-letter-spacing") { + property = Property::TextLetterSpacing; + } + break; + + case util::hashFNV1a("text-justify"): + if (name == "text-justify") { + property = Property::TextJustify; + } + break; + + case util::hashFNV1a("text-anchor"): + if (name == "text-anchor") { + property = Property::TextAnchor; + } + break; + + case util::hashFNV1a("text-max-angle"): + if (name == "text-max-angle") { + property = Property::TextMaxAngle; + } + break; + + case util::hashFNV1a("text-rotate"): + if (name == "text-rotate") { + property = Property::TextRotate; + } + break; + + case util::hashFNV1a("text-padding"): + if (name == "text-padding") { + property = Property::TextPadding; + } + break; + + case util::hashFNV1a("text-keep-upright"): + if (name == "text-keep-upright") { + property = Property::TextKeepUpright; + } + break; + + case util::hashFNV1a("text-transform"): + if (name == "text-transform") { + property = Property::TextTransform; + } + break; + + case util::hashFNV1a("text-offset"): + if (name == "text-offset") { + property = Property::TextOffset; + } + break; + + case util::hashFNV1a("text-allow-overlap"): + if (name == "text-allow-overlap") { + property = Property::TextAllowOverlap; + } + break; + + case util::hashFNV1a("text-ignore-placement"): + if (name == "text-ignore-placement") { + property = Property::TextIgnorePlacement; + } + break; + + case util::hashFNV1a("text-optional"): + if (name == "text-optional") { + property = Property::TextOptional; } + break; + + } - setTextMaxWidth(*typedValue); - return nullopt; + if (property == Property::Unknown) { + return Error { "layer doesn't support this property" }; } - - if (name == "text-line-height") { + + + if (property == Property::SymbolPlacement) { Error error; - optional> typedValue = convert>(value, error, false, false); + optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setTextLineHeight(*typedValue); + + setSymbolPlacement(*typedValue); return nullopt; + } - if (name == "text-letter-spacing") { + if (property == Property::SymbolSpacing || property == Property::IconPadding || property == Property::TextLineHeight || property == Property::TextMaxAngle || property == Property::TextPadding) { Error error; - optional> typedValue = convert>(value, error, true, false); + optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setTextLetterSpacing(*typedValue); - return nullopt; + + if (property == Property::SymbolSpacing) { + setSymbolSpacing(*typedValue); + return nullopt; + } + + if (property == Property::IconPadding) { + setIconPadding(*typedValue); + return nullopt; + } + + if (property == Property::TextLineHeight) { + setTextLineHeight(*typedValue); + return nullopt; + } + + if (property == Property::TextMaxAngle) { + setTextMaxAngle(*typedValue); + return nullopt; + } + + if (property == Property::TextPadding) { + setTextPadding(*typedValue); + return nullopt; + } + } - if (name == "text-justify") { + if (property == Property::SymbolAvoidEdges || property == Property::IconAllowOverlap || property == Property::IconIgnorePlacement || property == Property::IconOptional || property == Property::IconKeepUpright || property == Property::TextKeepUpright || property == Property::TextAllowOverlap || property == Property::TextIgnorePlacement || property == Property::TextOptional) { Error error; - optional> typedValue = convert>(value, error, true, false); + optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setTextJustify(*typedValue); - return nullopt; + + if (property == Property::SymbolAvoidEdges) { + setSymbolAvoidEdges(*typedValue); + return nullopt; + } + + if (property == Property::IconAllowOverlap) { + setIconAllowOverlap(*typedValue); + return nullopt; + } + + if (property == Property::IconIgnorePlacement) { + setIconIgnorePlacement(*typedValue); + return nullopt; + } + + if (property == Property::IconOptional) { + setIconOptional(*typedValue); + return nullopt; + } + + if (property == Property::IconKeepUpright) { + setIconKeepUpright(*typedValue); + return nullopt; + } + + if (property == Property::TextKeepUpright) { + setTextKeepUpright(*typedValue); + return nullopt; + } + + if (property == Property::TextAllowOverlap) { + setTextAllowOverlap(*typedValue); + return nullopt; + } + + if (property == Property::TextIgnorePlacement) { + setTextIgnorePlacement(*typedValue); + return nullopt; + } + + if (property == Property::TextOptional) { + setTextOptional(*typedValue); + return nullopt; + } + } - if (name == "text-anchor") { + if (property == Property::IconRotationAlignment || property == Property::IconPitchAlignment || property == Property::TextPitchAlignment || property == Property::TextRotationAlignment) { Error error; - optional> typedValue = convert>(value, error, true, false); + optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setTextAnchor(*typedValue); - return nullopt; + + if (property == Property::IconRotationAlignment) { + setIconRotationAlignment(*typedValue); + return nullopt; + } + + if (property == Property::IconPitchAlignment) { + setIconPitchAlignment(*typedValue); + return nullopt; + } + + if (property == Property::TextPitchAlignment) { + setTextPitchAlignment(*typedValue); + return nullopt; + } + + if (property == Property::TextRotationAlignment) { + setTextRotationAlignment(*typedValue); + return nullopt; + } + } - if (name == "text-max-angle") { + if (property == Property::IconSize || property == Property::IconRotate || property == Property::TextSize || property == Property::TextMaxWidth || property == Property::TextLetterSpacing || property == Property::TextRotate) { Error error; - optional> typedValue = convert>(value, error, false, false); + optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - - setTextMaxAngle(*typedValue); - return nullopt; + + if (property == Property::IconSize) { + setIconSize(*typedValue); + return nullopt; + } + + if (property == Property::IconRotate) { + setIconRotate(*typedValue); + return nullopt; + } + + if (property == Property::TextSize) { + setTextSize(*typedValue); + return nullopt; + } + + if (property == Property::TextMaxWidth) { + setTextMaxWidth(*typedValue); + return nullopt; + } + + if (property == Property::TextLetterSpacing) { + setTextLetterSpacing(*typedValue); + return nullopt; + } + + if (property == Property::TextRotate) { + setTextRotate(*typedValue); + return nullopt; + } + } - if (name == "text-rotate") { + if (property == Property::IconTextFit) { Error error; - optional> typedValue = convert>(value, error, true, false); + optional> typedValue = convert>(value, error, false, false); if (!typedValue) { return error; } - - setTextRotate(*typedValue); + + setIconTextFit(*typedValue); return nullopt; + } - if (name == "text-padding") { + if (property == Property::IconTextFitPadding) { Error error; - optional> typedValue = convert>(value, error, false, false); + optional>> typedValue = convert>>(value, error, false, false); if (!typedValue) { return error; } - - setTextPadding(*typedValue); + + setIconTextFitPadding(*typedValue); return nullopt; + } - if (name == "text-keep-upright") { + if (property == Property::IconImage || property == Property::TextField) { Error error; - optional> typedValue = convert>(value, error, false, false); + optional> typedValue = convert>(value, error, true, true); if (!typedValue) { return error; } - - setTextKeepUpright(*typedValue); - return nullopt; + + if (property == Property::IconImage) { + setIconImage(*typedValue); + return nullopt; + } + + if (property == Property::TextField) { + setTextField(*typedValue); + return nullopt; + } + } - if (name == "text-transform") { + if (property == Property::IconOffset || property == Property::TextOffset) { Error error; - optional> typedValue = convert>(value, error, true, false); + optional>> typedValue = convert>>(value, error, true, false); if (!typedValue) { return error; } - - setTextTransform(*typedValue); - return nullopt; + + if (property == Property::IconOffset) { + setIconOffset(*typedValue); + return nullopt; + } + + if (property == Property::TextOffset) { + setTextOffset(*typedValue); + return nullopt; + } + } - if (name == "text-offset") { + if (property == Property::IconAnchor || property == Property::TextAnchor) { Error error; - optional>> typedValue = convert>>(value, error, true, false); + optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - - setTextOffset(*typedValue); - return nullopt; + + if (property == Property::IconAnchor) { + setIconAnchor(*typedValue); + return nullopt; + } + + if (property == Property::TextAnchor) { + setTextAnchor(*typedValue); + return nullopt; + } + } - if (name == "text-allow-overlap") { + if (property == Property::TextFont) { Error error; - optional> typedValue = convert>(value, error, false, false); + optional>> typedValue = convert>>(value, error, true, false); if (!typedValue) { return error; } - - setTextAllowOverlap(*typedValue); + + setTextFont(*typedValue); return nullopt; + } - if (name == "text-ignore-placement") { + if (property == Property::TextJustify) { Error error; - optional> typedValue = convert>(value, error, false, false); + optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - - setTextIgnorePlacement(*typedValue); + + setTextJustify(*typedValue); return nullopt; + } - if (name == "text-optional") { + if (property == Property::TextTransform) { Error error; - optional> typedValue = convert>(value, error, false, false); + optional> typedValue = convert>(value, error, true, false); if (!typedValue) { return error; } - - setTextOptional(*typedValue); + + setTextTransform(*typedValue); return nullopt; + } + return Error { "layer doesn't support this property" }; } diff --git a/src/mbgl/util/fnv_hash.hpp b/src/mbgl/util/fnv_hash.hpp new file mode 100644 index 0000000000..87d4661c56 --- /dev/null +++ b/src/mbgl/util/fnv_hash.hpp @@ -0,0 +1,11 @@ +#pragma once + +namespace mbgl { +namespace util { + +inline constexpr uint64_t hashFNV1a(const char * str, uint64_t value = 0xcbf29ce484222325) { + return str[0] ? hashFNV1a(str + 1, (value ^ uint64_t(str[0])) * 0x100000001b3) : value; +} + +} // end namespace util +} // end namespace mbgl -- cgit v1.2.1 From d886d3e4c04801e57340f98761cf76eec29e969d Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 10 Aug 2018 15:15:24 -0700 Subject: [core] Factor out setVisibility conversion --- include/mbgl/style/layer.hpp | 1 + src/mbgl/style/layer.cpp | 19 +++++++++++++++++++ src/mbgl/style/layers/background_layer.cpp | 14 +------------- src/mbgl/style/layers/circle_layer.cpp | 14 +------------- src/mbgl/style/layers/fill_extrusion_layer.cpp | 14 +------------- src/mbgl/style/layers/fill_layer.cpp | 14 +------------- src/mbgl/style/layers/heatmap_layer.cpp | 14 +------------- src/mbgl/style/layers/hillshade_layer.cpp | 14 +------------- src/mbgl/style/layers/layer.cpp.ejs | 14 +------------- src/mbgl/style/layers/line_layer.cpp | 14 +------------- src/mbgl/style/layers/raster_layer.cpp | 14 +------------- src/mbgl/style/layers/symbol_layer.cpp | 14 +------------- 12 files changed, 30 insertions(+), 130 deletions(-) diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index fee9f9121e..e0f71d2689 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -120,6 +120,7 @@ public: // Dynamic properties virtual optional setLayoutProperty(const std::string& name, const conversion::Convertible& value) = 0; virtual optional setPaintProperty(const std::string& name, const conversion::Convertible& value) = 0; + optional setVisibility(const conversion::Convertible& value); // Private implementation class Impl; diff --git a/src/mbgl/style/layer.cpp b/src/mbgl/style/layer.cpp index 142fe313cf..31ff5bf47a 100644 --- a/src/mbgl/style/layer.cpp +++ b/src/mbgl/style/layer.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace mbgl { namespace style { @@ -38,5 +39,23 @@ void Layer::setObserver(LayerObserver* observer_) { observer = observer_ ? observer_ : &nullObserver; } +optional Layer::setVisibility(const conversion::Convertible& value) { + using namespace conversion; + + if (isUndefined(value)) { + setVisibility(VisibilityType::Visible); + return nullopt; + } + + Error error; + optional visibility = convert(value, error); + if (!visibility) { + return error; + } + + setVisibility(*visibility); + return nullopt; +} + } // namespace style } // namespace mbgl diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index 88e175cb7c..e47b41daa8 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -273,19 +273,7 @@ optional BackgroundLayer::setPaintProperty(const std::string& name, const optional BackgroundLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { - if (isUndefined(value)) { - setVisibility(VisibilityType::Visible); - return nullopt; - } - - Error error; - optional visibility = convert(value, error); - if (!visibility) { - return error; - } - - setVisibility(*visibility); - return nullopt; + return Layer::setVisibility(value); } enum class Property { diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index eb3227da37..1dae77547b 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -718,19 +718,7 @@ optional CircleLayer::setPaintProperty(const std::string& name, const Con optional CircleLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { - if (isUndefined(value)) { - setVisibility(VisibilityType::Visible); - return nullopt; - } - - Error error; - optional visibility = convert(value, error); - if (!visibility) { - return error; - } - - setVisibility(*visibility); - return nullopt; + return Layer::setVisibility(value); } enum class Property { diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index 33f5bbe87c..db90415daa 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -520,19 +520,7 @@ optional FillExtrusionLayer::setPaintProperty(const std::string& name, co optional FillExtrusionLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { - if (isUndefined(value)) { - setVisibility(VisibilityType::Visible); - return nullopt; - } - - Error error; - optional visibility = convert(value, error); - if (!visibility) { - return error; - } - - setVisibility(*visibility); - return nullopt; + return Layer::setVisibility(value); } enum class Property { diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index c2756dc90e..2da131b6b2 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -520,19 +520,7 @@ optional FillLayer::setPaintProperty(const std::string& name, const Conve optional FillLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { - if (isUndefined(value)) { - setVisibility(VisibilityType::Visible); - return nullopt; - } - - Error error; - optional visibility = convert(value, error); - if (!visibility) { - return error; - } - - setVisibility(*visibility); - return nullopt; + return Layer::setVisibility(value); } enum class Property { diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index 69499e7d4a..df00558135 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -405,19 +405,7 @@ optional HeatmapLayer::setPaintProperty(const std::string& name, const Co optional HeatmapLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { - if (isUndefined(value)) { - setVisibility(VisibilityType::Visible); - return nullopt; - } - - Error error; - optional visibility = convert(value, error); - if (!visibility) { - return error; - } - - setVisibility(*visibility); - return nullopt; + return Layer::setVisibility(value); } enum class Property { diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp index 9ccdd1567b..fb96c681cc 100644 --- a/src/mbgl/style/layers/hillshade_layer.cpp +++ b/src/mbgl/style/layers/hillshade_layer.cpp @@ -430,19 +430,7 @@ optional HillshadeLayer::setPaintProperty(const std::string& name, const optional HillshadeLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { - if (isUndefined(value)) { - setVisibility(VisibilityType::Visible); - return nullopt; - } - - Error error; - optional visibility = convert(value, error); - if (!visibility) { - return error; - } - - setVisibility(*visibility); - return nullopt; + return Layer::setVisibility(value); } enum class Property { diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index 8a6db749cf..4e80a7bf74 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -257,19 +257,7 @@ case util::hashFNV1a("<%- property.name %>"): optional <%- camelize(type) %>Layer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { - if (isUndefined(value)) { - setVisibility(VisibilityType::Visible); - return nullopt; - } - - Error error; - optional visibility = convert(value, error); - if (!visibility) { - return error; - } - - setVisibility(*visibility); - return nullopt; + return Layer::setVisibility(value); } enum class Property { diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index cc6bfdde37..c744adad95 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -732,19 +732,7 @@ optional LineLayer::setPaintProperty(const std::string& name, const Conve optional LineLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { - if (isUndefined(value)) { - setVisibility(VisibilityType::Visible); - return nullopt; - } - - Error error; - optional visibility = convert(value, error); - if (!visibility) { - return error; - } - - setVisibility(*visibility); - return nullopt; + return Layer::setVisibility(value); } enum class Property { diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index da3f7f8a18..45d3240833 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -519,19 +519,7 @@ optional RasterLayer::setPaintProperty(const std::string& name, const Con optional RasterLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { - if (isUndefined(value)) { - setVisibility(VisibilityType::Visible); - return nullopt; - } - - Error error; - optional visibility = convert(value, error); - if (!visibility) { - return error; - } - - setVisibility(*visibility); - return nullopt; + return Layer::setVisibility(value); } enum class Property { diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index e7cba19ea5..48af6b13aa 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -1432,19 +1432,7 @@ optional SymbolLayer::setPaintProperty(const std::string& name, const Con optional SymbolLayer::setLayoutProperty(const std::string& name, const Convertible& value) { if (name == "visibility") { - if (isUndefined(value)) { - setVisibility(VisibilityType::Visible); - return nullopt; - } - - Error error; - optional visibility = convert(value, error); - if (!visibility) { - return error; - } - - setVisibility(*visibility); - return nullopt; + return Layer::setVisibility(value); } enum class Property { -- cgit v1.2.1 From 41d5768f5861c200dc0721acb13b39783a168b29 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Mon, 13 Aug 2018 12:45:03 -0700 Subject: [core] Don't default-show text/icons that depend on the placement of a paired icon/text Fixes issue #12483. --- platform/android/CHANGELOG.md | 5 ++++- platform/ios/CHANGELOG.md | 1 + platform/macos/CHANGELOG.md | 2 ++ platform/node/CHANGELOG.md | 1 + src/mbgl/text/placement.cpp | 11 +++++++++-- 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index 2df4bf18da..a7113546b5 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -2,6 +2,9 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started. +## master +- Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) + ## 6.4.0-beta.1 - August 9, 2018 - Don't prefetch tiles for geojson sources [#12529](https://github.com/mapbox/mapbox-gl-native/pull/12529) - Enable LTO in release builds [#12546](https://github.com/mapbox/mapbox-gl-native/pull/12546) @@ -44,7 +47,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Add LatLngForScreenCoordinate to MapSnapshotter API, This allows to convert a LatLng value to the x,y position on the MapSnasphot image [#12221](https://github.com/mapbox/mapbox-gl-native/pull/12221) - Expose multiple getCameraFor equivalent methods to convert a geometry or a bounds to a camera position with taking in account padding, tilt and bearing [#12290](https://github.com/mapbox/mapbox-gl-native/pull/12290) - Avoid race condition when calling getMapAsync from a non-UI thread when running instrumentation tests [#12308](https://github.com/mapbox/mapbox-gl-native/pull/12308) - + ## 6.2.1 - June 27, 2018 - Backport range alpha values from 0 to 1 with int color conversion [#12235](https://github.com/mapbox/mapbox-gl-native/pull/12235) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 59d5cac39b..cf03852328 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -6,6 +6,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Improved the Swift interface for `MGLMapView.decelerationRate`. ([#12584](https://github.com/mapbox/mapbox-gl-native/issues/12584)) * Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) +* Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) ## 4.3.0 diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index bfc94b28ad..c0266aff5a 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -2,6 +2,8 @@ # master +- Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) + ## Styles and rendering * Token string syntax (`"{token}"`) in `MGLSymbolStyleLayer` `text` and `iconImageName` properties is now correctly converted to the appropriate `NSExpression` equivalent. ([#11659](https://github.com/mapbox/mapbox-gl-native/issues/11659)) diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md index 8ce4756814..81210ab153 100644 --- a/platform/node/CHANGELOG.md +++ b/platform/node/CHANGELOG.md @@ -1,4 +1,5 @@ # master +- Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) - The `Map` constructor now accepts a `mode` option which can be either `"static"` (default) or `"tile"`. It must be set to `"tile"` when rendering individual tiles in order for the symbols to match across tiles. - Remove unnecessary memory use when collision debug mode is not enabled ([#12294](https://github.com/mapbox/mapbox-gl-native/issues/12294)) - Added support for rendering `symbol-placement: line-center` ([#12337](https://github.com/mapbox/mapbox-gl-native/pull/12337)) diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index 8bd92087b1..a050be4648 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -254,9 +254,16 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set& JointOpacityState duplicateOpacityState(false, false, true); + const bool textAllowOverlap = bucket.layout.get(); + const bool iconAllowOverlap = bucket.layout.get(); + + // If allow-overlap is true, we can show symbols before placement runs on them + // But we have to wait for placement if we potentially depend on a paired icon/text + // with allow-overlap: false. + // See https://github.com/mapbox/mapbox-gl-native/issues/12483 JointOpacityState defaultOpacityState( - bucket.layout.get(), - bucket.layout.get(), + textAllowOverlap && (iconAllowOverlap || !bucket.hasIconData() || bucket.layout.get()), + iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || bucket.layout.get()), true); for (SymbolInstance& symbolInstance : bucket.symbolInstances) { -- cgit v1.2.1 From f3ebdaebafbd3396cff148cc4eb1f1148b0bb724 Mon Sep 17 00:00:00 2001 From: "Thiago Marcos P. Santos" Date: Tue, 14 Aug 2018 11:08:47 +0300 Subject: [windows] Fix build on Windows Include what you use. --- platform/default/sqlite3.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp index 2e76f6eec4..1a6045a9a8 100644 --- a/platform/default/sqlite3.cpp +++ b/platform/default/sqlite3.cpp @@ -1,6 +1,7 @@ #include "sqlite3.hpp" #include +#include #include #include #include -- cgit v1.2.1 From 60cbedc344eff10df0069a9d243a555dc59992ee Mon Sep 17 00:00:00 2001 From: Langston Smith Date: Tue, 14 Aug 2018 07:35:23 -0700 Subject: Fix to textureview transparent background testapp activity (#12605) * removed comma * removed map style declaration in xml --- .../src/main/res/layout/activity_textureview_transparent.xml | 3 +-- .../MapboxGLAndroidSDKTestApp/src/main/res/raw/no_bg_style.json | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml index 3b9ee71359..1d99e61d74 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml @@ -21,8 +21,7 @@ app:mapbox_cameraTargetLng="8.363795" app:mapbox_cameraZoom="2" app:mapbox_renderTextureMode="true" - app:mapbox_renderTextureTranslucentSurface="true" - app:mapbox_styleUrl="mapbox://styles/agerace-globant/cja02de7193b02suvy4gpbt2c"/> + app:mapbox_renderTextureTranslucentSurface="true"/> diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/no_bg_style.json b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/no_bg_style.json index 964eefc319..9f2b419497 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/no_bg_style.json +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/raw/no_bg_style.json @@ -2,7 +2,7 @@ "version": 8, "name": "Land", "metadata": { - "mapbox:autocomposite": true, + "mapbox:autocomposite": true }, "sources": { "composite": { -- cgit v1.2.1 From 16e6ca86faad8527af529b3a6de0751dbac447d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 14 Aug 2018 08:53:02 -0700 Subject: [core] add test for comparing filter name to id --- test/style/filter.test.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/style/filter.test.cpp b/test/style/filter.test.cpp index e04a569203..9678fe0895 100644 --- a/test/style/filter.test.cpp +++ b/test/style/filter.test.cpp @@ -251,3 +251,7 @@ TEST(Filter, ZoomExpressionNested) { TEST(Filter, Internal) { filter(R"(["filter-==","class","snow"])"); } + +TEST(Filter, Short) { + filter(R"(["==", ["id"], "foo"])"); +} -- cgit v1.2.1 From 9ecb0997effb006e88c25d6fbca2570c8ab51adc Mon Sep 17 00:00:00 2001 From: Vladimir Kondrashov Date: Mon, 13 Aug 2018 11:25:33 -0700 Subject: [core] Fix out of range exception for string compare --- platform/default/asset_file_source.cpp | 2 +- platform/default/local_file_source.cpp | 2 +- src/mbgl/style/expression/is_constant.cpp | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/platform/default/asset_file_source.cpp b/platform/default/asset_file_source.cpp index 3063bf88a0..7988654ae5 100644 --- a/platform/default/asset_file_source.cpp +++ b/platform/default/asset_file_source.cpp @@ -75,7 +75,7 @@ std::unique_ptr AssetFileSource::request(const Resource& resource, } bool AssetFileSource::acceptsURL(const std::string& url) { - return std::equal(assetProtocol.begin(), assetProtocol.end(), url.begin()); + return 0 == url.rfind(assetProtocol, 0); } } // namespace mbgl diff --git a/platform/default/local_file_source.cpp b/platform/default/local_file_source.cpp index 0635e86d80..1b7b7b9278 100644 --- a/platform/default/local_file_source.cpp +++ b/platform/default/local_file_source.cpp @@ -75,7 +75,7 @@ std::unique_ptr LocalFileSource::request(const Resource& resource, } bool LocalFileSource::acceptsURL(const std::string& url) { - return std::equal(fileProtocol.begin(), fileProtocol.end(), url.begin()); + return 0 == url.rfind(fileProtocol, 0); } } // namespace mbgl diff --git a/src/mbgl/style/expression/is_constant.cpp b/src/mbgl/style/expression/is_constant.cpp index 69f27f6fef..3b20f49a86 100644 --- a/src/mbgl/style/expression/is_constant.cpp +++ b/src/mbgl/style/expression/is_constant.cpp @@ -17,7 +17,7 @@ bool isFeatureConstant(const Expression& expression) { return false; } else if (name == "has" && parameterCount && *parameterCount == 1) { return false; - } else if (std::equal(std::begin(filter), std::end(filter) - 1, name.begin())) { + } else if (0 == name.rfind(filter, 0)) { // Legacy filters begin with "filter-" and are never constant. return false; } else if ( @@ -28,7 +28,7 @@ bool isFeatureConstant(const Expression& expression) { return false; } } - + if (expression.getKind() == Kind::CollatorExpression) { // Although the results of a Collator expression with fixed arguments // generally shouldn't change between executions, we can't serialize them -- cgit v1.2.1 From 20f880ebec82bbd7553fc382400227efc0105bce Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 14 Aug 2018 11:35:39 -0700 Subject: [core] Fix querying for annotations near tile boundaries at high zoom. Fixes issue #12472. This commit doesn't address the underlying issues that come from symbolAnnotationTree using a slightly lower precision coordinate system than the annotations themselves. Instead, it just puts a small padding around each tile when it queries for tile data, so that symbols right at the tile boundary will be included in both tiles. The rendering/querying code will take care of only displaying one instance. The padding is in global coordinates, so at higher zoom the padding will be larger in tile units -- this is consistent with precision loss also being greater at higher zoom. --- platform/android/CHANGELOG.md | 1 + platform/ios/CHANGELOG.md | 1 + platform/macos/CHANGELOG.md | 1 + platform/node/CHANGELOG.md | 1 + src/mbgl/annotation/annotation_manager.cpp | 8 +++++++- test/api/annotations.test.cpp | 13 +++++++++++++ 6 files changed, 24 insertions(+), 1 deletion(-) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index a7113546b5..daef4095f9 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -4,6 +4,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## master - Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) +- Fix symbol querying for markers near tile boundaries at high zoom. ([#12472](https://github.com/mapbox/mapbox-gl-native/issues/12472)) ## 6.4.0-beta.1 - August 9, 2018 - Don't prefetch tiles for geojson sources [#12529](https://github.com/mapbox/mapbox-gl-native/pull/12529) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index cf03852328..e3ad4d5b3e 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -7,6 +7,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Improved the Swift interface for `MGLMapView.decelerationRate`. ([#12584](https://github.com/mapbox/mapbox-gl-native/issues/12584)) * Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) * Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) +* Fix the behavior of `-[MGLMapView visibleFeaturesAtPoint:]` near tile boundaries at high zoom. ([#12472](https://github.com/mapbox/mapbox-gl-native/issues/12472)) ## 4.3.0 diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index c0266aff5a..1c1454de4d 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -3,6 +3,7 @@ # master - Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) +- Fix the `-[MGLMapView annotationAtPoint:]` method near tile boundaries at high zoom. ([#12472](https://github.com/mapbox/mapbox-gl-native/issues/12472)) ## Styles and rendering diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md index 81210ab153..cfb86f4dbf 100644 --- a/platform/node/CHANGELOG.md +++ b/platform/node/CHANGELOG.md @@ -1,5 +1,6 @@ # master - Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) +- Fix symbol querying for annotations near tile boundaries at high zoom. ([#12472](https://github.com/mapbox/mapbox-gl-native/issues/12472)) - The `Map` constructor now accepts a `mode` option which can be either `"static"` (default) or `"tile"`. It must be set to `"tile"` when rendering individual tiles in order for the symbols to match across tiles. - Remove unnecessary memory use when collision debug mode is not enabled ([#12294](https://github.com/mapbox/mapbox-gl-native/issues/12294)) - Added support for rendering `symbol-placement: line-center` ([#12337](https://github.com/mapbox/mapbox-gl-native/pull/12337)) diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp index 41eedf17dc..1baf83179e 100644 --- a/src/mbgl/annotation/annotation_manager.cpp +++ b/src/mbgl/annotation/annotation_manager.cpp @@ -140,7 +140,13 @@ std::unique_ptr AnnotationManager::getTileData(const Canonic auto pointLayer = tileData->addLayer(PointLayerID); LatLngBounds tileBounds(tileID); - + // Hack for https://github.com/mapbox/mapbox-gl-native/issues/12472 + // To handle precision issues, query a slightly larger area than the tile bounds + // Symbols at a border can be included in vector data for both tiles + // The rendering/querying logic will make sure the symbols show up in only one of the tiles + tileBounds.extend(LatLng(tileBounds.south() - 0.000000001, tileBounds.west() - 0.000000001)); + tileBounds.extend(LatLng(tileBounds.north() + 0.000000001, tileBounds.east() + 0.000000001)); + symbolTree.query(boost::geometry::index::intersects(tileBounds), boost::make_function_output_iterator([&](const auto& val){ val->updateLayer(tileID, *pointLayer); diff --git a/test/api/annotations.test.cpp b/test/api/annotations.test.cpp index 07257851ac..fea1f87106 100644 --- a/test/api/annotations.test.cpp +++ b/test/api/annotations.test.cpp @@ -59,6 +59,18 @@ TEST(Annotations, SymbolAnnotation) { // } } +TEST(Annotations, SymbolAnnotationTileBoundary) { + // Almost exactly the same as SymbolAnnotation test above, but offset my fractions of a degree + // tests precision issue from https://github.com/mapbox/mapbox-gl-native/issues/12472 + AnnotationTest test; + + test.map.getStyle().loadJSON(util::read_file("test/fixtures/api/empty.json")); + test.map.addAnnotationImage(namedMarker("default_marker")); + test.map.addAnnotation(SymbolAnnotation { Point(0.000000000000001, 0.00000000000001), "default_marker" }); + test.map.setZoom(10); + test.checkRendering("point_annotation"); +} + TEST(Annotations, LineAnnotation) { AnnotationTest test; @@ -475,3 +487,4 @@ TEST(Annotations, ChangeMaxZoom) { test.map.setZoom(test.map.getMaxZoom()); test.checkRendering("line_annotation_max_zoom"); } + -- cgit v1.2.1 From 4b9ed3837a68dd49286711049c1f07be7bbcab04 Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Thu, 2 Aug 2018 13:42:35 -0700 Subject: [ios] Remove duplicated guides --- .../ios/docs/guides/Adding Markers to a Map.md | 62 ------------- platform/ios/docs/guides/For Style Authors.md | 4 +- .../ios/docs/guides/Migrating to Expressions.md | 4 +- platform/ios/docs/guides/Runtime Styling.md | 57 ------------ .../ios/docs/guides/Working with Mapbox Studio.md | 96 --------------------- .../adding-points-to-a-map/annotation-image.png | Bin 171537 -> 0 bytes .../img/adding-points-to-a-map/annotation-view.png | Bin 79919 -> 0 bytes .../img/adding-points-to-a-map/circle-layer.png | Bin 215965 -> 0 bytes .../img/adding-points-to-a-map/symbol-layer.png | Bin 75743 -> 0 bytes .../docs/img/runtime-styling/CustomAnnotations.gif | Bin 44108 -> 0 bytes .../ios/docs/img/runtime-styling/DynamicStyles.gif | Bin 94908 -> 0 bytes platform/ios/docs/img/runtime-styling/Emoji.gif | Bin 126330 -> 0 bytes platform/ios/docs/img/runtime-styling/HexBins.gif | Bin 435797 -> 0 bytes .../ios/docs/img/runtime-styling/Population.gif | Bin 228484 -> 0 bytes .../ios/docs/img/runtime-styling/SnowLevels.gif | Bin 463142 -> 0 bytes .../docs/img/studio-workflow/add-properties.gif | Bin 176869 -> 0 bytes .../docs/img/studio-workflow/create-polygons.gif | Bin 565786 -> 0 bytes .../docs/img/studio-workflow/property-values.png | Bin 39756 -> 0 bytes .../docs/img/studio-workflow/stop-functions.png | Bin 92170 -> 0 bytes 19 files changed, 4 insertions(+), 219 deletions(-) delete mode 100644 platform/ios/docs/guides/Adding Markers to a Map.md delete mode 100644 platform/ios/docs/guides/Runtime Styling.md delete mode 100644 platform/ios/docs/guides/Working with Mapbox Studio.md delete mode 100644 platform/ios/docs/img/adding-points-to-a-map/annotation-image.png delete mode 100644 platform/ios/docs/img/adding-points-to-a-map/annotation-view.png delete mode 100644 platform/ios/docs/img/adding-points-to-a-map/circle-layer.png delete mode 100644 platform/ios/docs/img/adding-points-to-a-map/symbol-layer.png delete mode 100644 platform/ios/docs/img/runtime-styling/CustomAnnotations.gif delete mode 100644 platform/ios/docs/img/runtime-styling/DynamicStyles.gif delete mode 100644 platform/ios/docs/img/runtime-styling/Emoji.gif delete mode 100644 platform/ios/docs/img/runtime-styling/HexBins.gif delete mode 100644 platform/ios/docs/img/runtime-styling/Population.gif delete mode 100644 platform/ios/docs/img/runtime-styling/SnowLevels.gif delete mode 100644 platform/ios/docs/img/studio-workflow/add-properties.gif delete mode 100644 platform/ios/docs/img/studio-workflow/create-polygons.gif delete mode 100644 platform/ios/docs/img/studio-workflow/property-values.png delete mode 100644 platform/ios/docs/img/studio-workflow/stop-functions.png diff --git a/platform/ios/docs/guides/Adding Markers to a Map.md b/platform/ios/docs/guides/Adding Markers to a Map.md deleted file mode 100644 index b33b536d44..0000000000 --- a/platform/ios/docs/guides/Adding Markers to a Map.md +++ /dev/null @@ -1,62 +0,0 @@ -# Adding Markers to a Map - -Mapbox offers a few different ways to add markers to a map, each with different tradeoffs. Below is an overview of the variety of approaches that can be used. - -## **Annotations API** - -Our annotations API includes the `MGLAnnotationImage`, and `MGLAnnotationView` classes. These are most similar to MapKit’s annotation class and provide a familiar interface for working with markers and callouts. - -| MGLAnnotationImage | MGLAnnotationView | -|----------------------|---------------------| -| `MGLAnnotationImage` | `MGLAnnotationView` | - -**MGLAnnotationImage** is an annotation class that is easily customizable with any `UIImage`. -It is highly performant, as the images are rendered directly using OpenGL. However, if you need to animate your annotations or control z-layer ordering, consider working with **MGLAnnotationView** which supports any animation that can be applied to a `UIView`. View hierarchy can be manipulated by using instance methods available on `UIView` such as `-[UIView bringSubviewToFront:]`. - -**MGLAnnotationView** is an annotation class that is an easily customizable `UIView`. Use this class if you need your markers to be dynamic or animated. `MGLAnnotationView` has a significant advantage over `MGLAnnotationImage` when you need every annotation to be unique. For example, annotation views are ideal for showing user locations on a map using high-resolution profile pictures. However, the map can slow down when many annotation views are visible at the same time, so if you need to add a very large number of markers, consider using our runtime styling APIs instead. - -Both `MGLAnnotationImage` and `MGLAnnotationView` can become interactive by adding a [few lines of code](https://www.mapbox.com/ios-sdk/examples/marker/). When the user taps an annotation, the annotation’s name appears in a basic callout. An annotation view can additionally respond to [drag-and-drop gestures](https://www.mapbox.com/ios-sdk/examples/draggable-views/). - -## **Runtime styling API** - -For full control of how markers are displayed on a map, consider using our [runtime styling](runtime-styling.html) APIs. Like `MGLAnnotationImage`, it is a performant approach to adding markers because they rendered directly using OpenGL. However, the runtime styling APIs also provide support for rendering labels together with icons, finer control of z-ordering, and clustering, so consider using this set of APIs if you need to display a large amount of highly customizable markers. - -Our runtime styling API is the most powerful option if you need to create rich data visualizations within in your map, but it is the most complex and has a steeper learning curve than our annotations API. - -The runtime styling API includes our `MGLSymbolStyleLayer` and `MGLCircleStyleLayer` classes that can be used to dynamically display on markers on map when used in conjunction with either an `MGLVectorSource` or an `MGLShapeSource`. - -If you need to implement callouts with the `MGLSymbolStyleLayer` or `MGLCircleStyleLayer`, you will need to implement your own tap gesture recognizer that calls `-[MGLMapView visibleFeaturesAtPoint:inStyleLayersWithIdentifiers:]` to get the tapped point feature, then show a `UIView` you provide. Additionally, if you need to animate markers when using the runtime styling APIs, consider using a timer to update the source data coordinates accordingly. - -| MGLCircleStyleLayer | MGLSymbolStyleLayer | -|----------------------|---------------------| -| `MGLCircleStyleLayer` | `MGLSymbolStyleLayer` | - -The **MGLCircleStyleLayer** class is the style layer class responsible for displaying the source’s point features as circle-shaped markers. You can specify circle fill and outline colors, as well as size. You can also dynamically change the circle’s styling properties based on any attributes your source data contains. - -The **MGLSymbolStyleLayer** class is the style layer class responsible for displaying the source’s point features as icons and labels. You can use custom images as icons and also combine text labels, placing them exactly where you specify. You can also dynamically change the symbol’s styling properties based on any attributes your source data contains. - -Still undecided on which approach will work best for your use case? [Reach out to our support team](https://www.mapbox.com/contact/). - -See the table below for a summary of APIs that can be used to add markers to a map: - -✅ Recommended - -⚠️ Supported with caveats - -➖ Unavailable or not supported - - -| Feature | MGLAnnotationView | MGLAnnotationImage | MGLSymbolStyleLayer | MGLCircleStyleLayer | -|----------------------------------------------------|--------------------------------------------------------------------|----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------| -| Customizability | ✅ Text labels, interactive subviews | ⚠️ Static images only | ✅ Full support for text labels and label placement | ✅Customize circle color and outline | -| Borrows familiar concepts from | MapKit, Google Maps SDK | ➖ | Mapbox GL JS, Mapbox Studio | Mapbox GL JS, Mapbox Studio | -| Can use images | ✅ | ✅ | ✅ | ➖ | -| Can use text | ✅ | ➖ | ✅ | ➖ | -| Control Z-index | ✅ | ➖ | ⚠️ Add multiple layers at, above, or below a specified layer index to control ordering | ⚠️ Add multiple layers at, above, or below a specified layer index to control ordering | -| Drag and drop | ✅ | ➖ | ➖ | ➖ | -| Core Animation support | ✅ | ➖ | ➖ | ➖ | -| Add/move/replace data | ✅ | ✅ | ⚠️ Partial data updates are less performant than using annotations | ⚠️ Partial data updates are less performant than using annotations | -| SceneKit support | ✅ | ➖ | ➖ | ➖ | -| Can be dynamically styled based on data attributes | ✅ Subclass `MGLPointAnnotation` to add custom attributes | ✅ Subclass `MGLPointAnnotation` to add custom attributes | ✅ | ✅ | -| Supports callouts | ✅ Built-in callouts included | ✅ Built-in callouts included | ⚠️ Implement your own gesture recognizer that uses feature querying, then create custom UIViews to mimic native callouts | ⚠️ Implement your own gesture recognizer that uses feature querying, then create custom UIViews to mimic native callouts | -| Supports clustering | ⚠️ Use a [third-party plugin](https://github.com/hulab/ClusterKit/) | ➖ | ✅ | ✅ | diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md index 24a2f7d3a4..9d240045b3 100644 --- a/platform/ios/docs/guides/For Style Authors.md +++ b/platform/ios/docs/guides/For Style Authors.md @@ -41,7 +41,7 @@ Studio, especially when multitasking is enabled. Your user’s viewing distance may be shorter than on a desktop computer. Some of your users may use the Larger Dynamic Type and Accessibility Text features to increase the size of all text on the device. You can use the -[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s +[runtime styling API](https://www.mapbox.com/ios-sdk/maps/overview/runtime-styling/) to adjust your style’s font and icon sizes accordingly. Design sprite images and choose font weights that look crisp on both @@ -98,7 +98,7 @@ represented at runtime by an `MGLStyle` object, which provides access to various `MGLSource` and `MGLStyleLayer` objects that represent content sources and style layers, respectively. For more information about the capabilities exposed by the runtime styling API, -see “[Runtime Styling](runtime-styling.html)”. +see “[Runtime Styling](https://www.mapbox.com/ios-sdk/maps/overview/runtime-styling/)”. The names of runtime styling classes and properties on iOS are generally consistent with the style specification and Mapbox Studio’s Styles editor. Any diff --git a/platform/ios/docs/guides/Migrating to Expressions.md b/platform/ios/docs/guides/Migrating to Expressions.md index 96d4df6853..b0965ee999 100644 --- a/platform/ios/docs/guides/Migrating to Expressions.md +++ b/platform/ios/docs/guides/Migrating to Expressions.md @@ -5,7 +5,7 @@ # Migrating from Style Functions to Expressions -[Runtime Styling](runtime-styling.html) enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Developers can specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source. +[Runtime Styling](https://www.mapbox.com/ios-sdk/maps/overview/runtime-styling/) enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Developers can specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source. With Mapbox Maps SDK for iOS v4.0.0, style functions have been replaced with expressions. These provide even more tools for developers who want to style their maps dynamically. This guide outlines some tips for migrating from style functions to expressions, and offers an overview of some things that developers can do with expressions. @@ -113,7 +113,7 @@ mapView.style?.insertLayer(layer, below: symbolLayer) If you previously used an interpolation base greater than `0` (other than `1`), you can use `MGLExpressionInterpolationMode.exponential` as the curve type for `+[NSExpression(MGLAdditions) mgl_expressionForInterpolatingExpression:withCurveType:parameters:stops:]` or `'exponential'` as the curve type for [`mgl_interpolate:withCurveType:parameters:stops:`](predicates-and-expressions.html#code-mgl_interpolate-withcurvetype-parameters-stops-code). The `parameters` argument takes that interpolation base. This interpolates between values exponentially, creating an accelerated ramp effect. -Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](working-with-mapbox-studio.html)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. +Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](https://www.mapbox.com/ios-sdk/maps/overview/mapbox-studio/)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. diff --git a/platform/ios/docs/guides/Runtime Styling.md b/platform/ios/docs/guides/Runtime Styling.md deleted file mode 100644 index 194d8b3bdd..0000000000 --- a/platform/ios/docs/guides/Runtime Styling.md +++ /dev/null @@ -1,57 +0,0 @@ -# Runtime Styling - -Mapbox’s runtime styling features allow you direct control over every layer in your maps with code. It’s now possible to create dynamic maps and visualizations that aren’t possible with other mobile maps SDKs. - -Runtime styling expands upon the design power of [Mapbox Studio](https://www.mapbox.com/mapbox-studio/) and exposes all of the same properties and attributes directly to mobile developers in our SDK. - -Beyond the custom styled maps that you can create with Mapbox Studio, you can now change the look and feel of your map on the fly having maps in your app visually respond to user interaction or or context. Or leverage the power of OpenGL for highly performant and complex data visualizations. Now it’s possible to mix in your own data and bring your map to life. - -## Example use cases - -As an example of what’s possible with runtime styling, consider some of the following use cases: - -### Styling maps on the fly - -At runtime, you can tailor the map specifically to your user interface. Tweak colors, text, and icons to match the style to your brand. - -![dynamic styles](img/runtime-styling/DynamicStyles.gif "an example showing dynamic styles") - -For maps that aren’t going to change in response to custom data or user interaction, consider creating a custom map style with [Mapbox Studio](https://www.mapbox.com/mapbox-studio/). - -### Map interactivity - -You can customize the map to the point of having it respond dynamically based on the actions your users are taking. Increase the text size of streets while a user is driving, emphasize points of interest tailored to a user’s preferences, or change your UI if users are at parks, trails, landmarks, or rivers. - -![emojis](img/runtime-styling/Emoji.gif "an example showing emoji interaction") - -### Powerful data visualization - -Mapbox maps are built on top of OpenGL and can support rendering data without the traditional overhead of `UIView`-based map annotations. - -Mapbox can support data visualizations that were slow or impossible with traditional map SDKs. Render heatmaps, visualize population density, or even go so far as updating the snow levels in the mountains to match recent snowfall. - -![hex bins](img/runtime-styling/HexBins.gif "an example using hex bins") -![population](img/runtime-styling/Population.gif "an example showing population density") -![snow levels](img/runtime-styling/SnowLevels.gif "an example visualizing snow levels in the mountains") - -### Powerful annotations - -The Mapbox SDK gives you access to all of the same tools we use to render our default map styles. Instead of using generic pin markers, enrich your place data or custom polygons with icons and labels that make your maps stand out. - -![custom annotations](img/runtime-styling/CustomAnnotations.gif "an example showing custom annotations") - -### Custom shapes - -Draw custom shapes on the map the same way you would a custom `UIView` or `CALayer`. These shapes keep their geographic scale and are perfect for visualizing everything from indoor floor plans to metro systems to hurricane tracks. - -## Next steps - -Check out the [iOS code examples](https://www.mapbox.com/ios-sdk/examples/runtime-toggle-layer/) to learn more about how to use runtime styling in your own apps. - -## Resources - -* [Information for style authors](for-style-authors.html) -* [Mapbox Streets source reference](https://www.mapbox.com/vector-tiles/mapbox-streets-v7/) -* [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/) -* [Mapbox Studio](https://www.mapbox.com/mapbox-studio/) -* [iOS code examples](https://www.mapbox.com/ios-sdk/examples/) diff --git a/platform/ios/docs/guides/Working with Mapbox Studio.md b/platform/ios/docs/guides/Working with Mapbox Studio.md deleted file mode 100644 index 232b165efd..0000000000 --- a/platform/ios/docs/guides/Working with Mapbox Studio.md +++ /dev/null @@ -1,96 +0,0 @@ -# Working with Mapbox Studio - -[Mapbox Studio’s Styles editor](http://mapbox.com/studio) is Mapbox’s tool for creating custom map styles. It also serves as an excellent tool for rapidly prototyping dynamic maps and [runtime styling](runtime-styling.html) interactions for iOS. - -## Creating a base style - -Start by heading to [mapbox.com/studio](https://www.mapbox.com/studio) and creating a new style. Any style that’s close to what you’ll be using in your app is ideal. - -## Prototyping with data - -The goal in using Mapbox Studio for prototyping runtime styling implementations is to test data presentation assumptions as quickly as possible. With the Mapbox Studio tools, you can import a small subset of your own real data, fake data as a placeholder, or prototype with existing Mapbox data. - -### Prototyping with Mapbox data -The default [Mapbox Streets tileset](https://www.mapbox.com/studio/tilesets/mapbox.mapbox-streets-v7/) might offer data similar to your own that you can use to style before you swap in your own data at runtime. - -For example, if you’re looking to prototype points of interest, consider the `poi_label` layer; if you want to style GPS traces, the `roads` layer might be a good proxy. Take a look at what’s available in [Mapbox Streets](https://www.mapbox.com/studio/tilesets/mapbox.mapbox-streets-v7/): there’s probably a layer that closely matches your data. - -### Importing real data -If you can’t find a good approximation for your data in Mapbox Streets, consider uploading a small subset of your data into Mapbox Studio as a custom tileset. - -From the [Mapbox Studio Dashboard](https://www.mapbox.com/studio/), click `Tilesets` in the sidebar, then click `New Tileset` to get started with most common geo file formats including KML, GPX, GeoJSON, Shapefiles, and CSV. - -### Faking placeholder data -If you don’t have any custom data on hand in a format that works easily with the Tileset importer, you can fake placeholder data with the Dataset Editor. - -From the [Mapbox Studio Dashboard](https://www.mapbox.com/studio/), click `Datasets` in the sidebar, then click on `New Dataset` to get started. - -Zoom into your desired location and use the draw tools on the left to start creating a set of sample data. - -![create shapes](img/studio-workflow/create-polygons.gif) - -Next, add data properties you’d like to use to drive your style. Consider categorical properties or numeric properties that you’d use to filter and group your data. Text properties can be used to display icons or labels. - -![add properties](img/studio-workflow/add-properties.gif) - -**General Guidelines:** - -* Text along a line: add line with a text property -* Text at specific points on a line or polygon: in addition to the line, create points at the specific points you’d like with text properties -* If you want circles where scale doesn’t matter relative to the geography (e.g. always 20 pixels), you can add as a point and style with a circle layer or a symbol -* If you want circles or arcs where the scale matters (e.g. 10 mile radius), you’ll need to approximately freehand a polygon that you can create more precisely later in code. - -When you’re done, save your dataset and export as a tileset. When that’s complete, add your tileset to your style. - -### Import into your style - -1. Click `New Layer` -2. Select your tileset -3. Select your shape type: - * `Symbol`: best for text and icons - * `Line`: best for lines or adding strokes to polygons - * `Fill`: best for filling polygons - * `Circle`: for styling points or nodes along a line or polygon as circles. If you need circles of a fixed radius (e.g. 1 mile radius), you should model your data as a polygon. -4. Add filters if necessary - * You can selectively filter your data by their properties to group and style separately -5. Click on `Create Layer` - -## Styling with Mapbox Studio - -Mapbox Studio shines for styling your data and the process is much faster than attempting to style natively. - -There are some nuances to understand between the different layer types and how they work together. Don’t be afraid to use the layers sidebar to peek into the techniques used to style the stock Mapbox maps. You can duplicate these layers, re-point the source to your own data, and tweak as needed. - -**Best Practices:** - -* Layers are cheap, so duplicate and update filters liberally. -* If you’d like to stroke polygons you’ll need to use two layers: one a fill and one a stroked line. -* If you want to stroke a line, create two layers, one for the default stroke and one with a wider width for its casing -* If you intend to animate properties or transition between values, consider creating separate layers for each state and toggling visibility to visualize the difference. - -## Implement on iOS with runtime styling - -Once you’re happy with the styles you’ve created, it’s time to [get setup with Mapbox in your app](https://www.mapbox.com/ios-sdk/). - -To implement your prototypes with runtime styling: - -1. Implement `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]`. -2. Add your real data as a source: - * This can be done using vector data from tileset editor ([example](https://www.mapbox.com/ios-sdk/examples/dds-circle-layer)), custom vector tiles, added as GeoJSON ([example](https://www.mapbox.com/ios-sdk/examples/runtime-add-line), or added manually through the app via `MGLShapeSource` ([example](https://www.mapbox.com/ios-sdk/examples/runtime-multiple-annotations)) -3. For each layer you’ve prototyped in Studio, add its corresponding `MGLStyleLayer` subclass. See [“Configuring the map content’s appearance”](for-style-authors.html#configuring-the-map-content-s-appearance) for the available style layer classes. - -**Translating style attributes from Studio** -For each property you’ve edited in Studio, you can hover over the property name to find the corresponding property in the iOS SDK. It’ll generally be the camelCased version of the Property ID, but see [“Configuring the map content’s appearance”](for-style-authors.html#configuring-the-map-content-s-appearance) for a table of properties that differ between Mapbox Studio and the iOS SDK. - -![property values](img/studio-workflow/property-values.png) - -**Translating stop functions** -It’s possible to use stop functions in Mapbox Studio to transition the style of a layer by its zoom level (e.g. a line that gets wider as you zoom in). These can be translated in the mobile SDKs using `+[MGLSyleValue valueWithInterpolationBase:stops:]`. The rate of change between stops in Studio is represented by `interpolationBase`. - -![Stop functions](img/studio-workflow/stop-functions.png) - -## Resources - -* [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/) -* [Mapbox Studio](https://www.mapbox.com/mapbox-studio/) -* [iOS code examples](https://www.mapbox.com/ios-sdk/examples/) diff --git a/platform/ios/docs/img/adding-points-to-a-map/annotation-image.png b/platform/ios/docs/img/adding-points-to-a-map/annotation-image.png deleted file mode 100644 index b9aa946363..0000000000 Binary files a/platform/ios/docs/img/adding-points-to-a-map/annotation-image.png and /dev/null differ diff --git a/platform/ios/docs/img/adding-points-to-a-map/annotation-view.png b/platform/ios/docs/img/adding-points-to-a-map/annotation-view.png deleted file mode 100644 index 90c181f664..0000000000 Binary files a/platform/ios/docs/img/adding-points-to-a-map/annotation-view.png and /dev/null differ diff --git a/platform/ios/docs/img/adding-points-to-a-map/circle-layer.png b/platform/ios/docs/img/adding-points-to-a-map/circle-layer.png deleted file mode 100644 index 5edf88e0da..0000000000 Binary files a/platform/ios/docs/img/adding-points-to-a-map/circle-layer.png and /dev/null differ diff --git a/platform/ios/docs/img/adding-points-to-a-map/symbol-layer.png b/platform/ios/docs/img/adding-points-to-a-map/symbol-layer.png deleted file mode 100644 index cff39b0bce..0000000000 Binary files a/platform/ios/docs/img/adding-points-to-a-map/symbol-layer.png and /dev/null differ diff --git a/platform/ios/docs/img/runtime-styling/CustomAnnotations.gif b/platform/ios/docs/img/runtime-styling/CustomAnnotations.gif deleted file mode 100644 index 71d4c4a8a0..0000000000 Binary files a/platform/ios/docs/img/runtime-styling/CustomAnnotations.gif and /dev/null differ diff --git a/platform/ios/docs/img/runtime-styling/DynamicStyles.gif b/platform/ios/docs/img/runtime-styling/DynamicStyles.gif deleted file mode 100644 index 8854474ede..0000000000 Binary files a/platform/ios/docs/img/runtime-styling/DynamicStyles.gif and /dev/null differ diff --git a/platform/ios/docs/img/runtime-styling/Emoji.gif b/platform/ios/docs/img/runtime-styling/Emoji.gif deleted file mode 100644 index afb7a42693..0000000000 Binary files a/platform/ios/docs/img/runtime-styling/Emoji.gif and /dev/null differ diff --git a/platform/ios/docs/img/runtime-styling/HexBins.gif b/platform/ios/docs/img/runtime-styling/HexBins.gif deleted file mode 100644 index 6078ac9e8d..0000000000 Binary files a/platform/ios/docs/img/runtime-styling/HexBins.gif and /dev/null differ diff --git a/platform/ios/docs/img/runtime-styling/Population.gif b/platform/ios/docs/img/runtime-styling/Population.gif deleted file mode 100644 index 8de14e6422..0000000000 Binary files a/platform/ios/docs/img/runtime-styling/Population.gif and /dev/null differ diff --git a/platform/ios/docs/img/runtime-styling/SnowLevels.gif b/platform/ios/docs/img/runtime-styling/SnowLevels.gif deleted file mode 100644 index 463e0398d2..0000000000 Binary files a/platform/ios/docs/img/runtime-styling/SnowLevels.gif and /dev/null differ diff --git a/platform/ios/docs/img/studio-workflow/add-properties.gif b/platform/ios/docs/img/studio-workflow/add-properties.gif deleted file mode 100644 index 6cab64c050..0000000000 Binary files a/platform/ios/docs/img/studio-workflow/add-properties.gif and /dev/null differ diff --git a/platform/ios/docs/img/studio-workflow/create-polygons.gif b/platform/ios/docs/img/studio-workflow/create-polygons.gif deleted file mode 100644 index 6383dd31df..0000000000 Binary files a/platform/ios/docs/img/studio-workflow/create-polygons.gif and /dev/null differ diff --git a/platform/ios/docs/img/studio-workflow/property-values.png b/platform/ios/docs/img/studio-workflow/property-values.png deleted file mode 100644 index 2b85db80d6..0000000000 Binary files a/platform/ios/docs/img/studio-workflow/property-values.png and /dev/null differ diff --git a/platform/ios/docs/img/studio-workflow/stop-functions.png b/platform/ios/docs/img/studio-workflow/stop-functions.png deleted file mode 100644 index 8480cb2d53..0000000000 Binary files a/platform/ios/docs/img/studio-workflow/stop-functions.png and /dev/null differ -- cgit v1.2.1 From bee605e0639666e89c12ec941fd7636eeece3c6d Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Tue, 14 Aug 2018 13:13:19 -0700 Subject: Edit link --- platform/ios/docs/guides/For Style Authors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md index 9d240045b3..9548926a4c 100644 --- a/platform/ios/docs/guides/For Style Authors.md +++ b/platform/ios/docs/guides/For Style Authors.md @@ -41,7 +41,7 @@ Studio, especially when multitasking is enabled. Your user’s viewing distance may be shorter than on a desktop computer. Some of your users may use the Larger Dynamic Type and Accessibility Text features to increase the size of all text on the device. You can use the -[runtime styling API](https://www.mapbox.com/ios-sdk/maps/overview/runtime-styling/) to adjust your style’s +[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s to adjust your style’s font and icon sizes accordingly. Design sprite images and choose font weights that look crisp on both -- cgit v1.2.1 From b8a1b13420544d55f90e58cd8d7fd659eed4464e Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Tue, 14 Aug 2018 13:23:01 -0700 Subject: Fix typo --- platform/ios/docs/guides/For Style Authors.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md index 9548926a4c..b8e3a16889 100644 --- a/platform/ios/docs/guides/For Style Authors.md +++ b/platform/ios/docs/guides/For Style Authors.md @@ -41,8 +41,7 @@ Studio, especially when multitasking is enabled. Your user’s viewing distance may be shorter than on a desktop computer. Some of your users may use the Larger Dynamic Type and Accessibility Text features to increase the size of all text on the device. You can use the -[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s to adjust your style’s -font and icon sizes accordingly. +[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s font and icon sizes accordingly. Design sprite images and choose font weights that look crisp on both standard-resolution displays and Retina displays. This SDK supports the same -- cgit v1.2.1 From 9bd23a73621464e9197293ff61419359ac58ee1e Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Tue, 14 Aug 2018 13:57:33 -0700 Subject: Update darwin docs --- platform/darwin/docs/guides/For Style Authors.md.ejs | 2 +- platform/darwin/docs/guides/Migrating to Expressions.md.ejs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs index b8112d6fec..24cb256297 100644 --- a/platform/darwin/docs/guides/For Style Authors.md.ejs +++ b/platform/darwin/docs/guides/For Style Authors.md.ejs @@ -148,7 +148,7 @@ represented at runtime by an `MGLStyle` object, which provides access to various layers, respectively. <% if (iOS) { -%> For more information about the capabilities exposed by the runtime styling API, -see “[Runtime Styling](runtime-styling.html)”. +see “[Runtime Styling](https://www.mapbox.com/ios-sdk/maps/overview/runtime-styling/)”. <% } -%> The names of runtime styling classes and properties on <%- os %> are generally diff --git a/platform/darwin/docs/guides/Migrating to Expressions.md.ejs b/platform/darwin/docs/guides/Migrating to Expressions.md.ejs index addbf6940e..cd68fd5944 100644 --- a/platform/darwin/docs/guides/Migrating to Expressions.md.ejs +++ b/platform/darwin/docs/guides/Migrating to Expressions.md.ejs @@ -12,7 +12,7 @@ # Migrating from Style Functions to Expressions -[Runtime Styling](runtime-styling.html) enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Developers can specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source. +[Runtime Styling](https://www.mapbox.com/ios-sdk/maps/overview/runtime-styling/ enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Developers can specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source. With Mapbox Maps SDK for <%- iOS ? 'iOS v4.0.0' : 'macOS v0.7.0' %>, style functions have been replaced with expressions. These provide even more tools for developers who want to style their maps dynamically. This guide outlines some tips for migrating from style functions to expressions, and offers an overview of some things that developers can do with expressions. @@ -91,7 +91,7 @@ Current syntax: If you previously used an interpolation base greater than `0` (other than `1`), you can use `MGLExpressionInterpolationMode.exponential` as the curve type for `+[NSExpression(MGLAdditions) mgl_expressionForInterpolatingExpression:withCurveType:parameters:stops:]` or `'exponential'` as the curve type for [`mgl_interpolate:withCurveType:parameters:stops:`](predicates-and-expressions.html#code-mgl_interpolate-withcurvetype-parameters-stops-code). The `parameters` argument takes that interpolation base. This interpolates between values exponentially, creating an accelerated ramp effect. -Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](working-with-mapbox-studio.html)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. +Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio]((https://www.mapbox.com/ios-sdk/maps/overview/mapbox-studio/)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. -- cgit v1.2.1 From 04705f436482606f8b8c1df6d0eb6a16a8069f97 Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Tue, 14 Aug 2018 14:19:21 -0700 Subject: Addiional darwin fixes and Jazzy template updates --- platform/darwin/docs/guides/For Style Authors.md.ejs | 3 +-- platform/darwin/docs/guides/Migrating to Expressions.md.ejs | 4 ++-- platform/ios/jazzy.yml | 3 --- platform/macos/docs/guides/Migrating to Expressions.md | 4 ++-- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs index 24cb256297..906892b525 100644 --- a/platform/darwin/docs/guides/For Style Authors.md.ejs +++ b/platform/darwin/docs/guides/For Style Authors.md.ejs @@ -56,8 +56,7 @@ Studio, especially when multitasking is enabled. Your user’s viewing distance may be shorter than on a desktop computer. Some of your users may use the Larger Dynamic Type and Accessibility Text features to increase the size of all text on the device. You can use the -[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s -font and icon sizes accordingly. +[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s font and icon sizes accordingly. <% } -%> Design sprite images and choose font weights that look crisp on both diff --git a/platform/darwin/docs/guides/Migrating to Expressions.md.ejs b/platform/darwin/docs/guides/Migrating to Expressions.md.ejs index cd68fd5944..dfd4ba4834 100644 --- a/platform/darwin/docs/guides/Migrating to Expressions.md.ejs +++ b/platform/darwin/docs/guides/Migrating to Expressions.md.ejs @@ -12,7 +12,7 @@ # Migrating from Style Functions to Expressions -[Runtime Styling](https://www.mapbox.com/ios-sdk/maps/overview/runtime-styling/ enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Developers can specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source. +[Runtime Styling](https://www.mapbox.com/ios-sdk/maps/overview/runtime-styling/) enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Developers can specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source. With Mapbox Maps SDK for <%- iOS ? 'iOS v4.0.0' : 'macOS v0.7.0' %>, style functions have been replaced with expressions. These provide even more tools for developers who want to style their maps dynamically. This guide outlines some tips for migrating from style functions to expressions, and offers an overview of some things that developers can do with expressions. @@ -91,7 +91,7 @@ Current syntax: If you previously used an interpolation base greater than `0` (other than `1`), you can use `MGLExpressionInterpolationMode.exponential` as the curve type for `+[NSExpression(MGLAdditions) mgl_expressionForInterpolatingExpression:withCurveType:parameters:stops:]` or `'exponential'` as the curve type for [`mgl_interpolate:withCurveType:parameters:stops:`](predicates-and-expressions.html#code-mgl_interpolate-withcurvetype-parameters-stops-code). The `parameters` argument takes that interpolation base. This interpolates between values exponentially, creating an accelerated ramp effect. -Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio]((https://www.mapbox.com/ios-sdk/maps/overview/mapbox-studio/)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. +Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](https://www.mapbox.com/ios-sdk/maps/overview/mapbox-studio/)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml index f995cc06cd..a6823519e6 100644 --- a/platform/ios/jazzy.yml +++ b/platform/ios/jazzy.yml @@ -17,9 +17,6 @@ framework_root: ../darwin/src custom_categories: - name: Guides children: - - Adding Markers to a Map - - Runtime Styling - - Working with Mapbox Studio - Working with GeoJSON Data - Predicates and Expressions - Migrating to Expressions diff --git a/platform/macos/docs/guides/Migrating to Expressions.md b/platform/macos/docs/guides/Migrating to Expressions.md index e8d038dbb0..361f1b3e4c 100644 --- a/platform/macos/docs/guides/Migrating to Expressions.md +++ b/platform/macos/docs/guides/Migrating to Expressions.md @@ -5,7 +5,7 @@ # Migrating from Style Functions to Expressions -[Runtime Styling](runtime-styling.html) enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Developers can specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source. +[Runtime Styling](https://www.mapbox.com/ios-sdk/maps/overview/runtime-styling/) enables you to modify every aspect of the map’s appearance dynamically as a user interacts with your application. Developers can specify in advance how a layout or paint attribute will vary as the zoom level changes or how the appearance of individual features vary based on metadata provided by a content source. With Mapbox Maps SDK for macOS v0.7.0, style functions have been replaced with expressions. These provide even more tools for developers who want to style their maps dynamically. This guide outlines some tips for migrating from style functions to expressions, and offers an overview of some things that developers can do with expressions. @@ -113,7 +113,7 @@ mapView.style?.insertLayer(layer, below: symbolLayer) If you previously used an interpolation base greater than `0` (other than `1`), you can use `MGLExpressionInterpolationMode.exponential` as the curve type for `+[NSExpression(MGLAdditions) mgl_expressionForInterpolatingExpression:withCurveType:parameters:stops:]` or `'exponential'` as the curve type for [`mgl_interpolate:withCurveType:parameters:stops:`](predicates-and-expressions.html#code-mgl_interpolate-withcurvetype-parameters-stops-code). The `parameters` argument takes that interpolation base. This interpolates between values exponentially, creating an accelerated ramp effect. -Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](working-with-mapbox-studio.html)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. +Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](https://www.mapbox.com/ios-sdk/maps/overview/mapbox-studio/)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. -- cgit v1.2.1 From 66a09b924f92529993f65f964d6e9f392937fe77 Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Tue, 14 Aug 2018 14:52:36 -0700 Subject: Fix line break --- platform/darwin/docs/guides/For Style Authors.md.ejs | 3 ++- platform/ios/docs/guides/For Style Authors.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs index 906892b525..940c9b1042 100644 --- a/platform/darwin/docs/guides/For Style Authors.md.ejs +++ b/platform/darwin/docs/guides/For Style Authors.md.ejs @@ -56,7 +56,8 @@ Studio, especially when multitasking is enabled. Your user’s viewing distance may be shorter than on a desktop computer. Some of your users may use the Larger Dynamic Type and Accessibility Text features to increase the size of all text on the device. You can use the -[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s font and icon sizes accordingly. +[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s + font and icon sizes accordingly. <% } -%> Design sprite images and choose font weights that look crisp on both diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md index b8e3a16889..af575d7461 100644 --- a/platform/ios/docs/guides/For Style Authors.md +++ b/platform/ios/docs/guides/For Style Authors.md @@ -41,7 +41,8 @@ Studio, especially when multitasking is enabled. Your user’s viewing distance may be shorter than on a desktop computer. Some of your users may use the Larger Dynamic Type and Accessibility Text features to increase the size of all text on the device. You can use the -[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s font and icon sizes accordingly. +[runtime styling API](#manipulating-the-style-at-runtime) to adjust your style’s + font and icon sizes accordingly. Design sprite images and choose font weights that look crisp on both standard-resolution displays and Retina displays. This SDK supports the same -- cgit v1.2.1 From 41169403a2e2208424197d1b9573ee999de85d8f Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Tue, 14 Aug 2018 14:58:29 -0700 Subject: Rename link title --- platform/darwin/docs/guides/Migrating to Expressions.md.ejs | 2 +- platform/ios/docs/guides/Migrating to Expressions.md | 2 +- platform/macos/docs/guides/Migrating to Expressions.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/darwin/docs/guides/Migrating to Expressions.md.ejs b/platform/darwin/docs/guides/Migrating to Expressions.md.ejs index dfd4ba4834..3ea5b33d73 100644 --- a/platform/darwin/docs/guides/Migrating to Expressions.md.ejs +++ b/platform/darwin/docs/guides/Migrating to Expressions.md.ejs @@ -91,7 +91,7 @@ Current syntax: If you previously used an interpolation base greater than `0` (other than `1`), you can use `MGLExpressionInterpolationMode.exponential` as the curve type for `+[NSExpression(MGLAdditions) mgl_expressionForInterpolatingExpression:withCurveType:parameters:stops:]` or `'exponential'` as the curve type for [`mgl_interpolate:withCurveType:parameters:stops:`](predicates-and-expressions.html#code-mgl_interpolate-withcurvetype-parameters-stops-code). The `parameters` argument takes that interpolation base. This interpolates between values exponentially, creating an accelerated ramp effect. -Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](https://www.mapbox.com/ios-sdk/maps/overview/mapbox-studio/)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. +Here’s a visualization from Mapbox Studio (see [Mapbox Studio and iOS](https://www.mapbox.com/ios-sdk/maps/overview/mapbox-studio/)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. diff --git a/platform/ios/docs/guides/Migrating to Expressions.md b/platform/ios/docs/guides/Migrating to Expressions.md index b0965ee999..d92aab0ffc 100644 --- a/platform/ios/docs/guides/Migrating to Expressions.md +++ b/platform/ios/docs/guides/Migrating to Expressions.md @@ -113,7 +113,7 @@ mapView.style?.insertLayer(layer, below: symbolLayer) If you previously used an interpolation base greater than `0` (other than `1`), you can use `MGLExpressionInterpolationMode.exponential` as the curve type for `+[NSExpression(MGLAdditions) mgl_expressionForInterpolatingExpression:withCurveType:parameters:stops:]` or `'exponential'` as the curve type for [`mgl_interpolate:withCurveType:parameters:stops:`](predicates-and-expressions.html#code-mgl_interpolate-withcurvetype-parameters-stops-code). The `parameters` argument takes that interpolation base. This interpolates between values exponentially, creating an accelerated ramp effect. -Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](https://www.mapbox.com/ios-sdk/maps/overview/mapbox-studio/)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. +Here’s a visualization from Mapbox Studio (see [Mapbox Studio and iOS](https://www.mapbox.com/ios-sdk/maps/overview/mapbox-studio/)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. diff --git a/platform/macos/docs/guides/Migrating to Expressions.md b/platform/macos/docs/guides/Migrating to Expressions.md index 361f1b3e4c..44e14a6eec 100644 --- a/platform/macos/docs/guides/Migrating to Expressions.md +++ b/platform/macos/docs/guides/Migrating to Expressions.md @@ -113,7 +113,7 @@ mapView.style?.insertLayer(layer, below: symbolLayer) If you previously used an interpolation base greater than `0` (other than `1`), you can use `MGLExpressionInterpolationMode.exponential` as the curve type for `+[NSExpression(MGLAdditions) mgl_expressionForInterpolatingExpression:withCurveType:parameters:stops:]` or `'exponential'` as the curve type for [`mgl_interpolate:withCurveType:parameters:stops:`](predicates-and-expressions.html#code-mgl_interpolate-withcurvetype-parameters-stops-code). The `parameters` argument takes that interpolation base. This interpolates between values exponentially, creating an accelerated ramp effect. -Here’s a visualization from Mapbox Studio (see [Working with Mapbox Studio](https://www.mapbox.com/ios-sdk/maps/overview/mapbox-studio/)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. +Here’s a visualization from Mapbox Studio (see [Mapbox Studio and iOS](https://www.mapbox.com/ios-sdk/maps/overview/mapbox-studio/)) comparing interpolation base values of `1.5` and `0.5` based on zoom. In order to convert camera style functions, use `$zoomLevel` or `MGL_FUNCTION('zoomLevel')` as the attribute key. -- cgit v1.2.1 From c96d9df798b9baba5134f4d22127b9ba044742b4 Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Tue, 14 Aug 2018 15:25:00 -0700 Subject: Guides -> Appendices --- platform/ios/jazzy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml index a6823519e6..84ca50ed48 100644 --- a/platform/ios/jazzy.yml +++ b/platform/ios/jazzy.yml @@ -15,7 +15,7 @@ umbrella_header: src/Mapbox.h framework_root: ../darwin/src custom_categories: - - name: Guides + - name: Appendices children: - Working with GeoJSON Data - Predicates and Expressions -- cgit v1.2.1 From a3b6fc149895a7f4c29acd6bba70546edec41438 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 10 Aug 2018 10:22:38 -0400 Subject: [build] vendor std::expected polyfill --- include/mbgl/util/expected.hpp | 16 + scripts/vendor/expected.sh | 13 + vendor/expected/LICENSE.txt | 23 + vendor/expected/files.txt | 1 + vendor/expected/include/expected.hpp | 1708 ++++++++++++++++++++++++++++++++++ vendor/expected/version.txt | 1 + 6 files changed, 1762 insertions(+) create mode 100644 include/mbgl/util/expected.hpp create mode 100755 scripts/vendor/expected.sh create mode 100644 vendor/expected/LICENSE.txt create mode 100644 vendor/expected/files.txt create mode 100644 vendor/expected/include/expected.hpp create mode 100644 vendor/expected/version.txt diff --git a/include/mbgl/util/expected.hpp b/include/mbgl/util/expected.hpp new file mode 100644 index 0000000000..a45f071065 --- /dev/null +++ b/include/mbgl/util/expected.hpp @@ -0,0 +1,16 @@ +#pragma once + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wshadow" +#include +#pragma GCC diagnostic pop + +namespace mbgl { + +template +using expected = nonstd::expected; + +template +using unexpected = nonstd::unexpected_type; + +} // namespace mbgl diff --git a/scripts/vendor/expected.sh b/scripts/vendor/expected.sh new file mode 100755 index 0000000000..58c98902f6 --- /dev/null +++ b/scripts/vendor/expected.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +source "$(dirname "${BASH_SOURCE[0]}")/common.sh" + +NAME=expected +VERSION=a2359cf61478d735a308e952b1c9840714f61386 +ROOT=expected-lite-$VERSION + +download "https://github.com/martinmoene/expected-lite/archive/$VERSION.tar.gz" +init +extract "$ROOT/include" "$ROOT/LICENSE.txt" +mv include/nonstd/expected.hpp include +rm -rf include/nonstd +file_list include -name "*.hpp" diff --git a/vendor/expected/LICENSE.txt b/vendor/expected/LICENSE.txt new file mode 100644 index 0000000000..36b7cd93cd --- /dev/null +++ b/vendor/expected/LICENSE.txt @@ -0,0 +1,23 @@ +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/vendor/expected/files.txt b/vendor/expected/files.txt new file mode 100644 index 0000000000..258044be9a --- /dev/null +++ b/vendor/expected/files.txt @@ -0,0 +1 @@ +include/expected.hpp diff --git a/vendor/expected/include/expected.hpp b/vendor/expected/include/expected.hpp new file mode 100644 index 0000000000..70298d7237 --- /dev/null +++ b/vendor/expected/include/expected.hpp @@ -0,0 +1,1708 @@ +// This version targets C++11 and later. +// +// Copyright (C) 2016-2018 Martin Moene. +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// expected lite is based on: +// A proposal to add a utility class to represent expected monad +// by Vicente J. Botet Escriba and Pierre Talbot. http:://wg21.link/p0323 + +#ifndef NONSTD_EXPECTED_LITE_HPP +#define NONSTD_EXPECTED_LITE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define expected_lite_VERSION "0.1.0" + +// expected-lite configuration +// +// DXXXXR0: -- +// N4015 : -2 (2014-05-26) +// N4109 : -1 (2014-06-29) +// P0323R0: 0 (2016-05-28) +// P0323R1: 1 (2016-10-12) +// -------: +// P0323R2: 2 (2017-06-15) +// P0323R3: 3 (2017-10-15) +// P0323R4: 4 (2017-11-26) +// P0323R5: 5 (2018-02-08) +// +// expected-lite uses 2 and higher + +#ifndef nsel_P0323R +# define nsel_P0323R 5 +#endif + +// Compiler detection (C++20 is speculative): +// Note: MSVC supports C++14 since it supports C++17. + +#ifdef _MSVC_LANG +# define type_MSVC_LANG _MSVC_LANG +#else +# define type_MSVC_LANG 0 +#endif + +#define type_CPP11 (__cplusplus == 201103L ) +#define nsel_CPP11_OR_GREATER (__cplusplus >= 201103L || type_MSVC_LANG >= 201103L ) +#define nsel_CPP14_OR_GREATER (__cplusplus >= 201402L || type_MSVC_LANG >= 201703L ) +#define nsel_CPP17_OR_GREATER (__cplusplus >= 201703L || type_MSVC_LANG >= 201703L ) +#define nsel_CPP20_OR_GREATER (__cplusplus >= 202000L || type_MSVC_LANG >= 202000L ) + +#if nsel_CPP14_OR_GREATER +# define nsel_constexpr14 constexpr +#else +# define nsel_constexpr14 /*constexpr*/ +#endif + +#if nsel_CPP17_OR_GREATER +# define nsel_inline17 inline +#else +# define nsel_inline17 /*inline*/ +#endif + +// Method enabling + +#define nsel_REQUIRES(...) \ + typename std::enable_if<__VA_ARGS__, void*>::type = 0 + +#define nsel_REQUIRES_0(...) \ + template< bool B = (__VA_ARGS__), typename std::enable_if::type = 0 > + +#define nsel_REQUIRES_T(...) \ + typename = typename std::enable_if< (__VA_ARGS__), nonstd::expected_detail::enabler >::type + +// Clang, GNUC, MSVC warning suppression macros: + +#if defined(_MSC_VER) && !defined(__clang__) +# define nsel_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900)) ) +#else +# define nsel_COMPILER_MSVC_VERSION 0 +#endif + +#ifdef __clang__ +# pragma clang diagnostic push +#elif defined __GNUC__ +# pragma GCC diagnostic push +#endif // __clang__ + +#if nsel_COMPILER_MSVC_VERSION >= 140 +# pragma warning( push ) +# define nsel_DISABLE_MSVC_WARNINGS(codes) __pragma( warning(disable: codes) ) +#else +# define nsel_DISABLE_MSVC_WARNINGS(codes) +#endif + +#ifdef __clang__ +# define nsel_RESTORE_WARNINGS() _Pragma("clang diagnostic pop") +#elif defined __GNUC__ +# define nsel_RESTORE_WARNINGS() _Pragma("GCC diagnostic pop") +#elif nsel_COMPILER_MSVC_VERSION >= 140 +# define nsel_RESTORE_WARNINGS() __pragma( warning( pop ) ) +#else +# define nsel_RESTORE_WARNINGS() +#endif + +// Suppress the following MSVC (GSL) warnings: +// - C26409: Avoid calling new and delete explicitly, use std::make_unique instead (r.11) + +nsel_DISABLE_MSVC_WARNINGS( 26409 ) + +namespace nonstd { + +namespace std20 { + +// type traits C++20: + +template< typename T > +struct remove_cvref +{ + typedef typename std::remove_cv< typename std::remove_reference::type >::type type; +}; + +} // namespace std20 + +// forward declaration: + +template< typename T, typename E > +class expected; + +namespace expected_detail { + +/// for nsel_REQUIRES_T + +enum class enabler{}; + +/// discriminated union to hold value or 'error'. + +template< typename T, typename E > +union storage_t +{ + friend class expected; + +private: + using value_type = T; + using error_type = E; + + // no-op construction + storage_t() {} + ~storage_t() {} + + void construct_value( value_type const & v ) + { + new( &m_value ) value_type( v ); + } + + void construct_value( value_type && v ) + { + new( &m_value ) value_type( std::move( v ) ); + } + + void destruct_value() + { + m_value.~value_type(); + } + + void construct_error( error_type const & e ) + { + new( &m_error ) error_type( e ); + } + + void construct_error( error_type && e ) + { + new( &m_error ) error_type( std::move( e ) ); + } + + void destruct_error() + { + m_error.~error_type(); + } + + constexpr value_type const & value() const & + { + return m_value; + } + + value_type & value() & + { + return m_value; + } + + constexpr value_type const && value() const && + { + return std::move( m_value ); + } + + nsel_constexpr14 value_type && value() && + { + return std::move( m_value ); + } + + value_type const * value_ptr() const + { + return &m_value; + } + + value_type * value_ptr() + { + return &m_value; + } + + error_type const & error() const + { + return m_error; + } + + error_type & error() + { + return m_error; + } + +private: + value_type m_value; + error_type m_error; +}; + +/// discriminated union to hold only 'error'. + +template< typename E > +union storage_t +{ + friend class expected; + +private: + using value_type = void; + using error_type = E; + + // no-op construction + storage_t() {} + ~storage_t() {} + + void construct_error( error_type const & e ) + { + new( &m_error ) error_type( e ); + } + + void construct_error( error_type && e ) + { + new( &m_error ) error_type( std::move( e ) ); + } + + void destruct_error() + { + m_error.~error_type(); + } + + error_type const & error() const + { + return m_error; + } + + error_type & error() + { + return m_error; + } + +private: + error_type m_error; +}; + +} // namespace expected_detail + +/// // x.x.3 Unexpected object type; unexpected_type; C++17 and later can also use aliased type unexpected. + +#if nsel_P0323R <= 2 +template< typename E = std::exception_ptr > +class unexpected_type +#else +template< typename E > +class unexpected_type +#endif // nsel_P0323R +{ +public: + using error_type = E; + + unexpected_type() = delete; + constexpr unexpected_type( unexpected_type const &) = default; + constexpr unexpected_type( unexpected_type &&) = default; + nsel_constexpr14 unexpected_type& operator=( unexpected_type const &) = default; + nsel_constexpr14 unexpected_type& operator=( unexpected_type &&) = default; + + template< typename E2, nsel_REQUIRES_T( + std::is_constructible::value ) + > + constexpr explicit unexpected_type( E2 && error ) + : m_error( std::forward( error ) ) + {} + + template< typename E2 > + constexpr explicit unexpected_type( unexpected_type const & error, nsel_REQUIRES( + std::is_constructible::value + && !std::is_convertible::value /*=> explicit */ ) + ) + : m_error( error ) + {} + + template< typename E2 > + constexpr /*non-explicit*/ unexpected_type( unexpected_type const & error, nsel_REQUIRES( + std::is_constructible::value + && std::is_convertible::value /*=> non-explicit */ ) + ) + : m_error( error ) + {} + + template< typename E2 > + constexpr explicit unexpected_type( unexpected_type && error, nsel_REQUIRES( + std::is_constructible::value + && !std::is_convertible::value /*=> explicit */ ) + ) + : m_error( error ) + {} + + template< typename E2 > + constexpr /*non-explicit*/ unexpected_type( unexpected_type && error, nsel_REQUIRES( + std::is_constructible::value + && std::is_convertible::value /*=> non-explicit */ ) + ) + : m_error( error ) + {} + + nsel_constexpr14 E & value() & noexcept + { + return m_error; + } + + constexpr E const & value() const & noexcept + { + return m_error; + } + + nsel_constexpr14 E && value() && noexcept + { + return std::move( m_error ); + } + + constexpr E const && value() const && noexcept + { + return std::move( m_error ); + } + +// , nsel_REQUIRES( +// std::is_move_constructible::value +// && std::is_swappable::value ) + + void swap( unexpected_type & rhs ) noexcept ( +#if nsel_CPP17_OR_GREATER + std::is_nothrow_move_constructible::value + && std::is_nothrow_swappable::value +#else + std::is_nothrow_move_constructible::value + && noexcept ( std::swap( std::declval(), std::declval() ) ) +#endif + ) + { + using std::swap; + swap( m_error, rhs.m_error ); + } + +private: + error_type m_error; +}; + +/// class unexpected_type, std::exception_ptr specialization (P0323R2) + +#if nsel_P0323R <= 2 + +template<> +class unexpected_type< std::exception_ptr > +{ +public: + using error_type = std::exception_ptr; + + unexpected_type() = delete; + + ~unexpected_type(){} + + explicit unexpected_type( std::exception_ptr const & error ) + : m_error( error ) + {} + + explicit unexpected_type(std::exception_ptr && error ) + : m_error( std::move( error ) ) + {} + + template< typename E > + explicit unexpected_type( E error ) + : m_error( std::make_exception_ptr( error ) ) + {} + + std::exception_ptr const & value() const + { + return m_error; + } + + std::exception_ptr & value() + { + return m_error; + } + +private: + std::exception_ptr m_error; +}; + +#endif // nsel_P0323R + +/// x.x.4, Unexpected equality operators + +template< typename E > +constexpr bool operator==( unexpected_type const & x, unexpected_type const & y ) +{ + return x.value() == y.value(); +} + +template< typename E > +constexpr bool operator!=( unexpected_type const & x, unexpected_type const & y ) +{ + return ! ( x == y ); +} + +#if nsel_P0323R <= 2 + +template< typename E > +constexpr bool operator<( unexpected_type const & x, unexpected_type const & y ) +{ + return x.value() < y.value(); +} + +template< typename E > +constexpr bool operator>( unexpected_type const & x, unexpected_type const & y ) +{ + return ( y < x ); +} + +template< typename E > +constexpr bool operator<=( unexpected_type const & x, unexpected_type const & y ) +{ + return ! ( y < x ); +} + +template< typename E > +constexpr bool operator>=( unexpected_type const & x, unexpected_type const & y ) +{ + return ! ( x < y ); +} + +/// x.x.5 Specialized algorithms + +template< typename E > +void swap( unexpected_type & x, unexpected_type & y) noexcept ( noexcept ( x.swap(y) ) ) +{ + x.swap( y ); +} + +// unexpected: relational operators for std::exception_ptr: + +inline constexpr bool operator<( unexpected_type const & /*x*/, unexpected_type const & /*y*/ ) +{ + return false; +} + +inline constexpr bool operator>( unexpected_type const & /*x*/, unexpected_type const & /*y*/ ) +{ + return false; +} + +inline constexpr bool operator<=( unexpected_type const & x, unexpected_type const & y ) +{ + return ( x == y ); +} + +inline constexpr bool operator>=( unexpected_type const & x, unexpected_type const & y ) +{ + return ( x == y ); +} + +#endif // nsel_P0323R + +// unexpected: traits + +#if nsel_P0323R <= 3 + +template +struct is_unexpected : std::false_type {}; + +template +struct is_unexpected< unexpected_type > : std::true_type {}; + +#endif // nsel_P0323R + +// unexpected: factory + +// keep make_unexpected() removed in p0323r2 for pre-C++17: + +template< typename E> +nsel_constexpr14 auto +make_unexpected( E && v) -> unexpected_type< typename std::decay::type > +{ + return unexpected_type< typename std::decay::type >( v ); +} + +#if nsel_P0323R <= 3 + +/*nsel_constexpr14*/ auto inline +make_unexpected_from_current_exception() -> unexpected_type< std::exception_ptr > +{ + return unexpected_type< std::exception_ptr >( std::current_exception() ); +} + +#endif // nsel_P0323R + +/// in-place tag: construct a value in-place (should come from std::experimental::optional) + +struct in_place_t{}; + +nsel_inline17 constexpr in_place_t in_place{}; + +/// unexpect tag, in_place_unexpected tag: construct an error + +struct unexpect_t{}; +using in_place_unexpected_t = unexpect_t; + +nsel_inline17 constexpr unexpect_t unexpect{}; +nsel_inline17 constexpr unexpect_t in_place_unexpected{}; + +/// expected access error + +template< typename E > +class bad_expected_access; + +template <> +class bad_expected_access< void > : public std::exception +{ +public: + explicit bad_expected_access() + : std::exception() + {} +}; + +template< typename E > +class bad_expected_access : public bad_expected_access< void > +{ +public: + using error_type = E; + + explicit bad_expected_access( error_type error ) + : m_error( error ) + {} + + virtual char const * what() const noexcept override + { + return "bad_expected_access"; + } + + nsel_constexpr14 error_type & error() & + { + return m_error; + } + + constexpr error_type const & error() const & + { + return m_error; + } + + nsel_constexpr14 error_type && error() && + { + return std::move( m_error ); + } + + constexpr error_type const && error() const && + { + return std::move( m_error ); + } + +private: + error_type m_error; +}; + +/// class error_traits + +template< typename Error > +struct error_traits +{ + static void rethrow( Error const & e ) + { + throw bad_expected_access{ e }; + } +}; + +template<> +struct error_traits< std::exception_ptr > +{ + static void rethrow( std::exception_ptr const & e ) + { + std::rethrow_exception( e ); + } +}; + +template<> +struct error_traits< std::error_code > +{ + static void rethrow( std::error_code const & e ) + { + throw std::system_error( e ); + } +}; + +/// class expected + +#if nsel_P0323R <= 2 +template< typename T, typename E = std::exception_ptr > +class expected +#else +template< typename T, typename E > +class expected +#endif // nsel_P0323R +{ +public: + using value_type = T; + using error_type = E; + using unexpected_type = nonstd::unexpected_type; + + template< typename U > + struct rebind + { + using type = expected; + }; + + // x.x.4.1 constructors + + nsel_REQUIRES_0( + std::is_default_constructible::value + ) + nsel_constexpr14 expected() noexcept + ( + std::is_nothrow_default_constructible::value + ) + : has_value_( true ) + { + contained.construct_value( value_type() ); + } + + nsel_constexpr14 expected( expected const & rhs +// , nsel_REQUIRES( +// std::is_copy_constructible::value +// && std::is_copy_constructible::value ) + ) + : has_value_( rhs.has_value_ ) + { + if ( has_value() ) contained.construct_value( rhs.contained.value() ); + else contained.construct_error( rhs.contained.error() ); + } + + nsel_constexpr14 expected( expected && rhs +// , nsel_REQUIRES( +// std::is_move_constructible::value +// && std::is_move_constructible::value ) + ) noexcept ( + std::is_nothrow_move_constructible::value + && std::is_nothrow_move_constructible::value + ) + : has_value_( rhs.has_value_ ) + { + if ( has_value() ) contained.construct_value( std::move( rhs.contained.value() ) ); + else contained.construct_error( std::move( rhs.contained.error() ) ); + } + + template< typename U, typename G > + nsel_constexpr14 explicit expected( expected const & rhs, nsel_REQUIRES( + std::is_constructible::value + && std::is_constructible::value + && !std::is_constructible&>::value + && !std::is_constructible&&>::value + && !std::is_constructible&>::value + && !std::is_constructible&&>::value + && !std::is_convertible&, T>::value + && !std::is_convertible&&, T>::value + && !std::is_convertible&, T>::value + && !std::is_convertible&&, T>::value + && (!std::is_convertible::value || !std::is_convertible::value ) /*=> explicit */ ) + ) + : has_value_( rhs.has_value_ ) + { + if ( has_value() ) contained.construct_value( rhs.contained.value() ); + else contained.construct_error( rhs.contained.error() ); + } + + template< typename U, typename G > + nsel_constexpr14 /*non-explicit*/ expected( expected const & rhs, nsel_REQUIRES( + std::is_constructible::value + && std::is_constructible::value + && !std::is_constructible&>::value + && !std::is_constructible&&>::value + && !std::is_constructible&>::value + && !std::is_constructible&&>::value + && !std::is_convertible&, T>::value + && !std::is_convertible&&, T>::value + && !std::is_convertible&, T>::value + && !std::is_convertible&&, T>::value + && !(!std::is_convertible::value || !std::is_convertible::value ) /*=> explicit */ ) + ) + : has_value_( rhs.has_value_ ) + { + if ( has_value() ) contained.construct_value( rhs.contained.value() ); + else contained.construct_error( rhs.contained.error() ); + } + + template< typename U, typename G > + nsel_constexpr14 explicit expected( expected && rhs, nsel_REQUIRES( + std::is_constructible::value + && std::is_constructible::value + && !std::is_constructible&>::value + && !std::is_constructible&&>::value + && !std::is_constructible&>::value + && !std::is_constructible&&>::value + && !std::is_convertible&, T>::value + && !std::is_convertible&&, T>::value + && !std::is_convertible&, T>::value + && !std::is_convertible&&, T>::value + && (!std::is_convertible::value || !std::is_convertible::value ) /*=> explicit */ ) + ) + : has_value_( rhs.has_value_ ) + { + if ( has_value() ) contained.construct_value( std::move( rhs.contained.value() ) ); + else contained.construct_error( std::move( rhs.contained.error() ) ); + } + + template< typename U, typename G > + nsel_constexpr14 /*non-explicit*/ expected( expected && rhs, nsel_REQUIRES( + std::is_constructible::value + && std::is_constructible::value + && !std::is_constructible&>::value + && !std::is_constructible&&>::value + && !std::is_constructible&>::value + && !std::is_constructible&&>::value + && !std::is_convertible&, T>::value + && !std::is_convertible&&, T>::value + && !std::is_convertible&, T>::value + && !std::is_convertible&&, T>::value + && !(!std::is_convertible::value || !std::is_convertible::value ) /*=> non-explicit */ ) + ) + : has_value_( rhs.has_value_ ) + { + if ( has_value() ) contained.construct_value( std::move( rhs.contained.value() ) ); + else contained.construct_error( std::move( rhs.contained.error() ) ); + } + + nsel_constexpr14 expected( value_type const & v +// , nsel_REQUIRES( +// std::is_copy_constructible::value ) + ) + : has_value_( true ) + { + contained.construct_value( v ); + } + + template< typename U = T > + nsel_constexpr14 explicit expected( U && v, nsel_REQUIRES( + std::is_constructible::value + && !std::is_same::type, in_place_t>::value + && !std::is_same, typename std20::remove_cvref::type>::value + && !std::is_same, typename std20::remove_cvref::type>::value + && !std::is_convertible::value /*=> explicit */ +) + ) noexcept + ( + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value + ) + : has_value_( true ) + { + contained.construct_value( std::forward( v ) ); + } + + template< typename U = T > + nsel_constexpr14 expected( U && v, nsel_REQUIRES( + std::is_constructible::value + && !std::is_same::type, in_place_t>::value + && !std::is_same, typename std20::remove_cvref::type>::value + && !std::is_same, typename std20::remove_cvref::type>::value + && std::is_convertible::value /*=> non-explicit */ +) + ) noexcept + ( + std::is_nothrow_move_constructible::value && + std::is_nothrow_move_constructible::value + ) + : has_value_( true ) + { + contained.construct_value( std::forward( v ) ); + } + + template ::value ) > + + nsel_constexpr14 explicit expected( in_place_t, Args&&... args ) + : has_value_( true ) + { + contained.construct_value( std::forward( args )... ); + } + + template< typename U, typename... Args, nsel_REQUIRES_T( + std::is_constructible, Args&&...>::value ) > + + nsel_constexpr14 explicit expected( in_place_t, std::initializer_list il, Args&&... args ) + : has_value_( true ) + { + contained.construct_value( il, std::forward( args )... ); + } + + template< typename G = E > + nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error, nsel_REQUIRES( + !std::is_convertible::value /*=> explicit */ ) + ) + : has_value_( false ) + { + contained.construct_error( error.value() ); + } + + template< typename G = E > + nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error, nsel_REQUIRES( + std::is_convertible::value /*=> non-explicit */ ) + ) + : has_value_( false ) + { + contained.construct_error( error.value() ); + } + + template< typename G = E > + nsel_constexpr14 explicit expected( nonstd::unexpected_type && error, nsel_REQUIRES( + !std::is_convertible::value /*=> explicit */ ) + ) + : has_value_( false ) + { + contained.construct_error( std::move( error.value() ) ); + } + + template< typename G = E > + nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error, nsel_REQUIRES( + std::is_convertible::value /*=> non-explicit */ ) + ) + : has_value_( false ) + { + contained.construct_error( std::move( error.value() ) ); + } + + template< typename... Args, nsel_REQUIRES_T( + std::is_constructible::value ) + > + nsel_constexpr14 explicit expected( unexpect_t, Args&&... args ) + : has_value_( false ) + { + contained.construct_error( std::forward( args )... ); + } + + template< typename U, typename... Args, nsel_REQUIRES_T( + std::is_constructible, Args&&...>::value ) + > + nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list il, Args&&... args ) + : has_value_( false ) + { + contained.construct_error( il, std::forward( args )... ); + } + + // x.x.4.2 destructor + + ~expected() + { + if ( has_value() ) contained.destruct_value(); + else contained.destruct_error(); + } + + // x.x.4.3 assignment + +// nsel_REQUIRES( +// std::is_copy_constructible::value && +// std::is_copy_assignable::value && +// std::is_copy_constructible::value && +// std::is_copy_assignable::value ) + + expected operator=( expected const & rhs ) + { + expected( rhs ).swap( *this ); + return *this; + } + +// nsel_REQUIRES( +// std::is_move_constructible::value && +// std::is_move_assignable::value && +// std::is_move_constructible::value && +// std::is_move_assignable::value ) + + expected & operator=( expected && rhs ) noexcept + ( + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_constructible::value&& + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_constructible::value ) + { + expected( std::move( rhs ) ).swap( *this ); + return *this; + } + + template< typename U, nsel_REQUIRES_T( + std::is_constructible::value && + std::is_assignable::value ) > + + expected & operator=( U && v ) + { + expected( std::forward( v ) ).swap( *this ); + return *this; + } + +// nsel_REQUIRES( +// std::is_copy_constructible::value && +// std::is_assignable::value ) + + expected & operator=( unexpected_type const & u ) + { + expected( std::move( u ) ).swap( *this ); + return *this; + } + +// nsel_REQUIRES( +// std::is_copy_constructible::value && +// std::is_assignable::value ) + + expected & operator=( unexpected_type && u ) + { + expected( std::move( u ) ).swap( *this ); + return *this; + } + + template< typename... Args, nsel_REQUIRES_T( + std::is_constructible::value ) > + + void emplace( Args &&... args ) + { + expected( in_place, std::forward(args)... ).swap( *this ); + } + + template< typename U, typename... Args, nsel_REQUIRES_T( + std::is_constructible&, Args&&...>::value ) > + + void emplace( std::initializer_list il, Args &&... args ) + { + expected( in_place, il, std::forward(args)... ).swap( *this ); + } + + // x.x.4.4 swap + +// nsel_REQUIRES( +// std::is_move_constructible::value && +// std::is_move_constructible::value ) + + void swap( expected & rhs ) noexcept + ( +#if nsel_CPP17_OR_GREATER + std::is_nothrow_move_constructible::value && std::is_nothrow_swappable::value && + std::is_nothrow_move_constructible::value && std::is_nothrow_swappable::value +#else + std::is_nothrow_move_constructible::value && noexcept ( std::swap( std::declval(), std::declval() ) ) && + std::is_nothrow_move_constructible::value && noexcept ( std::swap( std::declval(), std::declval() ) ) +#endif + ) + { + using std::swap; + + if ( bool(*this) && bool(rhs) ) { swap( contained.value(), rhs.contained.value() ); } + else if ( ! bool(*this) && ! bool(rhs) ) { swap( contained.error(), rhs.contained.error() ); } + else if ( bool(*this) && ! bool(rhs) ) { error_type t( std::move( rhs.error() ) ); + rhs.contained.destruct_error(); + rhs.contained.construct_value( std::move( contained.value() ) ); + contained.destruct_value(); + contained.construct_error( std::move( t ) ); + swap( has_value_, rhs.has_value_ ); } + else if ( ! bool(*this) && bool(rhs) ) { rhs.swap( *this ); } + } + + // x.x.4.5 observers + + constexpr value_type const * operator ->() const + { + return assert( has_value() ), contained.value_ptr(); + } + + value_type * operator ->() + { + return assert( has_value() ), contained.value_ptr(); + } + + constexpr value_type const & operator *() const & + { + return assert( has_value() ), contained.value(); + } + + value_type & operator *() & + { + return assert( has_value() ), contained.value(); + } + + constexpr value_type const && operator *() const && + { + return assert( has_value() ), std::move( contained.value() ); + } + + nsel_constexpr14 value_type && operator *() && + { + return assert( has_value() ), std::move( contained.value() ); + } + + constexpr explicit operator bool() const noexcept + { + return has_value(); + } + + constexpr bool has_value() const noexcept + { + return has_value_; + } + + constexpr value_type const & value() const & + { + return has_value() + ? ( contained.value() ) + : ( error_traits::rethrow( contained.error() ), contained.value() ); + } + + value_type & value() & + { + return has_value() + ? ( contained.value() ) + : ( error_traits::rethrow( contained.error() ), contained.value() ); + } + + constexpr value_type const && value() const && + { + return std::move( has_value() + ? ( contained.value() ) + : ( error_traits::rethrow( contained.error() ), contained.value() ) ); + } + + nsel_constexpr14 value_type && value() && + { + return std::move( has_value() + ? ( contained.value() ) + : ( error_traits::rethrow( contained.error() ), contained.value() ) ); + } + + constexpr error_type const & error() const & + { + return assert( ! has_value() ), contained.error(); + } + + error_type & error() & + { + return assert( ! has_value() ), contained.error(); + } + + constexpr error_type const && error() const && + { + return assert( ! has_value() ), std::move( contained.error() ); + } + + error_type && error() && + { + return assert( ! has_value() ), std::move( contained.error() ); + } + + constexpr unexpected_type get_unexpected() const + { + return make_unexpected( contained.error() ); + } + + template< typename Ex > + bool has_exception() const + { + using ContainedEx = typename std::remove_reference< decltype( get_unexpected().value() ) >::type; + return ! has_value() && std::is_base_of< Ex, ContainedEx>::value; + } + + template< typename U, nsel_REQUIRES_T( + std::is_copy_constructible::value && + std::is_convertible::value ) > + + value_type value_or( U && v ) const & + { + return has_value() + ? contained.value() + : static_cast( std::forward( v ) ); + } + + template< typename U, nsel_REQUIRES_T( + std::is_move_constructible::value && + std::is_convertible::value ) > + + value_type value_or( U && v ) && + { + return has_value() + ? std::move( contained.value() ) + : static_cast( std::forward( v ) ); + } + + // unwrap() + +// template +// constexpr expected expected,E>::unwrap() const&; + +// template +// constexpr expected expected::unwrap() const&; + +// template +// expected expected, E>::unwrap() &&; + +// template +// template expected expected::unwrap() &&; + + // factories + +// template +// expected catch_exception(F&& f); + +// template +// expected())),E> map(F&& func) ; + +// template +// 'see below' bind(F&& func); + +// template +// expected catch_error(F&& f); + +// template +// 'see below' then(F&& func); + +private: + bool has_value_; + expected_detail::storage_t contained; +}; + +/// class expected, void specialization + +template< typename E > +class expected +{ +public: + using value_type = void; + using error_type = E; + using unexpected_type = nonstd::unexpected_type; + + // x.x.4.1 constructors + + constexpr expected() noexcept + : has_value_( true ) + { + } + + nsel_constexpr14 expected( expected const & rhs ) + : has_value_( rhs.has_value_ ) + { + if ( ! has_value() ) contained.construct_error( rhs.contained.error() ); + } + + nsel_REQUIRES_0( + std::is_move_constructible::value ) + + nsel_constexpr14 expected( expected && rhs ) noexcept + ( + true // TBD - see also non-void specialization + ) + : has_value_( rhs.has_value_ ) + { + if ( ! has_value() ) contained.construct_error( std::move( rhs.contained.error() ) ); + } + + constexpr explicit expected( in_place_t ) + : has_value_( true ) + { + } + + template< typename G = E > + nsel_constexpr14 explicit expected( nonstd::unexpected_type const & error, nsel_REQUIRES( + !std::is_convertible::value /*=> explicit */ ) + ) + : has_value_( false ) + { + contained.construct_error( error.value() ); + } + + template< typename G = E > + nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type const & error, nsel_REQUIRES( + std::is_convertible::value /*=> non-explicit */ ) + ) + : has_value_( false ) + { + contained.construct_error( error.value() ); + } + + template< typename G = E > + nsel_constexpr14 explicit expected( nonstd::unexpected_type && error, nsel_REQUIRES( + !std::is_convertible::value /*=> explicit */ ) + ) + : has_value_( false ) + { + contained.construct_error( std::move( error.value() ) ); + } + + template< typename G = E > + nsel_constexpr14 /*non-explicit*/ expected( nonstd::unexpected_type && error, nsel_REQUIRES( + std::is_convertible::value /*=> non-explicit */ ) + ) + : has_value_( false ) + { + contained.construct_error( std::move( error.value() ) ); + } + + template< typename... Args, nsel_REQUIRES_T( + std::is_constructible::value ) + > + nsel_constexpr14 explicit expected( unexpect_t, Args&&... args ) + : has_value_( false ) + { + contained.construct_error( std::forward( args )... ); + } + + template< typename U, typename... Args, nsel_REQUIRES_T( + std::is_constructible, Args&&...>::value ) + > + nsel_constexpr14 explicit expected( unexpect_t, std::initializer_list il, Args&&... args ) + : has_value_( false ) + { + contained.construct_error( il, std::forward( args )... ); + } + + + // destructor + + ~expected() + { + if ( ! has_value() ) contained.destruct_error(); + } + + // x.x.4.3 assignment + +// nsel_REQUIRES( +// std::is_copy_constructible::value && +// std::is_copy_assignable::value ) + + expected & operator=( expected const & rhs ) + { + expected( rhs ).swap( *this ); + return *this; + } + +// nsel_REQUIRES( +// std::is_move_constructible::value && +// std::is_move_assignable::value ) + + expected & operator=( expected && rhs ) noexcept + ( + std::is_nothrow_move_assignable::value && + std::is_nothrow_move_constructible::value ) + { + expected( std::move( rhs ) ).swap( *this ); + return *this; + } + + void emplace() + {} + + // x.x.4.4 swap + +// nsel_REQUIRES( +// std::is_move_constructible::value ) + + void swap( expected & rhs ) noexcept + ( +#if nsel_CPP17_OR_GREATER + std::is_nothrow_move_constructible::value && std::is_nothrow_swappable::value +#else + std::is_nothrow_move_constructible::value && noexcept ( std::swap( std::declval(), std::declval() ) ) +#endif + ) + { + using std::swap; + + if ( ! bool(*this) && ! bool(rhs) ) { swap( contained.error(), rhs.contained.error() ); } + else if ( bool(*this) && ! bool(rhs) ) { contained.construct_error( std::move( rhs.error() ) ); + swap( has_value_, rhs.has_value_ ); } + else if ( ! bool(*this) && bool(rhs) ) { rhs.swap( *this ); } + } + + // x.x.4.5 observers + + constexpr explicit operator bool() const noexcept + { + return has_value(); + } + + constexpr bool has_value() const noexcept + { + return has_value_; + } + + void value() const + {} + + constexpr error_type const & error() const & + { + return assert( ! has_value() ), contained.error(); + } + + error_type & error() & + { + return assert( ! has_value() ), contained.error(); + } + + constexpr error_type const && error() const && + { + return assert( ! has_value() ), std::move( contained.error() ); + } + + error_type && error() && + { + return assert( ! has_value() ), std::move( contained.error() ); + } + + constexpr unexpected_type get_unexpected() const + { + return make_unexpected( contained.error() ); + } + + template + bool has_exception() const + { + return ! has_value() && std::is_base_of< Ex, decltype( get_unexpected().value() ) >::value; + } + +// template constexpr 'see below' unwrap() const&; +// +// template 'see below' unwrap() &&; + + // factories + +// template +// expected catch_exception(F&& f); +// +// template +// expected map(F&& func) ; +// +// template +// 'see below' bind(F&& func) ; +// +// template +// expected catch_error(F&& f); +// +// template +// 'see below' then(F&& func); + +private: + bool has_value_; + expected_detail::storage_t contained; +}; + +// expected: relational operators + +template +constexpr bool operator==( expected const & x, expected const & y ) +{ + return bool(x) != bool(y) ? false : bool(x) == false ? true : *x == *y; +} + +template +constexpr bool operator!=( expected const & x, expected const & y ) +{ + return !(x == y); +} + +template +constexpr bool operator<( expected const & x, expected const & y ) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template +constexpr bool operator>( expected const & x, expected const & y ) +{ + return (y < x); +} + +template +constexpr bool operator<=( expected const & x, expected const & y ) +{ + return !(y < x); +} + +template +constexpr bool operator>=( expected const & x, expected const & y ) +{ + return !(x < y); +} + +// expected: comparison with unexpected_type + +template +constexpr bool operator==( expected const & x, unexpected_type const & u ) +{ + return (!x) ? x.get_unexpected() == u : false; +} + +template +constexpr bool operator==( unexpected_type const & u, expected const & x ) +{ + return ( x == u ); +} + +template +constexpr bool operator!=( expected const & x, unexpected_type const & u ) +{ + return ! ( x == u ); +} + +template +constexpr bool operator!=( unexpected_type const & u, expected const & x ) +{ + return ! ( x == u ); +} + +template +constexpr bool operator<( expected const & x, unexpected_type const & u ) +{ + return (!x) ? ( x.get_unexpected() < u ) : false; +} + +#if nsel_P0323R <= 2 + +template +constexpr bool operator<( unexpected_type const & u, expected const & x ) +{ + return (!x) ? ( u < x.get_unexpected() ) : true ; +} + +template +constexpr bool operator>( expected const & x, unexpected_type const & u ) +{ + return ( u < x ); +} + +template +constexpr bool operator>( unexpected_type const & u, expected const & x ) +{ + return ( x < u ); +} + +template +constexpr bool operator<=( expected const & x, unexpected_type const & u ) +{ + return ! ( u < x ); +} + +template +constexpr bool operator<=( unexpected_type const & u, expected const & x) +{ + return ! ( x < u ); +} + +template +constexpr bool operator>=( expected const & x, unexpected_type const & u ) +{ + return ! ( u > x ); +} + +template +constexpr bool operator>=( unexpected_type const & u, expected const & x ) +{ + return ! ( x > u ); +} + +#endif // nsel_P0323R + +// expected: comparison with T + +template +constexpr bool operator==( expected const & x, T const & v ) +{ + return bool(x) ? *x == v : false; +} + +template +constexpr bool operator==(T const & v, expected const & x ) +{ + return bool(x) ? v == *x : false; +} + +template +constexpr bool operator!=( expected const & x, T const & v ) +{ + return bool(x) ? *x != v : true; +} + +template +constexpr bool operator!=( T const & v, expected const & x ) +{ + return bool(x) ? v != *x : true; +} + +template +constexpr bool operator<( expected const & x, T const & v ) +{ + return bool(x) ? *x < v : true; +} + +template +constexpr bool operator<( T const & v, expected const & x ) +{ + return bool(x) ? v < *x : false; +} + +template +constexpr bool operator>( T const & v, expected const & x ) +{ + return bool(x) ? *x < v : false; +} + +template +constexpr bool operator>( expected const & x, T const & v ) +{ + return bool(x) ? v < *x : false; +} + +template +constexpr bool operator<=( T const & v, expected const & x ) +{ + return bool(x) ? ! ( *x < v ) : false; +} + +template +constexpr bool operator<=( expected const & x, T const & v ) +{ + return bool(x) ? ! ( v < *x ) : true; +} + +template +constexpr bool operator>=( expected const & x, T const & v ) +{ + return bool(x) ? ! ( *x < v ) : false; +} + +template +constexpr bool operator>=( T const & v, expected const & x ) +{ + return bool(x) ? ! ( v < *x ) : true; +} + +/// x.x.x Specialized algorithms + +template< typename T, typename E > +void swap( expected & x, expected & y ) noexcept ( noexcept ( x.swap(y) ) ) +{ + x.swap( y ); +} + +#if nsel_P0323R <= 3 + +template< typename T> +constexpr auto make_expected( T && v ) -> expected< typename std::decay::type > +{ + return expected< typename std::decay::type >( std::forward( v ) ); +} + +// expected specialization: + +auto inline make_expected() -> expected +{ + return expected( in_place ); +} + +template< typename T> +constexpr auto make_expected_from_current_exception() -> expected +{ + return expected( make_unexpected_from_current_exception() ); +} + +template< typename T> +auto make_expected_from_exception( std::exception_ptr v ) -> expected +{ + return expected( unexpected_type( std::forward( v ) ) ); +} + +template< typename T, typename E > +constexpr auto make_expected_from_error( E e ) -> expected::type> +{ + return expected::type>( make_unexpected( e ) ); +} + +template< typename F > +/*nsel_constexpr14*/ +auto make_expected_from_call( F f, + nsel_REQUIRES( ! std::is_same::type, void>::value ) +) -> expected< typename std::result_of::type > +{ + try + { + return make_expected( f() ); + } + catch (...) + { + return make_unexpected_from_current_exception(); + } +} + +template< typename F > +/*nsel_constexpr14*/ +auto make_expected_from_call( F f, + nsel_REQUIRES( std::is_same::type, void>::value ) +) -> expected +{ + try + { + f(); + return make_expected(); + } + catch (...) + { + return make_unexpected_from_current_exception(); + } +} + +#endif // nsel_P0323R + +} // namespace nonstd + +namespace std { + +// expected: hash support + +template< typename T, typename E > +struct hash< nonstd::expected > +{ + using result_type = typename hash::result_type; + using argument_type = nonstd::expected; + + constexpr result_type operator()(argument_type const & arg) const + { + return arg ? std::hash{}(*arg) : result_type{}; + } +}; + +// TBD - ?? remove? see spec. +template< typename T, typename E > +struct hash< nonstd::expected > +{ + using result_type = typename hash::result_type; + using argument_type = nonstd::expected; + + constexpr result_type operator()(argument_type const & arg) const + { + return arg ? std::hash{}(*arg) : result_type{}; + } +}; + +// TBD - implement +// bool(e), hash>()(e) shall evaluate to the hashing true; +// otherwise it evaluates to an unspecified value if E is exception_ptr or +// a combination of hashing false and hash()(e.error()). + +template< typename E > +struct hash< nonstd::expected > +{ +}; + +} // namespace std + + +namespace nonstd { + +// void unexpected() is deprecated && removed in C++17 + +#if nsel_CPP17_OR_GREATER && nsel_COMPILER_MSVC_VERSION > 141 +template< typename E > +using unexpected = unexpected_type; +#endif + +} // namespace nonstd + +#undef nsel_REQUIRES +#undef nsel_REQUIRES_0 +#undef nsel_REQUIRES_T + +nsel_RESTORE_WARNINGS() + +#endif // NONSTD_EXPECTED_LITE_HPP diff --git a/vendor/expected/version.txt b/vendor/expected/version.txt new file mode 100644 index 0000000000..52e4107440 --- /dev/null +++ b/vendor/expected/version.txt @@ -0,0 +1 @@ +a2359cf61478d735a308e952b1c9840714f61386 -- cgit v1.2.1 From fa7b70945fe6927536869d7dd66de0834d1e8002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Wed, 13 Jun 2018 15:50:23 +0200 Subject: [core] harden OfflineDatabase --- cmake/test-files.cmake | 2 + include/mbgl/storage/offline.hpp | 2 +- platform/default/default_file_source.cpp | 28 +- platform/default/mbgl/storage/offline_database.cpp | 313 +++++++---- platform/default/mbgl/storage/offline_database.hpp | 24 +- platform/default/mbgl/storage/offline_download.cpp | 31 +- platform/default/sqlite3.cpp | 48 +- platform/qt/src/sqlite3.cpp | 12 +- test/fixtures/offline_database/corrupt-delayed.db | Bin 0 -> 19456 bytes .../fixtures/offline_database/corrupt-immediate.db | Bin 0 -> 4096 bytes test/src/mbgl/test/fixture_log_observer.cpp | 6 +- test/src/mbgl/test/sqlite3_test_fs.cpp | 320 +++++++++++ test/src/mbgl/test/sqlite3_test_fs.hpp | 39 ++ test/storage/offline_database.test.cpp | 592 +++++++++++++++------ test/storage/offline_download.test.cpp | 79 +-- test/storage/sqlite.test.cpp | 6 - 16 files changed, 1150 insertions(+), 352 deletions(-) create mode 100644 test/fixtures/offline_database/corrupt-delayed.db create mode 100644 test/fixtures/offline_database/corrupt-immediate.db create mode 100644 test/src/mbgl/test/sqlite3_test_fs.cpp create mode 100644 test/src/mbgl/test/sqlite3_test_fs.hpp diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake index 2a679fc40b..ff659b1cd1 100644 --- a/cmake/test-files.cmake +++ b/cmake/test-files.cmake @@ -95,6 +95,8 @@ set(MBGL_TEST_FILES test/src/mbgl/test/fixture_log_observer.hpp test/src/mbgl/test/getrss.cpp test/src/mbgl/test/getrss.hpp + test/src/mbgl/test/sqlite3_test_fs.cpp + test/src/mbgl/test/sqlite3_test_fs.hpp test/src/mbgl/test/stub_file_source.cpp test/src/mbgl/test/stub_file_source.hpp test/src/mbgl/test/stub_geometry_tile_feature.hpp diff --git a/include/mbgl/storage/offline.hpp b/include/mbgl/storage/offline.hpp index ef4a499e83..2193f8d09e 100644 --- a/include/mbgl/storage/offline.hpp +++ b/include/mbgl/storage/offline.hpp @@ -187,11 +187,11 @@ class OfflineRegion { public: // Move-only; not publicly constructible. OfflineRegion(OfflineRegion&&); - OfflineRegion& operator=(OfflineRegion&&); ~OfflineRegion(); OfflineRegion() = delete; OfflineRegion(const OfflineRegion&) = delete; + OfflineRegion& operator=(OfflineRegion&&) = delete; OfflineRegion& operator=(const OfflineRegion&) = delete; int64_t getID() const; diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp index f070121497..051e1b125c 100644 --- a/platform/default/default_file_source.cpp +++ b/platform/default/default_file_source.cpp @@ -74,9 +74,9 @@ public: } void getRegionStatus(int64_t regionID, std::function)> callback) { - try { - callback({}, getDownload(regionID).getStatus()); - } catch (...) { + if (auto download = getDownload(regionID)) { + callback({}, download->getStatus()); + } else { callback(std::current_exception(), {}); } } @@ -92,11 +92,15 @@ public: } void setRegionObserver(int64_t regionID, std::unique_ptr observer) { - getDownload(regionID).setObserver(std::move(observer)); + if (auto download = getDownload(regionID)) { + download->setObserver(std::move(observer)); + } } void setRegionDownloadState(int64_t regionID, OfflineRegionDownloadState state) { - getDownload(regionID).setState(state); + if (auto download = getDownload(regionID)) { + download->setState(state); + } } void request(AsyncRequest* req, Resource resource, ActorRef ref) { @@ -181,13 +185,19 @@ public: } private: - OfflineDownload& getDownload(int64_t regionID) { + OfflineDownload* getDownload(int64_t regionID) { auto it = downloads.find(regionID); if (it != downloads.end()) { - return *it->second; + return it->second.get(); + } + auto definition = offlineDatabase->getRegionDefinition(regionID); + if (!definition) { + return nullptr; } - return *downloads.emplace(regionID, - std::make_unique(regionID, offlineDatabase->getRegionDefinition(regionID), *offlineDatabase, onlineFileSource)).first->second; + + auto download = std::make_unique(regionID, std::move(*definition), + *offlineDatabase, onlineFileSource); + return downloads.emplace(regionID, std::move(download)).first->second.get(); } // shared so that destruction is done on the creating thread diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp index 8f7f0965f4..cfa7f52977 100644 --- a/platform/default/mbgl/storage/offline_database.cpp +++ b/platform/default/mbgl/storage/offline_database.cpp @@ -15,7 +15,14 @@ namespace mbgl { OfflineDatabase::OfflineDatabase(std::string path_, uint64_t maximumCacheSize_) : path(std::move(path_)), maximumCacheSize(maximumCacheSize_) { - ensureSchema(); + try { + initialize(); + } catch (const util::IOException& ex) { + handleError(ex, "open database"); + } catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "open database"); + } + // Assume that we can't open the database right now and work with an empty database object. } OfflineDatabase::~OfflineDatabase() { @@ -24,87 +31,71 @@ OfflineDatabase::~OfflineDatabase() { try { statements.clear(); db.reset(); - } catch (mapbox::sqlite::Exception& ex) { - Log::Error(Event::Database, (int)ex.code, ex.what()); + } catch (const util::IOException& ex) { + handleError(ex, "close database"); + } catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "close database"); } } -void OfflineDatabase::ensureSchema() { - auto result = mapbox::sqlite::Database::tryOpen(path, mapbox::sqlite::ReadWriteCreate); - if (result.is()) { - const auto& ex = result.get(); - if (ex.code == mapbox::sqlite::ResultCode::NotADB) { - // Corrupted; blow it away. - removeExisting(); - result = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadWriteCreate); - } else { - Log::Error(Event::Database, "Unexpected error connecting to database: %s", ex.what()); - throw ex; - } +void OfflineDatabase::initialize() { + assert(!db); + assert(statements.empty()); + + db = std::make_unique( + mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadWriteCreate)); + db->setBusyTimeout(Milliseconds::max()); + db->exec("PRAGMA foreign_keys = ON"); + + const auto userVersion = getPragma("PRAGMA user_version"); + switch (userVersion) { + case 0: + case 1: + // Newly created database, or old cache-only database; remove old table if it exists. + removeOldCacheTable(); + createSchema(); + return; + case 2: + migrateToVersion3(); + // fall through + case 3: + // Removed migration, see below. + // fall through + case 4: + migrateToVersion5(); + // fall through + case 5: + migrateToVersion6(); + // fall through + case 6: + // Happy path; we're done + return; + default: + // Downgrade: delete the database and try to reinitialize. + removeExisting(); + initialize(); } +} - try { - assert(result.is()); - db = std::make_unique(std::move(result.get())); - db->setBusyTimeout(Milliseconds::max()); - db->exec("PRAGMA foreign_keys = ON"); - - switch (userVersion()) { - case 0: - case 1: - // Newly created database, or old cache-only database; remove old table if it exists. - removeOldCacheTable(); - break; - case 2: - migrateToVersion3(); - // fall through - case 3: - case 4: - migrateToVersion5(); - // fall through - case 5: - migrateToVersion6(); - // fall through - case 6: - // happy path; we're done - return; - default: - // downgrade, delete the database - removeExisting(); - break; - } - } catch (const mapbox::sqlite::Exception& ex) { - // Unfortunately, SQLITE_NOTADB is not always reported upon opening the database. - // Apparently sometimes it is delayed until the first read operation. - if (ex.code == mapbox::sqlite::ResultCode::NotADB) { +void OfflineDatabase::handleError(const mapbox::sqlite::Exception& ex, const char* action) { + if (ex.code == mapbox::sqlite::ResultCode::NotADB || + ex.code == mapbox::sqlite::ResultCode::Corrupt) { + // Corrupted; delete database so that we have a clean slate for the next operation. + Log::Error(Event::Database, static_cast(ex.code), "Can't %s: %s", action, ex.what()); + try { removeExisting(); - } else { - throw; + } catch (const util::IOException& ioEx) { + handleError(ioEx, action); } - } - - try { - // When downgrading the database, or when the database is corrupt, we've deleted the old database handle, - // so we need to reopen it. - if (!db) { - db = std::make_unique(mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadWriteCreate)); - db->setBusyTimeout(Milliseconds::max()); - db->exec("PRAGMA foreign_keys = ON"); - } - - db->exec("PRAGMA auto_vacuum = INCREMENTAL"); - db->exec("PRAGMA journal_mode = DELETE"); - db->exec("PRAGMA synchronous = FULL"); - db->exec(offlineDatabaseSchema); - db->exec("PRAGMA user_version = 6"); - } catch (...) { - Log::Error(Event::Database, "Unexpected error creating database schema: %s", util::toString(std::current_exception()).c_str()); - throw; + } else { + // We treat the error as temporary, and pretend we have an inaccessible DB. + Log::Warning(Event::Database, static_cast(ex.code), "Can't %s: %s", action, ex.what()); } } -int OfflineDatabase::userVersion() { - return static_cast(getPragma("PRAGMA user_version")); +void OfflineDatabase::handleError(const util::IOException& ex, const char* action) { + // We failed to delete the database file. + Log::Error(Event::Database, ex.code, "Can't %s: %s", action, ex.what()); } void OfflineDatabase::removeExisting() { @@ -113,19 +104,28 @@ void OfflineDatabase::removeExisting() { statements.clear(); db.reset(); - try { - util::deleteFile(path); - } catch (util::IOException& ex) { - Log::Error(Event::Database, ex.code, ex.what()); - } + util::deleteFile(path); } void OfflineDatabase::removeOldCacheTable() { + assert(db); db->exec("DROP TABLE IF EXISTS http_cache"); db->exec("VACUUM"); } +void OfflineDatabase::createSchema() { + assert(db); + db->exec("PRAGMA auto_vacuum = INCREMENTAL"); + db->exec("PRAGMA journal_mode = DELETE"); + db->exec("PRAGMA synchronous = FULL"); + mapbox::sqlite::Transaction transaction(*db); + db->exec(offlineDatabaseSchema); + db->exec("PRAGMA user_version = 6"); + transaction.commit(); +} + void OfflineDatabase::migrateToVersion3() { + assert(db); db->exec("PRAGMA auto_vacuum = INCREMENTAL"); db->exec("VACUUM"); db->exec("PRAGMA user_version = 3"); @@ -138,12 +138,14 @@ void OfflineDatabase::migrateToVersion3() { // See: https://github.com/mapbox/mapbox-gl-native/pull/6320 void OfflineDatabase::migrateToVersion5() { + assert(db); db->exec("PRAGMA journal_mode = DELETE"); db->exec("PRAGMA synchronous = FULL"); db->exec("PRAGMA user_version = 5"); } void OfflineDatabase::migrateToVersion6() { + assert(db); mapbox::sqlite::Transaction transaction(*db); db->exec("ALTER TABLE resources ADD COLUMN must_revalidate INTEGER NOT NULL DEFAULT 0"); db->exec("ALTER TABLE tiles ADD COLUMN must_revalidate INTEGER NOT NULL DEFAULT 0"); @@ -152,6 +154,9 @@ void OfflineDatabase::migrateToVersion6() { } mapbox::sqlite::Statement& OfflineDatabase::getStatement(const char* sql) { + if (!db) { + initialize(); + } auto it = statements.find(sql); if (it == statements.end()) { it = statements.emplace(sql, std::make_unique(*db, sql)).first; @@ -159,9 +164,15 @@ mapbox::sqlite::Statement& OfflineDatabase::getStatement(const char* sql) { return *it->second; } -optional OfflineDatabase::get(const Resource& resource) { +optional OfflineDatabase::get(const Resource& resource) try { auto result = getInternal(resource); - return result ? result->first : optional(); + return result ? optional{ result->first } : nullopt; +} catch (const util::IOException& ex) { + handleError(ex, "read resource"); + return nullopt; +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "read resource"); + return nullopt; } optional> OfflineDatabase::getInternal(const Resource& resource) { @@ -182,11 +193,17 @@ optional OfflineDatabase::hasInternal(const Resource& resource) { } } -std::pair OfflineDatabase::put(const Resource& resource, const Response& response) { +std::pair OfflineDatabase::put(const Resource& resource, const Response& response) try { + if (!db) { + initialize(); + } mapbox::sqlite::Transaction transaction(*db, mapbox::sqlite::Transaction::Immediate); auto result = putInternal(resource, response, true); transaction.commit(); return result; +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "write resource"); + return { false, 0 }; } std::pair OfflineDatabase::putInternal(const Resource& resource, const Response& response, bool evict_) { @@ -227,11 +244,19 @@ std::pair OfflineDatabase::putInternal(const Resource& resource, optional> OfflineDatabase::getResource(const Resource& resource) { // Update accessed timestamp used for LRU eviction. - { + try { mapbox::sqlite::Query accessedQuery{ getStatement("UPDATE resources SET accessed = ?1 WHERE url = ?2") }; accessedQuery.bind(1, util::now()); accessedQuery.bind(2, resource.url); accessedQuery.run(); + } catch (const mapbox::sqlite::Exception& ex) { + if (ex.code == mapbox::sqlite::ResultCode::NotADB || + ex.code == mapbox::sqlite::ResultCode::Corrupt) { + throw; + } + + // If we don't have any indication that the database is corrupt, continue as usual. + Log::Warning(Event::Database, static_cast(ex.code), "Can't update timestamp: %s", ex.what()); } // clang-format off @@ -245,7 +270,7 @@ optional> OfflineDatabase::getResource(const Resou query.bind(1, resource.url); if (!query.run()) { - return {}; + return nullopt; } Response response; @@ -274,7 +299,7 @@ optional OfflineDatabase::hasResource(const Resource& resource) { mapbox::sqlite::Query query{ getStatement("SELECT length(data) FROM resources WHERE url = ?") }; query.bind(1, resource.url); if (!query.run()) { - return {}; + return nullopt; } return query.get>(0); @@ -366,7 +391,8 @@ bool OfflineDatabase::putResource(const Resource& resource, } optional> OfflineDatabase::getTile(const Resource::TileData& tile) { - { + // Update accessed timestamp used for LRU eviction. + try { // clang-format off mapbox::sqlite::Query accessedQuery{ getStatement( "UPDATE tiles " @@ -385,6 +411,13 @@ optional> OfflineDatabase::getTile(const Resource: accessedQuery.bind(5, tile.y); accessedQuery.bind(6, tile.z); accessedQuery.run(); + } catch (const mapbox::sqlite::Exception& ex) { + if (ex.code == mapbox::sqlite::ResultCode::NotADB || ex.code == mapbox::sqlite::ResultCode::Corrupt) { + throw; + } + + // If we don't have any indication that the database is corrupt, continue as usual. + Log::Warning(Event::Database, static_cast(ex.code), "Can't update timestamp: %s", ex.what()); } // clang-format off @@ -406,7 +439,7 @@ optional> OfflineDatabase::getTile(const Resource: query.bind(5, tile.z); if (!query.run()) { - return {}; + return nullopt; } Response response; @@ -450,7 +483,7 @@ optional OfflineDatabase::hasTile(const Resource::TileData& tile) { size.bind(5, tile.z); if (!size.run()) { - return {}; + return nullopt; } return size.get>(0); @@ -559,23 +592,30 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile, return true; } -std::vector OfflineDatabase::listRegions() { +std::vector OfflineDatabase::listRegions() try { mapbox::sqlite::Query query{ getStatement("SELECT id, definition, description FROM regions") }; - std::vector result; - while (query.run()) { - result.push_back(OfflineRegion( - query.get(0), - decodeOfflineRegionDefinition(query.get(1)), - query.get>(2))); + const auto id = query.get(0); + const auto definition = query.get(1); + const auto description = query.get>(2); + try { + OfflineRegion region(id, decodeOfflineRegionDefinition(definition), description); + result.emplace_back(std::move(region)); + } catch (const std::exception& ex) { + // Catch errors from malformed offline region definitions + // and skip them. + Log::Error(Event::General, "%s", ex.what()); + } } - return result; +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "list regions"); + return {}; } -OfflineRegion OfflineDatabase::createRegion(const OfflineRegionDefinition& definition, - const OfflineRegionMetadata& metadata) { +optional OfflineDatabase::createRegion(const OfflineRegionDefinition& definition, + const OfflineRegionMetadata& metadata) try { // clang-format off mapbox::sqlite::Query query{ getStatement( "INSERT INTO regions (definition, description) " @@ -585,11 +625,13 @@ OfflineRegion OfflineDatabase::createRegion(const OfflineRegionDefinition& defin query.bind(1, encodeOfflineRegionDefinition(definition)); query.bindBlob(2, metadata); query.run(); - return OfflineRegion(query.lastInsertRowId(), definition, metadata); +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "create region"); + return nullopt; } -OfflineRegionMetadata OfflineDatabase::updateMetadata(const int64_t regionID, const OfflineRegionMetadata& metadata) { +optional OfflineDatabase::updateMetadata(const int64_t regionID, const OfflineRegionMetadata& metadata) try { // clang-format off mapbox::sqlite::Query query{ getStatement( "UPDATE regions SET description = ?1 " @@ -600,9 +642,12 @@ OfflineRegionMetadata OfflineDatabase::updateMetadata(const int64_t regionID, co query.run(); return metadata; +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "update region metadata"); + return nullopt; } -void OfflineDatabase::deleteRegion(OfflineRegion&& region) { +void OfflineDatabase::deleteRegion(OfflineRegion&& region) try { { mapbox::sqlite::Query query{ getStatement("DELETE FROM regions WHERE id = ?") }; query.bind(1, region.getID()); @@ -610,13 +655,17 @@ void OfflineDatabase::deleteRegion(OfflineRegion&& region) { } evict(0); + assert(db); db->exec("PRAGMA incremental_vacuum"); // Ensure that the cached offlineTileCount value is recalculated. offlineMapboxTileCount = {}; +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "delete region"); + return; } -optional> OfflineDatabase::getRegionResource(int64_t regionID, const Resource& resource) { +optional> OfflineDatabase::getRegionResource(int64_t regionID, const Resource& resource) try { auto response = getInternal(resource); if (response) { @@ -624,9 +673,12 @@ optional> OfflineDatabase::getRegionResource(int64 } return response; +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "read region resource"); + return nullopt; } -optional OfflineDatabase::hasRegionResource(int64_t regionID, const Resource& resource) { +optional OfflineDatabase::hasRegionResource(int64_t regionID, const Resource& resource) try { auto response = hasInternal(resource); if (response) { @@ -634,29 +686,52 @@ optional OfflineDatabase::hasRegionResource(int64_t regionID, const Res } return response; +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "query region resource"); + return nullopt; } -uint64_t OfflineDatabase::putRegionResource(int64_t regionID, const Resource& resource, const Response& response) { +uint64_t OfflineDatabase::putRegionResource(int64_t regionID, + const Resource& resource, + const Response& response) try { + if (!db) { + initialize(); + } mapbox::sqlite::Transaction transaction(*db); auto size = putRegionResourceInternal(regionID, resource, response); transaction.commit(); return size; +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "write region resource"); + return 0; } -void OfflineDatabase::putRegionResources(int64_t regionID, const std::list>& resources, OfflineRegionStatus& status) { +void OfflineDatabase::putRegionResources(int64_t regionID, + const std::list>& resources, + OfflineRegionStatus& status) try { + if (!db) { + initialize(); + } mapbox::sqlite::Transaction transaction(*db); + // Accumulate all statistics locally first before adding them to the OfflineRegionStatus object + // to ensure correctness when the transaction fails. + uint64_t completedResourceCount = 0; + uint64_t completedResourceSize = 0; + uint64_t completedTileCount = 0; + uint64_t completedTileSize = 0; + for (const auto& elem : resources) { const auto& resource = std::get<0>(elem); const auto& response = std::get<1>(elem); try { uint64_t resourceSize = putRegionResourceInternal(regionID, resource, response); - status.completedResourceCount++; - status.completedResourceSize += resourceSize; + completedResourceCount++; + completedResourceSize += resourceSize; if (resource.kind == Resource::Kind::Tile) { - status.completedTileCount += 1; - status.completedTileSize += resourceSize; + completedTileCount += 1; + completedTileSize += resourceSize; } } catch (const MapboxTileLimitExceededException&) { // Commit the rest of the batch and retrow @@ -667,6 +742,13 @@ void OfflineDatabase::putRegionResources(int64_t regionID, const std::list OfflineDatabase::getRegionDefinition(int64_t regionID) try { mapbox::sqlite::Query query{ getStatement("SELECT definition FROM regions WHERE id = ?1") }; query.bind(1, regionID); query.run(); return decodeOfflineRegionDefinition(query.get(0)); +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "load region"); + return nullopt; } -OfflineRegionStatus OfflineDatabase::getRegionCompletedStatus(int64_t regionID) { +optional OfflineDatabase::getRegionCompletedStatus(int64_t regionID) try { OfflineRegionStatus result; std::tie(result.completedResourceCount, result.completedResourceSize) @@ -786,6 +871,9 @@ OfflineRegionStatus OfflineDatabase::getRegionCompletedStatus(int64_t regionID) result.completedResourceSize += result.completedTileSize; return result; +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "get region status"); + return nullopt; } std::pair OfflineDatabase::getCompletedResourceCountAndSize(int64_t regionID) { @@ -920,7 +1008,7 @@ bool OfflineDatabase::offlineMapboxTileCountLimitExceeded() { return getOfflineMapboxTileCount() >= offlineMapboxTileCountLimit; } -uint64_t OfflineDatabase::getOfflineMapboxTileCount() { +uint64_t OfflineDatabase::getOfflineMapboxTileCount() try { // Calculating this on every call would be much simpler than caching and // manually updating the value, but it would make offline downloads an O(n²) // operation, because the database query below involves an index scan of @@ -942,6 +1030,9 @@ uint64_t OfflineDatabase::getOfflineMapboxTileCount() { offlineMapboxTileCount = query.get(0); return *offlineMapboxTileCount; +} catch (const mapbox::sqlite::Exception& ex) { + handleError(ex, "get offline Mapbox tile count"); + return std::numeric_limits::max(); } bool OfflineDatabase::exceedsOfflineMapboxTileCountLimit(const Resource& resource) { diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp index 38eb3783ba..cdad11b79e 100644 --- a/platform/default/mbgl/storage/offline_database.hpp +++ b/platform/default/mbgl/storage/offline_database.hpp @@ -18,6 +18,7 @@ namespace sqlite { class Database; class Statement; class Query; +class Exception; } // namespace sqlite } // namespace mapbox @@ -26,6 +27,10 @@ namespace mbgl { class Response; class TileID; +namespace util { +struct IOException; +} // namespace util + struct MapboxTileLimitExceededException : util::Exception { MapboxTileLimitExceededException() : util::Exception("Mapbox tile limit exceeded") {} }; @@ -44,10 +49,10 @@ public: std::vector listRegions(); - OfflineRegion createRegion(const OfflineRegionDefinition&, - const OfflineRegionMetadata&); + optional createRegion(const OfflineRegionDefinition&, + const OfflineRegionMetadata&); - OfflineRegionMetadata updateMetadata(const int64_t regionID, const OfflineRegionMetadata&); + optional updateMetadata(const int64_t regionID, const OfflineRegionMetadata&); void deleteRegion(OfflineRegion&&); @@ -57,8 +62,8 @@ public: uint64_t putRegionResource(int64_t regionID, const Resource&, const Response&); void putRegionResources(int64_t regionID, const std::list>&, OfflineRegionStatus&); - OfflineRegionDefinition getRegionDefinition(int64_t regionID); - OfflineRegionStatus getRegionCompletedStatus(int64_t regionID); + optional getRegionDefinition(int64_t regionID); + optional getRegionCompletedStatus(int64_t regionID); void setOfflineMapboxTileCountLimit(uint64_t); uint64_t getOfflineMapboxTileCountLimit(); @@ -67,12 +72,15 @@ public: bool exceedsOfflineMapboxTileCountLimit(const Resource&); private: - int userVersion(); - void ensureSchema(); + void initialize(); + void handleError(const mapbox::sqlite::Exception&, const char* action); + void handleError(const util::IOException&, const char* action); + void removeExisting(); void removeOldCacheTable(); - void migrateToVersion3(); + void createSchema(); void migrateToVersion5(); + void migrateToVersion3(); void migrateToVersion6(); mapbox::sqlite::Statement& getStatement(const char *); diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp index 4da51db655..179d2d5f57 100644 --- a/platform/default/mbgl/storage/offline_download.cpp +++ b/platform/default/mbgl/storage/offline_download.cpp @@ -62,39 +62,44 @@ OfflineRegionStatus OfflineDownload::getStatus() const { return status; } - OfflineRegionStatus result = offlineDatabase.getRegionCompletedStatus(id); + auto result = offlineDatabase.getRegionCompletedStatus(id); + if (!result) { + // We can't find this offline region because the database is unavailable, or the download + // does not exist. + return {}; + } - result.requiredResourceCount++; + result->requiredResourceCount++; optional styleResponse = offlineDatabase.get(Resource::style(definition.styleURL)); if (!styleResponse) { - return result; + return *result; } style::Parser parser; parser.parse(*styleResponse->data); - result.requiredResourceCountIsPrecise = true; + result->requiredResourceCountIsPrecise = true; for (const auto& source : parser.sources) { SourceType type = source->getType(); auto handleTiledSource = [&] (const variant& urlOrTileset, const uint16_t tileSize) { if (urlOrTileset.is()) { - result.requiredResourceCount += + result->requiredResourceCount += definition.tileCount(type, tileSize, urlOrTileset.get().zoomRange); } else { - result.requiredResourceCount += 1; + result->requiredResourceCount += 1; const auto& url = urlOrTileset.get(); optional sourceResponse = offlineDatabase.get(Resource::source(url)); if (sourceResponse) { style::conversion::Error error; optional tileset = style::conversion::convertJSON(*sourceResponse->data, error); if (tileset) { - result.requiredResourceCount += + result->requiredResourceCount += definition.tileCount(type, tileSize, (*tileset).zoomRange); } } else { - result.requiredResourceCountIsPrecise = false; + result->requiredResourceCountIsPrecise = false; } } }; @@ -121,7 +126,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const { case SourceType::GeoJSON: { const auto& geojsonSource = *source->as(); if (geojsonSource.getURL()) { - result.requiredResourceCount += 1; + result->requiredResourceCount += 1; } break; } @@ -129,7 +134,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const { case SourceType::Image: { const auto& imageSource = *source->as(); if (imageSource.getURL()) { - result.requiredResourceCount += 1; + result->requiredResourceCount += 1; } break; } @@ -142,14 +147,14 @@ OfflineRegionStatus OfflineDownload::getStatus() const { } if (!parser.glyphURL.empty()) { - result.requiredResourceCount += parser.fontStacks().size() * GLYPH_RANGES_PER_FONT_STACK; + result->requiredResourceCount += parser.fontStacks().size() * GLYPH_RANGES_PER_FONT_STACK; } if (!parser.spriteURL.empty()) { - result.requiredResourceCount += 2; + result->requiredResourceCount += 2; } - return result; + return *result; } void OfflineDownload::activateDownload() { diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp index 1a6045a9a8..fed5a3a185 100644 --- a/platform/default/sqlite3.cpp +++ b/platform/default/sqlite3.cpp @@ -8,11 +8,38 @@ #include #include +#include #include namespace mapbox { namespace sqlite { +static_assert(mbgl::underlying_type(ResultCode::OK) == SQLITE_OK, "error"); +static_assert(mbgl::underlying_type(ResultCode::Error) == SQLITE_ERROR, "error"); +static_assert(mbgl::underlying_type(ResultCode::Internal) == SQLITE_INTERNAL, "error"); +static_assert(mbgl::underlying_type(ResultCode::Perm) == SQLITE_PERM, "error"); +static_assert(mbgl::underlying_type(ResultCode::Abort) == SQLITE_ABORT, "error"); +static_assert(mbgl::underlying_type(ResultCode::Busy) == SQLITE_BUSY, "error"); +static_assert(mbgl::underlying_type(ResultCode::Locked) == SQLITE_LOCKED, "error"); +static_assert(mbgl::underlying_type(ResultCode::NoMem) == SQLITE_NOMEM, "error"); +static_assert(mbgl::underlying_type(ResultCode::ReadOnly) == SQLITE_READONLY, "error"); +static_assert(mbgl::underlying_type(ResultCode::Interrupt) == SQLITE_INTERRUPT, "error"); +static_assert(mbgl::underlying_type(ResultCode::IOErr) == SQLITE_IOERR, "error"); +static_assert(mbgl::underlying_type(ResultCode::Corrupt) == SQLITE_CORRUPT, "error"); +static_assert(mbgl::underlying_type(ResultCode::NotFound) == SQLITE_NOTFOUND, "error"); +static_assert(mbgl::underlying_type(ResultCode::Full) == SQLITE_FULL, "error"); +static_assert(mbgl::underlying_type(ResultCode::CantOpen) == SQLITE_CANTOPEN, "error"); +static_assert(mbgl::underlying_type(ResultCode::Protocol) == SQLITE_PROTOCOL, "error"); +static_assert(mbgl::underlying_type(ResultCode::Schema) == SQLITE_SCHEMA, "error"); +static_assert(mbgl::underlying_type(ResultCode::TooBig) == SQLITE_TOOBIG, "error"); +static_assert(mbgl::underlying_type(ResultCode::Constraint) == SQLITE_CONSTRAINT, "error"); +static_assert(mbgl::underlying_type(ResultCode::Mismatch) == SQLITE_MISMATCH, "error"); +static_assert(mbgl::underlying_type(ResultCode::Misuse) == SQLITE_MISUSE, "error"); +static_assert(mbgl::underlying_type(ResultCode::NoLFS) == SQLITE_NOLFS, "error"); +static_assert(mbgl::underlying_type(ResultCode::Auth) == SQLITE_AUTH, "error"); +static_assert(mbgl::underlying_type(ResultCode::Range) == SQLITE_RANGE, "error"); +static_assert(mbgl::underlying_type(ResultCode::NotADB) == SQLITE_NOTADB, "error"); + class DatabaseImpl { public: DatabaseImpl(sqlite3* db_) @@ -24,7 +51,7 @@ public: { const int error = sqlite3_close(db); if (error != SQLITE_OK) { - mbgl::Log::Error(mbgl::Event::Database, "%s (Code %i)", sqlite3_errmsg(db), error); + mbgl::Log::Error(mbgl::Event::Database, error, "Failed to close database: %s", sqlite3_errmsg(db)); } } @@ -66,11 +93,8 @@ public: template using optional = std::experimental::optional; -static void errorLogCallback(void *, const int err, const char *msg) { - mbgl::Log::Record(mbgl::EventSeverity::Info, mbgl::Event::Database, err, "%s", msg); -} - -const static bool sqliteVersionCheck __attribute__((unused)) = []() { +__attribute__((constructor)) +static void initalize() { if (sqlite3_libversion_number() / 1000000 != SQLITE_VERSION_NUMBER / 1000000) { char message[96]; snprintf(message, 96, @@ -79,15 +103,17 @@ const static bool sqliteVersionCheck __attribute__((unused)) = []() { throw std::runtime_error(message); } +#ifndef NDEBUG // Enable SQLite logging before initializing the database. - sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, nullptr); - - return true; -}(); + sqlite3_config(SQLITE_CONFIG_LOG, [](void *, const int err, const char *msg) { + mbgl::Log::Record(mbgl::EventSeverity::Debug, mbgl::Event::Database, err, "%s", msg); + }, nullptr); +#endif +} mapbox::util::variant Database::tryOpen(const std::string &filename, int flags) { sqlite3* db = nullptr; - const int error = sqlite3_open_v2(filename.c_str(), &db, flags, nullptr); + const int error = sqlite3_open_v2(filename.c_str(), &db, flags | SQLITE_OPEN_URI, nullptr); if (error != SQLITE_OK) { const auto message = sqlite3_errmsg(db); return Exception { error, message }; diff --git a/platform/qt/src/sqlite3.cpp b/platform/qt/src/sqlite3.cpp index 2ca09fd3ad..96cee5fff8 100644 --- a/platform/qt/src/sqlite3.cpp +++ b/platform/qt/src/sqlite3.cpp @@ -23,13 +23,6 @@ namespace mapbox { namespace sqlite { -// https://www.sqlite.org/rescode.html#ok -static_assert(mbgl::underlying_type(ResultCode::OK) == 0, "error"); -// https://www.sqlite.org/rescode.html#cantopen -static_assert(mbgl::underlying_type(ResultCode::CantOpen) == 14, "error"); -// https://www.sqlite.org/rescode.html#notadb -static_assert(mbgl::underlying_type(ResultCode::NotADB) == 26, "error"); - void checkQueryError(const QSqlQuery& query) { QSqlError lastError = query.lastError(); if (lastError.type() != QSqlError::NoError) { @@ -114,6 +107,11 @@ mapbox::util::variant Database::tryOpen(const std::string & connectOptions.append("QSQLITE_OPEN_READONLY"); } + if (filename.compare(0, 5, "file:") == 0) { + if (!connectOptions.isEmpty()) connectOptions.append(';'); + connectOptions.append("QSQLITE_OPEN_URI"); + } + db.setConnectOptions(connectOptions); db.setDatabaseName(QString(filename.c_str())); diff --git a/test/fixtures/offline_database/corrupt-delayed.db b/test/fixtures/offline_database/corrupt-delayed.db new file mode 100644 index 0000000000..04989dbf36 Binary files /dev/null and b/test/fixtures/offline_database/corrupt-delayed.db differ diff --git a/test/fixtures/offline_database/corrupt-immediate.db b/test/fixtures/offline_database/corrupt-immediate.db new file mode 100644 index 0000000000..8909c402b2 Binary files /dev/null and b/test/fixtures/offline_database/corrupt-immediate.db differ diff --git a/test/src/mbgl/test/fixture_log_observer.cpp b/test/src/mbgl/test/fixture_log_observer.cpp index d8a4b9edce..d768c0284a 100644 --- a/test/src/mbgl/test/fixture_log_observer.cpp +++ b/test/src/mbgl/test/fixture_log_observer.cpp @@ -32,7 +32,9 @@ bool FixtureLog::Observer::onRecord(EventSeverity severity, const std::string& msg) { std::lock_guard lock(messagesMutex); - messages.emplace_back(severity, event, code, msg); + if (severity != EventSeverity::Debug) { + messages.emplace_back(severity, event, code, msg); + } return true; } @@ -48,7 +50,7 @@ size_t FixtureLog::Observer::count(const Message& message, bool substring) const size_t message_count = 0; for (const auto& msg : messages) { - if (msg.matches(message, substring)) { + if (!msg.checked && msg.matches(message, substring)) { message_count++; msg.checked = true; } diff --git a/test/src/mbgl/test/sqlite3_test_fs.cpp b/test/src/mbgl/test/sqlite3_test_fs.cpp new file mode 100644 index 0000000000..16d411faff --- /dev/null +++ b/test/src/mbgl/test/sqlite3_test_fs.cpp @@ -0,0 +1,320 @@ +#ifndef __QT__ // Qt doesn't expose SQLite VFS + +#include + +#include + +#include +#include +#include +#include +#include + +static bool sqlite3_test_fs_debug = false; +static bool sqlite3_test_fs_io = true; +static bool sqlite3_test_fs_file_open = true; +static bool sqlite3_test_fs_file_create = true; +static int64_t sqlite3_test_fs_read_limit = -1; +static int64_t sqlite3_test_fs_write_limit = -1; + +struct File { + sqlite3_file base; + sqlite3_file* real; +}; + +static int sqlite3_test_fs_close(sqlite3_file* pFile) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: close(%p)\n", pFile); + } + if (!sqlite3_test_fs_io) { + return SQLITE_AUTH; + } + File* file = (File*)pFile; + const int rc = file->real->pMethods->xClose(file->real); + if (rc == SQLITE_OK) { + sqlite3_free((void*)file->base.pMethods); + file->base.pMethods = 0; + } + return rc; +} + +static int sqlite3_test_fs_read(sqlite3_file* pFile, void* zBuf, int iAmt, sqlite3_int64 iOfst) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: read(%p, amount=%d, offset=%lld)\n", pFile, iAmt, iOfst); + } + if (!sqlite3_test_fs_io) { + return SQLITE_AUTH; + } + if (sqlite3_test_fs_read_limit >= 0) { + if (iAmt > sqlite3_test_fs_read_limit) { + iAmt = 0; + return SQLITE_IOERR; + } + sqlite3_test_fs_read_limit -= iAmt; + } + File* file = (File*)pFile; + return file->real->pMethods->xRead(file->real, zBuf, iAmt, iOfst); +} + +static int sqlite3_test_fs_write(sqlite3_file* pFile, const void* zBuf, int iAmt, sqlite3_int64 iOfst) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: write(%p, amount=%d, offset=%lld)\n", pFile, iAmt, iOfst); + } + if (!sqlite3_test_fs_io) { + return SQLITE_AUTH; + } + if (sqlite3_test_fs_write_limit >= 0) { + if (iAmt > sqlite3_test_fs_write_limit) { + iAmt = 0; + return SQLITE_FULL; + } + sqlite3_test_fs_write_limit -= iAmt; + } + File* file = (File*)pFile; + return file->real->pMethods->xWrite(file->real, zBuf, iAmt, iOfst); +} + +static int sqlite3_test_fs_truncate(sqlite3_file* pFile, sqlite3_int64 size) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: truncate(%p, size=%lld)\n", pFile, size); + } + if (!sqlite3_test_fs_io) { + return SQLITE_AUTH; + } + File* file = (File*)pFile; + return file->real->pMethods->xTruncate(file->real, size); +} + +static int sqlite3_test_fs_sync(sqlite3_file* pFile, int flags) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: sync(%p, flags=%d)\n", pFile, flags); + } + if (!sqlite3_test_fs_io) { + return SQLITE_AUTH; + } + File* file = (File*)pFile; + return file->real->pMethods->xSync(file->real, flags); +} + +static int sqlite3_test_fs_file_size(sqlite3_file* pFile, sqlite3_int64* pSize) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: file_size(%p)\n", pFile); + } + if (!sqlite3_test_fs_io) { + return SQLITE_AUTH; + } + File* file = (File*)pFile; + return file->real->pMethods->xFileSize(file->real, pSize); +} + +static int sqlite3_test_fs_lock(sqlite3_file* pFile, int eLock) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: lock(%p, %d)\n", pFile, eLock); + } + File* file = (File*)pFile; + return file->real->pMethods->xLock(file->real, eLock); +} + +static int sqlite3_test_fs_unlock(sqlite3_file* pFile, int eLock) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: unlock(%p, %d)\n", pFile, eLock); + } + File* file = (File*)pFile; + return file->real->pMethods->xUnlock(file->real, eLock); +} + +static int sqlite3_test_fs_check_reserved_lock(sqlite3_file* pFile, int* pResOut) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: check_reserved_lock(%p)\n", pFile); + } + File* file = (File*)pFile; + return file->real->pMethods->xCheckReservedLock(file->real, pResOut); +} + +static int sqlite3_test_fs_file_control(sqlite3_file* pFile, int op, void* pArg) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: file_control(%p, op=%d)\n", pFile, op); + } + if (!sqlite3_test_fs_io) { + return SQLITE_AUTH; + } + File* file = (File*)pFile; + return file->real->pMethods->xFileControl(file->real, op, pArg); +} + +static int sqlite3_test_fs_sector_size(sqlite3_file* pFile) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: sector_size(%p)\n", pFile); + } + if (!sqlite3_test_fs_io) { + return SQLITE_AUTH; + } + File* file = (File*)pFile; + return file->real->pMethods->xSectorSize(file->real); +} + +static int sqlite3_test_fs_device_characteristics(sqlite3_file* pFile) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: device_characteristics(%p)\n", pFile); + } + if (!sqlite3_test_fs_io) { + return SQLITE_AUTH; + } + File* file = (File*)pFile; + return file->real->pMethods->xDeviceCharacteristics(file->real); +} + +static int sqlite3_test_fs_open(sqlite3_vfs* vfs, const char* zName, sqlite3_file* pFile, int flags, int* pOutFlags) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: open(name=%s, flags=%d) -> %p\n", zName, flags, pFile); + } + if (!sqlite3_test_fs_io) { + pFile->pMethods = NULL; + return SQLITE_AUTH; + } + if (!sqlite3_test_fs_file_open) { + pFile->pMethods = NULL; + return SQLITE_CANTOPEN; + } + + File* file = (File*)pFile; + sqlite3_vfs* unix_fs = (sqlite3_vfs*)vfs->pAppData; + file->real = (sqlite3_file*)&file[1]; + + if (!sqlite3_test_fs_file_create) { + int res; + const int result = unix_fs->xAccess(vfs, zName, SQLITE_ACCESS_EXISTS, &res); + if (result != SQLITE_OK) { + pFile->pMethods = NULL; + return result; + } + if (res != 1) { + pFile->pMethods = NULL; + return SQLITE_CANTOPEN; + } + } + + const int status = unix_fs->xOpen(unix_fs, zName, file->real, flags, pOutFlags); + if (file->real->pMethods) { + sqlite3_io_methods* methods = (sqlite3_io_methods*)sqlite3_malloc(sizeof(sqlite3_io_methods)); + memset(methods, 0, sizeof(sqlite3_io_methods)); + methods->iVersion = 1; + methods->xClose = sqlite3_test_fs_close; + methods->xRead = sqlite3_test_fs_read; + methods->xWrite = sqlite3_test_fs_write; + methods->xTruncate = sqlite3_test_fs_truncate; + methods->xSync = sqlite3_test_fs_sync; + methods->xFileSize = sqlite3_test_fs_file_size; + methods->xLock = sqlite3_test_fs_lock; + methods->xUnlock = sqlite3_test_fs_unlock; + methods->xCheckReservedLock = sqlite3_test_fs_check_reserved_lock; + methods->xFileControl = sqlite3_test_fs_file_control; + methods->xSectorSize = sqlite3_test_fs_sector_size; + methods->xDeviceCharacteristics = sqlite3_test_fs_device_characteristics; + pFile->pMethods = methods; + } + return status; +} + +static int sqlite3_test_fs_delete(sqlite3_vfs* vfs, const char *zPath, int dirSync) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: delete(name=%s, sync=%d)\n", zPath, dirSync); + } + if (!sqlite3_test_fs_io) { + return SQLITE_AUTH; + } + sqlite3_vfs* unix_fs = (sqlite3_vfs*)vfs->pAppData; + return unix_fs->xDelete(unix_fs, zPath, dirSync); +} + +static int sqlite3_test_fs_access(sqlite3_vfs* vfs, const char *zPath, int flags, int *pResOut) { + if (sqlite3_test_fs_debug) { + fprintf(stderr, "SQLite3: access(name=%s, flags=%d)\n", zPath, flags); + } + if (!sqlite3_test_fs_io) { + return SQLITE_AUTH; + } + sqlite3_vfs* unix_fs = (sqlite3_vfs*)vfs->pAppData; + return unix_fs->xAccess(unix_fs, zPath, flags, pResOut); +} + +namespace mbgl { +namespace test { + +SQLite3TestFS::SQLite3TestFS() { + sqlite3_vfs* unix_fs = sqlite3_vfs_find("unix"); + if (unix_fs == 0) { + abort(); + } + + sqlite3_vfs* test_fs = (sqlite3_vfs*)sqlite3_malloc(sizeof(sqlite3_vfs)); + if (test_fs == 0) { + abort(); + } + memset(test_fs, 0, sizeof(sqlite3_vfs)); + test_fs->iVersion = 1; + test_fs->szOsFile = unix_fs->szOsFile + sizeof(File); + test_fs->mxPathname = unix_fs->mxPathname; + test_fs->zName = "test_fs"; + test_fs->pAppData = unix_fs; + test_fs->xOpen = sqlite3_test_fs_open; + test_fs->xDelete = sqlite3_test_fs_delete; + test_fs->xAccess = sqlite3_test_fs_access; + test_fs->xFullPathname = unix_fs->xFullPathname; + test_fs->xDlOpen = unix_fs->xDlOpen; + test_fs->xDlError = unix_fs->xDlError; + test_fs->xDlSym = unix_fs->xDlSym; + test_fs->xDlClose = unix_fs->xDlClose; + test_fs->xRandomness = unix_fs->xRandomness; + test_fs->xSleep = unix_fs->xSleep; + test_fs->xCurrentTime = unix_fs->xCurrentTime; + test_fs->xGetLastError = unix_fs->xGetLastError; + + sqlite3_vfs_register(test_fs, 0); +} + +SQLite3TestFS::~SQLite3TestFS() { + reset(); + sqlite3_vfs* test_fs = sqlite3_vfs_find("test_fs"); + if (test_fs) { + sqlite3_vfs_unregister(test_fs); + } +} + +void SQLite3TestFS::setDebug(bool value) { + sqlite3_test_fs_debug = value; +} + +void SQLite3TestFS::allowIO(bool value) { + sqlite3_test_fs_io = value; +} + +void SQLite3TestFS::allowFileOpen(bool value) { + sqlite3_test_fs_file_open = value; +} + +void SQLite3TestFS::allowFileCreate(bool value) { + sqlite3_test_fs_file_create = value; +} + +void SQLite3TestFS::setReadLimit(int64_t value) { + sqlite3_test_fs_read_limit = value; +} + +void SQLite3TestFS::setWriteLimit(int64_t value) { + sqlite3_test_fs_write_limit = value; +} + +void SQLite3TestFS::reset() { + setDebug(false); + allowIO(true); + allowFileOpen(true); + allowFileCreate(true); + setReadLimit(-1); + setWriteLimit(-1); +} + +} // namespace test +} // namespace mbgl + +#endif // __QT__ diff --git a/test/src/mbgl/test/sqlite3_test_fs.hpp b/test/src/mbgl/test/sqlite3_test_fs.hpp new file mode 100644 index 0000000000..00351f49ac --- /dev/null +++ b/test/src/mbgl/test/sqlite3_test_fs.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include + +namespace mbgl { +namespace test { + +class SQLite3TestFS { +public: + SQLite3TestFS(); + ~SQLite3TestFS(); + + // When enabled, the VFS will log all I/O operations to stdout. + void setDebug(bool); + + // Allow any type of I/O. Will fail with SQLITE_AUTH if set to false. This is useful to simulate + // scenarios where the OS blocks an entire app's I/O, e.g. when it's in the background. + void allowIO(bool); + + // Allow files to be opened. Will fail with SQLITE_CANTOPEN if set to false. + void allowFileOpen(bool); + + // Allow files to be created. Will fail with SQLITE_CANTOPEN if set to false. + void allowFileCreate(bool); + + // Allow N bytes to be read, then fail reads with SQLITE_IOERR. -1 == unlimited + // This limit is global, not per file. + void setReadLimit(int64_t); + + // Allow N bytes to be written, then fail writes with SQLITE_FULL. -1 == unlimited + // This limit is global, not per file. + void setWriteLimit(int64_t); + + // Reset all restrictions. + void reset(); +}; + +} // namespace test +} // namespace mbgl diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index 000f24e1cd..de40d8caf7 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -13,51 +14,235 @@ using namespace std::literals::string_literals; using namespace mbgl; +using mapbox::sqlite::ResultCode; static constexpr const char* filename = "test/fixtures/offline_database/offline.db"; +#ifndef __QT__ // Qt doesn't expose the ability to register virtual file system handlers. +static constexpr const char* filename_test_fs = "file:test/fixtures/offline_database/offline.db?vfs=test_fs"; +#endif -TEST(OfflineDatabase, TEST_REQUIRES_WRITE(Create)) { - FixtureLog log; +static void deleteDatabaseFiles() { + // Delete leftover journaling files as well. util::deleteFile(filename); + util::deleteFile(filename + "-wal"s); + util::deleteFile(filename + "-journal"s); +} + +static FixtureLog::Message error(ResultCode code, const char* message) { + return { EventSeverity::Error, Event::Database, static_cast(code), message }; +} + +static FixtureLog::Message warning(ResultCode code, const char* message) { + return { EventSeverity::Warning, Event::Database, static_cast(code), message }; +} + +static int databasePageCount(const std::string& path) { + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); + mapbox::sqlite::Statement stmt{ db, "pragma page_count" }; + mapbox::sqlite::Query query{ stmt }; + query.run(); + return query.get(0); +} + +static int databaseUserVersion(const std::string& path) { + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); + mapbox::sqlite::Statement stmt{ db, "pragma user_version" }; + mapbox::sqlite::Query query{ stmt }; + query.run(); + return query.get(0); +} + +static std::string databaseJournalMode(const std::string& path) { + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); + mapbox::sqlite::Statement stmt{ db, "pragma journal_mode" }; + mapbox::sqlite::Query query{ stmt }; + query.run(); + return query.get(0); +} +static int databaseSyncMode(const std::string& path) { + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); + mapbox::sqlite::Statement stmt{ db, "pragma synchronous" }; + mapbox::sqlite::Query query{ stmt }; + query.run(); + return query.get(0); +} + +static std::vector databaseTableColumns(const std::string& path, const std::string& name) { + mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); + const auto sql = std::string("pragma table_info(") + name + ")"; + mapbox::sqlite::Statement stmt{ db, sql.c_str() }; + mapbox::sqlite::Query query{ stmt }; + std::vector columns; + while (query.run()) { + columns.push_back(query.get(1)); + } + return columns; +} + +namespace fixture { + +const Resource resource{ Resource::Style, "mapbox://test" }; +const Resource tile = Resource::tile("mapbox://test", 1, 0, 0, 0, Tileset::Scheme::XYZ); +const Response response = [] { + Response res; + res.data = std::make_shared("first"); + return res; +}(); + +} // namespace + +TEST(OfflineDatabase, TEST_REQUIRES_WRITE(Create)) { + FixtureLog log; + deleteDatabaseFiles(); OfflineDatabase db(filename); EXPECT_FALSE(bool(db.get({ Resource::Unknown, "mapbox://test" }))); EXPECT_EQ(0u, log.uncheckedCount()); } +#ifndef __QT__ // Qt doesn't expose the ability to register virtual file system handlers. +TEST(OfflineDatabase, TEST_REQUIRES_WRITE(CreateFail)) { + FixtureLog log; + deleteDatabaseFiles(); + test::SQLite3TestFS fs; + + // Opening the database will fail because our mock VFS returns a SQLITE_CANTOPEN error because + // it is not allowed to create the file. The OfflineDatabase object should handle this gracefully + // and treat it like an empty cache that can't be written to. + fs.allowFileCreate(false); + OfflineDatabase db(filename_test_fs); + EXPECT_EQ(1u, log.count(warning(ResultCode::CantOpen, "Can't open database: unable to open database file"))); + + EXPECT_EQ(0u, log.uncheckedCount()); + + // We can try to insert things into the cache, but since the cache database isn't open, it won't be stored. + for (const auto& res : { fixture::resource, fixture::tile }) { + EXPECT_EQ(std::make_pair(false, uint64_t(0)), db.put(res, fixture::response)); + EXPECT_EQ(1u, log.count(warning(ResultCode::CantOpen, "Can't write resource: unable to open database file"))); + EXPECT_EQ(0u, log.uncheckedCount()); + } + + // We can also still "query" the database even though it is not open, and we will always get an empty result. + for (const auto& res : { fixture::resource, fixture::tile }) { + EXPECT_FALSE(bool(db.get(res))); + EXPECT_EQ(1u, log.count(warning(ResultCode::CantOpen, "Can't update timestamp: unable to open database file"))); + EXPECT_EQ(1u, log.count(warning(ResultCode::CantOpen, "Can't read resource: unable to open database file"))); + EXPECT_EQ(0u, log.uncheckedCount()); + } + + // Now, we're "freeing up" some space on the disk, and try to insert and query again. This time, we should + // be opening the datbase, creating the schema, and writing the data so that we can retrieve it again. + fs.allowFileCreate(true); + for (const auto& res : { fixture::resource, fixture::tile }) { + EXPECT_EQ(std::make_pair(true, uint64_t(5)), db.put(res, fixture::response)); + auto result = db.get(res); + EXPECT_EQ(0u, log.uncheckedCount()); + ASSERT_TRUE(result && result->data); + EXPECT_EQ("first", *result->data); + } + + // Next, set the file system to read only mode and try to read the data again. While we can't + // write anymore, we should still be able to read, and the query that tries to update the last + // accessed timestamp may fail without crashing. + fs.allowFileCreate(false); + fs.setWriteLimit(0); + for (const auto& res : { fixture::resource, fixture::tile }) { + auto result = db.get(res); + EXPECT_EQ(1u, log.count(warning(ResultCode::CantOpen, "Can't update timestamp: unable to open database file"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + ASSERT_TRUE(result && result->data); + EXPECT_EQ("first", *result->data); + } + fs.setDebug(false); + + // We're allowing SQLite to create a journal file, but restrict the number of bytes it + // can write so that it can start writing the journal file, but eventually fails during the + // timestamp update. + fs.allowFileCreate(true); + fs.setWriteLimit(8192); + for (const auto& res : { fixture::resource, fixture::tile }) { + auto result = db.get(res); + EXPECT_EQ(1u, log.count(warning(ResultCode::Full, "Can't update timestamp: database or disk is full"))); + EXPECT_EQ(0u, log.uncheckedCount()); + ASSERT_TRUE(result && result->data); + EXPECT_EQ("first", *result->data); + } + + // Lastly, we're disabling all I/O to simulate a backgrounded app that is restricted from doing + // any disk I/O at all. + fs.setWriteLimit(-1); + fs.allowIO(false); + for (const auto& res : { fixture::resource, fixture::tile }) { + // First, try reading. + auto result = db.get(res); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't update timestamp: authorization denied"))); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't read resource: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + EXPECT_FALSE(result); + + // Now try inserting. + EXPECT_EQ(std::make_pair(false, uint64_t(0)), db.put(res, fixture::response)); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't write resource: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + } + + // Allow deleting the database. + fs.reset(); +} +#endif // __QT__ + TEST(OfflineDatabase, TEST_REQUIRES_WRITE(SchemaVersion)) { FixtureLog log; - util::deleteFile(filename); + deleteDatabaseFiles(); { mapbox::sqlite::Database db = mapbox::sqlite::Database::open(filename, mapbox::sqlite::ReadWriteCreate); + db.setBusyTimeout(Milliseconds(1000)); db.exec("PRAGMA user_version = 1"); } + { + OfflineDatabase db(filename); + } + + EXPECT_EQ(6, databaseUserVersion(filename)); + OfflineDatabase db(filename); + // Now try inserting and reading back to make sure we have a valid database. + for (const auto& res : { fixture::resource, fixture::tile }) { + EXPECT_EQ(std::make_pair(true, uint64_t(5)), db.put(res, fixture::response)); + EXPECT_EQ(0u, log.uncheckedCount()); + auto result = db.get(res); + EXPECT_EQ(0u, log.uncheckedCount()); + ASSERT_TRUE(result && result->data); + EXPECT_EQ("first", *result->data); + } EXPECT_EQ(0u, log.uncheckedCount()); } TEST(OfflineDatabase, TEST_REQUIRES_WRITE(Invalid)) { FixtureLog log; - util::deleteFile(filename); + deleteDatabaseFiles(); util::write_file(filename, "this is an invalid file"); OfflineDatabase db(filename); - -#ifndef __QT__ - // Only non-Qt platforms are setting a logger on the SQLite object. // Checking two possibilities for the error string because it apparently changes between SQLite versions. - EXPECT_EQ(1u, - log.count({ EventSeverity::Info, Event::Database, static_cast(mapbox::sqlite::ResultCode::NotADB), - "statement aborts at 1: [PRAGMA user_version] file is encrypted or is not a database" }, true) + - log.count({ EventSeverity::Info, Event::Database, static_cast(mapbox::sqlite::ResultCode::NotADB), - "statement aborts at 1: [PRAGMA user_version] file is not a database" }, true)); -#endif - EXPECT_EQ(1u, log.count({ EventSeverity::Warning, Event::Database, -1, "Removing existing incompatible offline database" })); - EXPECT_EQ(0u, log.uncheckedCount()); + EXPECT_EQ(1u, log.count(error(ResultCode::NotADB, "Can't open database: file is encrypted or is not a database"), true) + + log.count(error(ResultCode::NotADB, "Can't open database: file is not a database"), true)); + EXPECT_EQ(1u, log.count(warning(static_cast(-1), "Removing existing incompatible offline database"))); + + // Now try inserting and reading back to make sure we have a valid database. + for (const auto& res : { fixture::resource, fixture::tile }) { + EXPECT_EQ(std::make_pair(true, uint64_t(5)), db.put(res, fixture::response)); + EXPECT_EQ(0u, log.uncheckedCount()); + auto result = db.get(res); + EXPECT_EQ(0u, log.uncheckedCount()); + ASSERT_TRUE(result && result->data); + EXPECT_EQ("first", *result->data); + } } TEST(OfflineDatabase, PutDoesNotStoreConnectionErrors) { @@ -118,7 +303,7 @@ TEST(OfflineDatabase, PutResource) { TEST(OfflineDatabase, TEST_REQUIRES_WRITE(GetResourceFromOfflineRegion)) { FixtureLog log; - util::deleteFile(filename); + deleteDatabaseFiles(); util::copyFile(filename, "test/fixtures/offline_database/satellite_test.db"); OfflineDatabase db(filename, mapbox::sqlite::ReadOnly); @@ -228,14 +413,15 @@ TEST(OfflineDatabase, CreateRegion) { OfflineDatabase db(":memory:"); OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; - OfflineRegion region = db.createRegion(definition, metadata); + auto region = db.createRegion(definition, metadata); + ASSERT_TRUE(region); - EXPECT_EQ(definition.styleURL, region.getDefinition().styleURL); - EXPECT_EQ(definition.bounds, region.getDefinition().bounds); - EXPECT_EQ(definition.minZoom, region.getDefinition().minZoom); - EXPECT_EQ(definition.maxZoom, region.getDefinition().maxZoom); - EXPECT_EQ(definition.pixelRatio, region.getDefinition().pixelRatio); - EXPECT_EQ(metadata, region.getMetadata()); + EXPECT_EQ(definition.styleURL, region->getDefinition().styleURL); + EXPECT_EQ(definition.bounds, region->getDefinition().bounds); + EXPECT_EQ(definition.minZoom, region->getDefinition().minZoom); + EXPECT_EQ(definition.maxZoom, region->getDefinition().maxZoom); + EXPECT_EQ(definition.pixelRatio, region->getDefinition().pixelRatio); + EXPECT_EQ(metadata, region->getMetadata()); EXPECT_EQ(0u, log.uncheckedCount()); } @@ -245,10 +431,11 @@ TEST(OfflineDatabase, UpdateMetadata) { OfflineDatabase db(":memory:"); OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; - OfflineRegion region = db.createRegion(definition, metadata); + auto region = db.createRegion(definition, metadata); + ASSERT_TRUE(region); OfflineRegionMetadata newmetadata {{ 4, 5, 6 }}; - db.updateMetadata(region.getID(), newmetadata); + db.updateMetadata(region->getID(), newmetadata); EXPECT_EQ(db.listRegions().at(0).getMetadata(), newmetadata); EXPECT_EQ(0u, log.uncheckedCount()); @@ -260,11 +447,12 @@ TEST(OfflineDatabase, ListRegions) { OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; - OfflineRegion region = db.createRegion(definition, metadata); + auto region = db.createRegion(definition, metadata); + ASSERT_TRUE(region); std::vector regions = db.listRegions(); ASSERT_EQ(1u, regions.size()); - EXPECT_EQ(region.getID(), regions.at(0).getID()); + EXPECT_EQ(region->getID(), regions.at(0).getID()); EXPECT_EQ(definition.styleURL, regions.at(0).getDefinition().styleURL); EXPECT_EQ(definition.bounds, regions.at(0).getDefinition().bounds); EXPECT_EQ(definition.minZoom, regions.at(0).getDefinition().minZoom); @@ -281,14 +469,16 @@ TEST(OfflineDatabase, GetRegionDefinition) { OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; - OfflineRegion region = db.createRegion(definition, metadata); - OfflineRegionDefinition result = db.getRegionDefinition(region.getID()); + auto region = db.createRegion(definition, metadata); + ASSERT_TRUE(region); + auto result = db.getRegionDefinition(region->getID()); + ASSERT_TRUE(result); - EXPECT_EQ(definition.styleURL, result.styleURL); - EXPECT_EQ(definition.bounds, result.bounds); - EXPECT_EQ(definition.minZoom, result.minZoom); - EXPECT_EQ(definition.maxZoom, result.maxZoom); - EXPECT_EQ(definition.pixelRatio, result.pixelRatio); + EXPECT_EQ(definition.styleURL, result->styleURL); + EXPECT_EQ(definition.bounds, result->bounds); + EXPECT_EQ(definition.minZoom, result->minZoom); + EXPECT_EQ(definition.maxZoom, result->maxZoom); + EXPECT_EQ(definition.pixelRatio, result->pixelRatio); EXPECT_EQ(0u, log.uncheckedCount()); } @@ -298,15 +488,16 @@ TEST(OfflineDatabase, DeleteRegion) { OfflineDatabase db(":memory:"); OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; - OfflineRegion region = db.createRegion(definition, metadata); + auto region = db.createRegion(definition, metadata); + ASSERT_TRUE(region); Response response; response.noContent = true; - db.putRegionResource(region.getID(), Resource::style("http://example.com/"), response); - db.putRegionResource(region.getID(), Resource::tile("http://example.com/", 1.0, 0, 0, 0, Tileset::Scheme::XYZ), response); + db.putRegionResource(region->getID(), Resource::style("http://example.com/"), response); + db.putRegionResource(region->getID(), Resource::tile("http://example.com/", 1.0, 0, 0, 0, Tileset::Scheme::XYZ), response); - db.deleteRegion(std::move(region)); + db.deleteRegion(std::move(*region)); ASSERT_EQ(0u, db.listRegions().size()); @@ -318,38 +509,35 @@ TEST(OfflineDatabase, CreateRegionInfiniteMaxZoom) { OfflineDatabase db(":memory:"); OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; OfflineRegionMetadata metadata; - OfflineRegion region = db.createRegion(definition, metadata); + auto region = db.createRegion(definition, metadata); + ASSERT_TRUE(region); - EXPECT_EQ(0, region.getDefinition().minZoom); - EXPECT_EQ(INFINITY, region.getDefinition().maxZoom); + EXPECT_EQ(0, region->getDefinition().minZoom); + EXPECT_EQ(INFINITY, region->getDefinition().maxZoom); EXPECT_EQ(0u, log.uncheckedCount()); } TEST(OfflineDatabase, TEST_REQUIRES_WRITE(ConcurrentUse)) { FixtureLog log; - util::deleteFile(filename); + deleteDatabaseFiles(); OfflineDatabase db1(filename); EXPECT_EQ(0u, log.uncheckedCount()); OfflineDatabase db2(filename); - Resource resource { Resource::Style, "http://example.com/" }; - Response response; - response.noContent = true; - std::thread thread1([&] { for (auto i = 0; i < 100; i++) { - db1.put(resource, response); - EXPECT_TRUE(bool(db1.get(resource))); + db1.put(fixture::resource, fixture::response); + EXPECT_TRUE(bool(db1.get(fixture::resource))); } }); std::thread thread2([&] { for (auto i = 0; i < 100; i++) { - db2.put(resource, response); - EXPECT_TRUE(bool(db2.get(resource))); + db2.put(fixture::resource, fixture::response); + EXPECT_TRUE(bool(db2.get(fixture::resource))); } }); @@ -411,13 +599,14 @@ TEST(OfflineDatabase, PutRegionResourceDoesNotEvict) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; - OfflineRegion region = db.createRegion(definition, OfflineRegionMetadata()); + auto region = db.createRegion(definition, OfflineRegionMetadata()); + ASSERT_TRUE(region); Response response; response.data = randomString(1024); for (uint32_t i = 1; i <= 100; i++) { - db.putRegionResource(region.getID(), Resource::style("http://example.com/"s + util::toString(i)), response); + db.putRegionResource(region->getID(), Resource::style("http://example.com/"s + util::toString(i)), response); } EXPECT_TRUE(bool(db.get(Resource::style("http://example.com/1")))); @@ -448,32 +637,36 @@ TEST(OfflineDatabase, GetRegionCompletedStatus) { OfflineDatabase db(":memory:"); OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata; - OfflineRegion region = db.createRegion(definition, metadata); + auto region = db.createRegion(definition, metadata); + ASSERT_TRUE(region); - OfflineRegionStatus status1 = db.getRegionCompletedStatus(region.getID()); - EXPECT_EQ(0u, status1.completedResourceCount); - EXPECT_EQ(0u, status1.completedResourceSize); - EXPECT_EQ(0u, status1.completedTileCount); - EXPECT_EQ(0u, status1.completedTileSize); + auto status1 = db.getRegionCompletedStatus(region->getID()); + ASSERT_TRUE(status1); + EXPECT_EQ(0u, status1->completedResourceCount); + EXPECT_EQ(0u, status1->completedResourceSize); + EXPECT_EQ(0u, status1->completedTileCount); + EXPECT_EQ(0u, status1->completedTileSize); Response response; response.data = std::make_shared("data"); - uint64_t styleSize = db.putRegionResource(region.getID(), Resource::style("http://example.com/"), response); + uint64_t styleSize = db.putRegionResource(region->getID(), Resource::style("http://example.com/"), response); - OfflineRegionStatus status2 = db.getRegionCompletedStatus(region.getID()); - EXPECT_EQ(1u, status2.completedResourceCount); - EXPECT_EQ(styleSize, status2.completedResourceSize); - EXPECT_EQ(0u, status2.completedTileCount); - EXPECT_EQ(0u, status2.completedTileSize); + auto status2 = db.getRegionCompletedStatus(region->getID()); + ASSERT_TRUE(status2); + EXPECT_EQ(1u, status2->completedResourceCount); + EXPECT_EQ(styleSize, status2->completedResourceSize); + EXPECT_EQ(0u, status2->completedTileCount); + EXPECT_EQ(0u, status2->completedTileSize); - uint64_t tileSize = db.putRegionResource(region.getID(), Resource::tile("http://example.com/", 1.0, 0, 0, 0, Tileset::Scheme::XYZ), response); + uint64_t tileSize = db.putRegionResource(region->getID(), Resource::tile("http://example.com/", 1.0, 0, 0, 0, Tileset::Scheme::XYZ), response); - OfflineRegionStatus status3 = db.getRegionCompletedStatus(region.getID()); - EXPECT_EQ(2u, status3.completedResourceCount); - EXPECT_EQ(styleSize + tileSize, status3.completedResourceSize); - EXPECT_EQ(1u, status3.completedTileCount); - EXPECT_EQ(tileSize, status3.completedTileSize); + auto status3 = db.getRegionCompletedStatus(region->getID()); + ASSERT_TRUE(status3); + EXPECT_EQ(2u, status3->completedResourceCount); + EXPECT_EQ(styleSize + tileSize, status3->completedResourceSize); + EXPECT_EQ(1u, status3->completedTileCount); + EXPECT_EQ(tileSize, status3->completedTileSize); EXPECT_EQ(0u, log.uncheckedCount()); } @@ -482,21 +675,22 @@ TEST(OfflineDatabase, HasRegionResource) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; - OfflineRegion region = db.createRegion(definition, OfflineRegionMetadata()); + auto region = db.createRegion(definition, OfflineRegionMetadata()); + ASSERT_TRUE(region); - EXPECT_FALSE(bool(db.hasRegionResource(region.getID(), Resource::style("http://example.com/1")))); - EXPECT_FALSE(bool(db.hasRegionResource(region.getID(), Resource::style("http://example.com/20")))); + EXPECT_FALSE(bool(db.hasRegionResource(region->getID(), Resource::style("http://example.com/1")))); + EXPECT_FALSE(bool(db.hasRegionResource(region->getID(), Resource::style("http://example.com/20")))); Response response; response.data = randomString(1024); for (uint32_t i = 1; i <= 100; i++) { - db.putRegionResource(region.getID(), Resource::style("http://example.com/"s + util::toString(i)), response); + db.putRegionResource(region->getID(), Resource::style("http://example.com/"s + util::toString(i)), response); } - EXPECT_TRUE(bool(db.hasRegionResource(region.getID(), Resource::style("http://example.com/1")))); - EXPECT_TRUE(bool(db.hasRegionResource(region.getID(), Resource::style("http://example.com/20")))); - EXPECT_EQ(1024, *(db.hasRegionResource(region.getID(), Resource::style("http://example.com/20")))); + EXPECT_TRUE(bool(db.hasRegionResource(region->getID(), Resource::style("http://example.com/1")))); + EXPECT_TRUE(bool(db.hasRegionResource(region->getID(), Resource::style("http://example.com/20")))); + EXPECT_EQ(1024, *(db.hasRegionResource(region->getID(), Resource::style("http://example.com/20")))); EXPECT_EQ(0u, log.uncheckedCount()); } @@ -505,7 +699,8 @@ TEST(OfflineDatabase, HasRegionResourceTile) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; - OfflineRegion region = db.createRegion(definition, OfflineRegionMetadata()); + auto region = db.createRegion(definition, OfflineRegionMetadata()); + ASSERT_TRUE(region); Resource resource { Resource::Tile, "http://example.com/" }; resource.tileData = Resource::TileData { @@ -519,15 +714,16 @@ TEST(OfflineDatabase, HasRegionResourceTile) { response.data = std::make_shared("first"); - EXPECT_FALSE(bool(db.hasRegionResource(region.getID(), resource))); - db.putRegionResource(region.getID(), resource, response); - EXPECT_TRUE(bool(db.hasRegionResource(region.getID(), resource))); - EXPECT_EQ(5, *(db.hasRegionResource(region.getID(), resource))); + EXPECT_FALSE(bool(db.hasRegionResource(region->getID(), resource))); + db.putRegionResource(region->getID(), resource, response); + EXPECT_TRUE(bool(db.hasRegionResource(region->getID(), resource))); + EXPECT_EQ(5, *(db.hasRegionResource(region->getID(), resource))); - OfflineRegion anotherRegion = db.createRegion(definition, OfflineRegionMetadata()); - EXPECT_LT(region.getID(), anotherRegion.getID()); - EXPECT_TRUE(bool(db.hasRegionResource(anotherRegion.getID(), resource))); - EXPECT_EQ(5, *(db.hasRegionResource(anotherRegion.getID(), resource))); + auto anotherRegion = db.createRegion(definition, OfflineRegionMetadata()); + ASSERT_TRUE(anotherRegion); + EXPECT_LT(region->getID(), anotherRegion->getID()); + EXPECT_TRUE(bool(db.hasRegionResource(anotherRegion->getID(), resource))); + EXPECT_EQ(5, *(db.hasRegionResource(anotherRegion->getID(), resource))); EXPECT_EQ(0u, log.uncheckedCount()); @@ -539,8 +735,10 @@ TEST(OfflineDatabase, OfflineMapboxTileCount) { OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata; - OfflineRegion region1 = db.createRegion(definition, metadata); - OfflineRegion region2 = db.createRegion(definition, metadata); + auto region1 = db.createRegion(definition, metadata); + ASSERT_TRUE(region1); + auto region2 = db.createRegion(definition, metadata); + ASSERT_TRUE(region2); Resource nonMapboxTile = Resource::tile("http://example.com/", 1.0, 0, 0, 0, Tileset::Scheme::XYZ); Resource mapboxTile1 = Resource::tile("mapbox://tiles/1", 1.0, 0, 0, 0, Tileset::Scheme::XYZ); @@ -553,27 +751,27 @@ TEST(OfflineDatabase, OfflineMapboxTileCount) { EXPECT_EQ(0u, db.getOfflineMapboxTileCount()); // Count stays the same after putting a non-tile resource. - db.putRegionResource(region1.getID(), Resource::style("http://example.com/"), response); + db.putRegionResource(region1->getID(), Resource::style("http://example.com/"), response); EXPECT_EQ(0u, db.getOfflineMapboxTileCount()); // Count stays the same after putting a non-Mapbox tile. - db.putRegionResource(region1.getID(), nonMapboxTile, response); + db.putRegionResource(region1->getID(), nonMapboxTile, response); EXPECT_EQ(0u, db.getOfflineMapboxTileCount()); // Count increases after putting a Mapbox tile not used by another region. - db.putRegionResource(region1.getID(), mapboxTile1, response); + db.putRegionResource(region1->getID(), mapboxTile1, response); EXPECT_EQ(1u, db.getOfflineMapboxTileCount()); // Count stays the same after putting a Mapbox tile used by another region. - db.putRegionResource(region2.getID(), mapboxTile1, response); + db.putRegionResource(region2->getID(), mapboxTile1, response); EXPECT_EQ(1u, db.getOfflineMapboxTileCount()); // Count stays the same after putting a Mapbox tile used by the same region. - db.putRegionResource(region2.getID(), mapboxTile1, response); + db.putRegionResource(region2->getID(), mapboxTile1, response); EXPECT_EQ(1u, db.getOfflineMapboxTileCount()); // Count stays the same after deleting a region when the tile is still used by another region. - db.deleteRegion(std::move(region2)); + db.deleteRegion(std::move(*region2)); EXPECT_EQ(1u, db.getOfflineMapboxTileCount()); // Count stays the same after the putting a non-offline Mapbox tile. @@ -581,11 +779,11 @@ TEST(OfflineDatabase, OfflineMapboxTileCount) { EXPECT_EQ(1u, db.getOfflineMapboxTileCount()); // Count increases after putting a pre-existing, but non-offline Mapbox tile. - db.putRegionResource(region1.getID(), mapboxTile2, response); + db.putRegionResource(region1->getID(), mapboxTile2, response); EXPECT_EQ(2u, db.getOfflineMapboxTileCount()); // Count decreases after deleting a region when the tiles are not used by other regions. - db.deleteRegion(std::move(region1)); + db.deleteRegion(std::move(*region1)); EXPECT_EQ(0u, db.getOfflineMapboxTileCount()); EXPECT_EQ(0u, log.uncheckedCount()); @@ -596,7 +794,8 @@ TEST(OfflineDatabase, BatchInsertion) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; - OfflineRegion region = db.createRegion(definition, OfflineRegionMetadata()); + auto region = db.createRegion(definition, OfflineRegionMetadata()); + ASSERT_TRUE(region); Response response; response.data = randomString(1024); @@ -607,7 +806,7 @@ TEST(OfflineDatabase, BatchInsertion) { } OfflineRegionStatus status; - db.putRegionResources(region.getID(), resources, status); + db.putRegionResources(region->getID(), resources, status); for (uint32_t i = 1; i <= 100; i++) { EXPECT_TRUE(bool(db.get(Resource::style("http://example.com/"s + util::toString(i))))); @@ -621,7 +820,8 @@ TEST(OfflineDatabase, BatchInsertionMapboxTileCountExceeded) { OfflineDatabase db(":memory:", 1024 * 100); db.setOfflineMapboxTileCountLimit(1); OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; - OfflineRegion region = db.createRegion(definition, OfflineRegionMetadata()); + auto region = db.createRegion(definition, OfflineRegionMetadata()); + ASSERT_TRUE(region); Response response; response.data = randomString(1024); @@ -633,68 +833,26 @@ TEST(OfflineDatabase, BatchInsertionMapboxTileCountExceeded) { OfflineRegionStatus status; try { - db.putRegionResources(region.getID(), resources, status); + db.putRegionResources(region->getID(), resources, status); EXPECT_FALSE(true); } catch (const MapboxTileLimitExceededException&) { // Expected } - EXPECT_EQ(status.completedTileCount, 1u); - EXPECT_EQ(status.completedResourceCount, 2u); - EXPECT_EQ(db.getRegionCompletedStatus(region.getID()).completedTileCount, 1u); - EXPECT_EQ(db.getRegionCompletedStatus(region.getID()).completedResourceCount, 2u); + EXPECT_EQ(0u, status.completedTileCount); + EXPECT_EQ(0u, status.completedResourceCount); + const auto completedStatus = db.getRegionCompletedStatus(region->getID()); + ASSERT_TRUE(completedStatus); + EXPECT_EQ(1u, completedStatus->completedTileCount); + EXPECT_EQ(2u, completedStatus->completedResourceCount); EXPECT_EQ(0u, log.uncheckedCount()); } -static int databasePageCount(const std::string& path) { - mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); - mapbox::sqlite::Statement stmt{ db, "pragma page_count" }; - mapbox::sqlite::Query query{ stmt }; - query.run(); - return query.get(0); -} - -static int databaseUserVersion(const std::string& path) { - mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); - mapbox::sqlite::Statement stmt{ db, "pragma user_version" }; - mapbox::sqlite::Query query{ stmt }; - query.run(); - return query.get(0); -} - -static std::string databaseJournalMode(const std::string& path) { - mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); - mapbox::sqlite::Statement stmt{ db, "pragma journal_mode" }; - mapbox::sqlite::Query query{ stmt }; - query.run(); - return query.get(0); -} - -static int databaseSyncMode(const std::string& path) { - mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); - mapbox::sqlite::Statement stmt{ db, "pragma synchronous" }; - mapbox::sqlite::Query query{ stmt }; - query.run(); - return query.get(0); -} - -static std::vector databaseTableColumns(const std::string& path, const std::string& name) { - mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadOnly); - const auto sql = std::string("pragma table_info(") + name + ")"; - mapbox::sqlite::Statement stmt{ db, sql.c_str() }; - mapbox::sqlite::Query query{ stmt }; - std::vector columns; - while (query.run()) { - columns.push_back(query.get(1)); - } - return columns; -} - TEST(OfflineDatabase, MigrateFromV2Schema) { // v2.db is a v2 database containing a single offline region with a small number of resources. FixtureLog log; - util::deleteFile(filename); + deleteDatabaseFiles(); util::copyFile(filename, "test/fixtures/offline_database/v2.db"); { @@ -715,7 +873,7 @@ TEST(OfflineDatabase, MigrateFromV2Schema) { TEST(OfflineDatabase, MigrateFromV3Schema) { // v3.db is a v3 database, migrated from v2. FixtureLog log; - util::deleteFile(filename); + deleteDatabaseFiles(); util::copyFile(filename, "test/fixtures/offline_database/v3.db"); { @@ -734,7 +892,7 @@ TEST(OfflineDatabase, MigrateFromV3Schema) { TEST(OfflineDatabase, MigrateFromV4Schema) { // v4.db is a v4 database, migrated from v2 & v3. This database used `journal_mode = WAL` and `synchronous = NORMAL`. FixtureLog log; - util::deleteFile(filename); + deleteDatabaseFiles(); util::copyFile(filename, "test/fixtures/offline_database/v4.db"); { @@ -760,7 +918,7 @@ TEST(OfflineDatabase, MigrateFromV4Schema) { TEST(OfflineDatabase, MigrateFromV5Schema) { // v5.db is a v5 database, migrated from v2, v3 & v4. FixtureLog log; - util::deleteFile(filename); + deleteDatabaseFiles(); util::copyFile(filename, "test/fixtures/offline_database/v5.db"); { @@ -808,3 +966,133 @@ TEST(OfflineDatabase, DowngradeSchema) { EXPECT_EQ(1u, log.count({ EventSeverity::Warning, Event::Database, -1, "Removing existing incompatible offline database" })); EXPECT_EQ(0u, log.uncheckedCount()); } + +TEST(OfflineDatabase, CorruptDatabaseOnOpen) { + FixtureLog log; + util::deleteFile(filename); + util::copyFile(filename, "test/fixtures/offline_database/corrupt-immediate.db"); + + // This database is corrupt in a way that will prevent opening the database. + OfflineDatabase db(filename); + EXPECT_EQ(1u, log.count(error(ResultCode::Corrupt, "Can't open database: database disk image is malformed"), true)); + EXPECT_EQ(1u, log.count(warning(static_cast(-1), "Removing existing incompatible offline database"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + // Now try inserting and reading back to make sure we have a valid database. + for (const auto& res : { fixture::resource, fixture::tile }) { + EXPECT_EQ(std::make_pair(true, uint64_t(5)), db.put(res, fixture::response)); + EXPECT_EQ(0u, log.uncheckedCount()); + auto result = db.get(res); + EXPECT_EQ(0u, log.uncheckedCount()); + ASSERT_TRUE(result && result->data); + EXPECT_EQ("first", *result->data); + } +} + +TEST(OfflineDatabase, CorruptDatabaseOnQuery) { + FixtureLog log; + util::deleteFile(filename); + util::copyFile(filename, "test/fixtures/offline_database/corrupt-delayed.db"); + + // This database is corrupt in a way that won't manifest itself until we start querying it, + // so just opening it will not cause an error. + OfflineDatabase db(filename); + + // Just opening this corrupt database should not have produced an error yet, since + // PRAGMA user_version still succeeds with this database. + EXPECT_EQ(0u, log.uncheckedCount()); + + // The first request fails because the database is corrupt and has to be recreated. + EXPECT_EQ(nullopt, db.get(fixture::tile)); + EXPECT_EQ(1u, log.count(error(ResultCode::Corrupt, "Can't read resource: database disk image is malformed"), true)); + EXPECT_EQ(1u, log.count(warning(static_cast(-1), "Removing existing incompatible offline database"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + // Now try inserting and reading back to make sure we have a valid database. + for (const auto& res : { fixture::resource, fixture::tile }) { + EXPECT_EQ(std::make_pair(true, uint64_t(5)), db.put(res, fixture::response)); + EXPECT_EQ(0u, log.uncheckedCount()); + auto result = db.get(res); + EXPECT_EQ(0u, log.uncheckedCount()); + ASSERT_TRUE(result && result->data); + EXPECT_EQ("first", *result->data); + } +} + +#ifndef __QT__ // Qt doesn't expose the ability to register virtual file system handlers. +TEST(OfflineDatabase, TEST_REQUIRES_WRITE(DisallowedIO)) { + FixtureLog log; + deleteDatabaseFiles(); + test::SQLite3TestFS fs; + + OfflineDatabase db(filename_test_fs); + EXPECT_EQ(0u, log.uncheckedCount()); + + // First, create a region object so that we can try deleting it later. + OfflineTilePyramidRegionDefinition definition( + "mapbox://style", LatLngBounds::hull({ 37.66, -122.57 }, { 37.83, -122.32 }), 0, 8, 2); + auto region = db.createRegion(definition, {}); + ASSERT_TRUE(region); + + // Now forbid any type of IO on the database and test that none of the calls crashes. + fs.allowIO(false); + + EXPECT_EQ(nullopt, db.get(fixture::resource)); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't update timestamp: authorization denied"))); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't read resource: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + EXPECT_EQ(std::make_pair(false, uint64_t(0)), db.put(fixture::resource, fixture::response)); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't write resource: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + const auto regions = db.listRegions(); + EXPECT_TRUE(regions.empty()); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't list regions: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + EXPECT_EQ(nullopt, db.createRegion(definition, {})); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't create region: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + EXPECT_EQ(nullopt, db.updateMetadata(region->getID(), {})); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't update region metadata: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + EXPECT_EQ(nullopt, db.getRegionResource(region->getID(), fixture::resource)); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't update timestamp: authorization denied"))); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't read region resource: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + EXPECT_EQ(nullopt, db.hasRegionResource(region->getID(), fixture::resource)); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't query region resource: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + EXPECT_EQ(0u, db.putRegionResource(region->getID(), fixture::resource, fixture::response)); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't write region resource: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + OfflineRegionStatus status; + db.putRegionResources(region->getID(), { std::make_tuple(fixture::resource, fixture::response) }, status); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't write region resources: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + EXPECT_EQ(nullopt, db.getRegionDefinition(region->getID())); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't load region: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + EXPECT_EQ(nullopt, db.getRegionCompletedStatus(region->getID())); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't get region status: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + db.deleteRegion(std::move(*region)); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't delete region: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + EXPECT_EQ(std::numeric_limits::max(), db.getOfflineMapboxTileCount()); + EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't get offline Mapbox tile count: authorization denied"))); + EXPECT_EQ(0u, log.uncheckedCount()); + + fs.reset(); +} +#endif // __QT__ diff --git a/test/storage/offline_download.test.cpp b/test/storage/offline_download.test.cpp index 57780eba40..e87ad6c370 100644 --- a/test/storage/offline_download.test.cpp +++ b/test/storage/offline_download.test.cpp @@ -42,7 +42,7 @@ public: OfflineDatabase db { ":memory:" }; std::size_t size = 0; - OfflineRegion createRegion() { + optional createRegion() { OfflineRegionDefinition definition { "", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 1.0 }; OfflineRegionMetadata metadata; return db.createRegion(definition, metadata); @@ -60,9 +60,10 @@ public: TEST(OfflineDownload, NoSubresources) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -100,9 +101,10 @@ TEST(OfflineDownload, NoSubresources) { TEST(OfflineDownload, InlineSource) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -140,9 +142,10 @@ TEST(OfflineDownload, InlineSource) { TEST(OfflineDownload, GeoJSONSource) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -175,9 +178,10 @@ TEST(OfflineDownload, GeoJSONSource) { TEST(OfflineDownload, Activate) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -250,9 +254,10 @@ TEST(OfflineDownload, Activate) { TEST(OfflineDownload, DoesNotFloodTheFileSourceWithRequests) { FakeFileSource fileSource; OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, fileSource); @@ -272,9 +277,10 @@ TEST(OfflineDownload, DoesNotFloodTheFileSourceWithRequests) { TEST(OfflineDownload, GetStatusNoResources) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); OfflineRegionStatus status = download.getStatus(); @@ -289,9 +295,10 @@ TEST(OfflineDownload, GetStatusNoResources) { TEST(OfflineDownload, GetStatusStyleComplete) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -311,9 +318,10 @@ TEST(OfflineDownload, GetStatusStyleComplete) { TEST(OfflineDownload, GetStatusStyleAndSourceComplete) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -337,9 +345,10 @@ TEST(OfflineDownload, GetStatusStyleAndSourceComplete) { TEST(OfflineDownload, RequestError) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -365,9 +374,10 @@ TEST(OfflineDownload, RequestError) { TEST(OfflineDownload, RequestErrorsAreRetried) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -398,9 +408,10 @@ TEST(OfflineDownload, RequestErrorsAreRetried) { TEST(OfflineDownload, TileCountLimitExceededNoTileResponse) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -440,9 +451,10 @@ TEST(OfflineDownload, TileCountLimitExceededNoTileResponse) { TEST(OfflineDownload, TileCountLimitExceededWithTileResponse) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -494,9 +506,10 @@ TEST(OfflineDownload, TileCountLimitExceededWithTileResponse) { TEST(OfflineDownload, WithPreviouslyExistingTile) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -528,9 +541,10 @@ TEST(OfflineDownload, WithPreviouslyExistingTile) { TEST(OfflineDownload, ReactivatePreviouslyCompletedDownload) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -556,7 +570,7 @@ TEST(OfflineDownload, ReactivatePreviouslyCompletedDownload) { test.loop.run(); OfflineDownload redownload( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); @@ -595,9 +609,10 @@ TEST(OfflineDownload, ReactivatePreviouslyCompletedDownload) { TEST(OfflineDownload, Deactivate) { OfflineTest test; - OfflineRegion region = test.createRegion(); + auto region = test.createRegion(); + ASSERT_TRUE(region); OfflineDownload download( - region.getID(), + region->getID(), OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), test.db, test.fileSource); diff --git a/test/storage/sqlite.test.cpp b/test/storage/sqlite.test.cpp index 22958c8bed..cdbb7f26d7 100644 --- a/test/storage/sqlite.test.cpp +++ b/test/storage/sqlite.test.cpp @@ -38,12 +38,6 @@ TEST(SQLite, TEST_REQUIRES_WRITE(TryOpen)) { auto result = mapbox::sqlite::Database::tryOpen("test/fixtures/offline_database/foobar123.db", mapbox::sqlite::ReadOnly); ASSERT_TRUE(result.is()); ASSERT_EQ(result.get().code, mapbox::sqlite::ResultCode::CantOpen); - -#ifndef __QT__ - // Only non-Qt platforms are setting a logger on the SQLite object. - EXPECT_EQ(1u, log.count({ EventSeverity::Info, Event::Database, static_cast(mapbox::sqlite::ResultCode::CantOpen), "cannot open file" }, true)); - EXPECT_EQ(1u, log.count({ EventSeverity::Info, Event::Database, static_cast(mapbox::sqlite::ResultCode::CantOpen), "No such file or directory" }, true)); -#endif EXPECT_EQ(0u, log.uncheckedCount()); } -- cgit v1.2.1 From 89515de769aea0b54a800514f7deaf65649d9d54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 6 Aug 2018 16:36:03 +0200 Subject: [test] add test for pending offline download when the disk is full --- test/storage/offline_download.test.cpp | 78 +++++++++++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 1 deletion(-) diff --git a/test/storage/offline_download.test.cpp b/test/storage/offline_download.test.cpp index e87ad6c370..f979d42601 100644 --- a/test/storage/offline_download.test.cpp +++ b/test/storage/offline_download.test.cpp @@ -1,5 +1,7 @@ #include #include +#include +#include #include #include @@ -10,11 +12,29 @@ #include #include +#include #include #include using namespace mbgl; using namespace std::literals::string_literals; +using mapbox::sqlite::ResultCode; + +#ifndef __QT__ // Qt doesn't expose the ability to register virtual file system handlers. +static constexpr const char* filename = "test/fixtures/offline_download/offline.db"; +static constexpr const char* filename_test_fs = "file:test/fixtures/offline_download/offline.db?vfs=test_fs"; + +static void deleteDatabaseFiles() { + // Delete leftover journaling files as well. + util::deleteFile(filename); + util::deleteFile(filename + "-wal"s); + util::deleteFile(filename + "-journal"s); +} + +static FixtureLog::Message warning(ResultCode code, const char* message) { + return { EventSeverity::Warning, Event::Database, static_cast(code), message }; +} +#endif class MockObserver : public OfflineRegionObserver { public: @@ -37,9 +57,12 @@ public: class OfflineTest { public: + OfflineTest(const std::string& path = ":memory:") : db(path) { + } + util::RunLoop loop; StubFileSource fileSource; - OfflineDatabase db { ":memory:" }; + OfflineDatabase db; std::size_t size = 0; optional createRegion() { @@ -636,3 +659,56 @@ TEST(OfflineDownload, Deactivate) { test.loop.run(); } + +#ifndef __QT__ // Qt doesn't expose the ability to register virtual file system handlers. +TEST(OfflineDownload, DiskFull) { + FixtureLog log; + deleteDatabaseFiles(); + test::SQLite3TestFS fs; + + OfflineTest test{ filename_test_fs }; + EXPECT_EQ(0u, log.uncheckedCount()); + + auto region = test.createRegion(); + ASSERT_TRUE(region); + EXPECT_EQ(0u, log.uncheckedCount()); + + // Simulate a full disk. + fs.setWriteLimit(8192); + + OfflineDownload download( + region->getID(), + OfflineTilePyramidRegionDefinition("http://127.0.0.1:3000/style.json", LatLngBounds::world(), 0.0, 0.0, 1.0), + test.db, test.fileSource); + + bool hasRequestedStyle = false; + + test.fileSource.styleResponse = [&] (const Resource& resource) { + EXPECT_EQ("http://127.0.0.1:3000/style.json", resource.url); + hasRequestedStyle = true; + return test.response("empty.style.json"); + }; + + auto observer = std::make_unique(); + + observer->statusChangedFn = [&] (OfflineRegionStatus status) { + EXPECT_EQ(OfflineRegionDownloadState::Active, status.downloadState); + EXPECT_EQ(0u, status.completedResourceCount); + EXPECT_EQ(0u, status.completedResourceSize); + EXPECT_EQ(hasRequestedStyle, status.requiredResourceCountIsPrecise); + EXPECT_FALSE(status.complete()); + + if (hasRequestedStyle) { + EXPECT_EQ(1u, log.count(warning(ResultCode::Full, "Can't write region resources: database or disk is full"))); + EXPECT_EQ(0u, log.uncheckedCount()); + test.loop.stop(); + } + }; + + download.setObserver(std::move(observer)); + download.setState(OfflineRegionDownloadState::Active); + + test.loop.run(); + EXPECT_EQ(0u, log.uncheckedCount()); +} +#endif // __QT__ -- cgit v1.2.1 From 6e06e55b95fdb9070d32d44786441255871dbb0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 13 Aug 2018 16:29:14 -0700 Subject: WIP: use expected for passing on errors --- CMakeLists.txt | 8 +-- bin/offline.cpp | 6 +-- cmake/core-files.cmake | 1 + cmake/filesource.cmake | 3 ++ cmake/mbgl.cmake | 55 +++++++------------- include/mbgl/storage/default_file_source.hpp | 15 +++--- include/mbgl/storage/offline.hpp | 2 + platform/android/config.cmake | 1 + platform/android/src/offline/offline_manager.cpp | 23 +++++---- platform/android/src/offline/offline_region.cpp | 20 ++++---- platform/darwin/src/MGLOfflinePack.mm | 2 +- platform/darwin/src/MGLOfflineStorage.mm | 24 ++++----- platform/default/default_file_source.cpp | 58 ++++++++-------------- platform/default/mbgl/storage/offline_database.cpp | 35 +++++++------ platform/default/mbgl/storage/offline_database.hpp | 16 +++--- platform/ios/ios.xcodeproj/project.pbxproj | 10 +++- scripts/config.xcconfig.in | 8 +-- test/storage/offline_database.test.cpp | 37 +++++++------- test/storage/offline_download.test.cpp | 2 +- 19 files changed, 156 insertions(+), 170 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b6b86d9a8d..a02b4b9173 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -176,8 +176,10 @@ if(WITH_NODEJS AND COMMAND mbgl_platform_node) endif() if(CMAKE_GENERATOR STREQUAL "Xcode") - write_xcconfig_target_properties( - mbgl-core - mbgl-filesource + set_xcconfig_target_properties(mbgl-core) + set_xcconfig_target_properties(mbgl-filesource) + file(GENERATE + OUTPUT "${CMAKE_BINARY_DIR}/config.xcconfig" + INPUT "${CMAKE_SOURCE_DIR}/scripts/config.xcconfig.in" ) endif() diff --git a/bin/offline.cpp b/bin/offline.cpp index 8b42ab7b72..603f0b848a 100644 --- a/bin/offline.cpp +++ b/bin/offline.cpp @@ -136,9 +136,9 @@ int main(int argc, char *argv[]) { std::signal(SIGINT, [] (int) { stop(); }); - fileSource.createOfflineRegion(definition, metadata, [&] (std::exception_ptr error, optional region_) { - if (error) { - std::cerr << "Error creating region: " << util::toString(error) << std::endl; + fileSource.createOfflineRegion(definition, metadata, [&] (mbgl::expected region_) { + if (!region_) { + std::cerr << "Error creating region: " << util::toString(region_.error()) << std::endl; loop.stop(); exit(1); } else { diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index e875f5b142..02335fef7a 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -664,6 +664,7 @@ set(MBGL_CORE_FILES include/mbgl/util/enum.hpp include/mbgl/util/event.hpp include/mbgl/util/exception.hpp + include/mbgl/util/expected.hpp include/mbgl/util/feature.hpp include/mbgl/util/font_stack.hpp include/mbgl/util/geo.hpp diff --git a/cmake/filesource.cmake b/cmake/filesource.cmake index ccd2192f39..9b7a4a1138 100644 --- a/cmake/filesource.cmake +++ b/cmake/filesource.cmake @@ -1,3 +1,5 @@ +add_vendor_target(expected INTERFACE) + add_library(mbgl-filesource STATIC # File source include/mbgl/storage/default_file_source.hpp @@ -39,6 +41,7 @@ target_include_directories(mbgl-filesource target_link_libraries(mbgl-filesource PUBLIC mbgl-core + PUBLIC expected ) mbgl_filesource() diff --git a/cmake/mbgl.cmake b/cmake/mbgl.cmake index bb029a47db..3abc974feb 100644 --- a/cmake/mbgl.cmake +++ b/cmake/mbgl.cmake @@ -115,13 +115,15 @@ endfunction() # Creates a library target for a vendored dependency function(add_vendor_target NAME TYPE) - add_library(${NAME} ${TYPE} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/empty.cpp") set(INCLUDE_TYPE "INTERFACE") set(SOURCE_TYPE "INTERFACE") if (TYPE STREQUAL "STATIC" OR TYPE STREQUAL "SHARED") + add_library(${NAME} ${TYPE} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/empty.cpp") set(INCLUDE_TYPE "PUBLIC") set(SOURCE_TYPE "PRIVATE") set_target_properties(${NAME} PROPERTIES SOURCES "") + else() + add_library(${NAME} ${TYPE}) endif() set_target_properties(${NAME} PROPERTIES INTERFACE_SOURCES "") file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/vendor/${NAME}/files.txt" FILES) @@ -137,48 +139,25 @@ macro(set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) endmacro (set_xcode_property) -function(_get_xcconfig_property target var) - get_property(result TARGET ${target} PROPERTY INTERFACE_${var} SET) - if (result) - get_property(result TARGET ${target} PROPERTY INTERFACE_${var}) - if (var STREQUAL "LINK_LIBRARIES") - # Remove target names from the list of linker flags, since Xcode can't deal with them. - set(link_flags) - foreach(item IN LISTS result) - if (NOT TARGET ${item}) - list(APPEND link_flags ${item}) - endif() - endforeach() - set(result "${link_flags}") +function(set_xcconfig_target_properties target) + # Create a list of linked libraries for use in the xcconfig generation script. + get_property(result TARGET ${target} PROPERTY INTERFACE_LINK_LIBRARIES) + string(GENEX_STRIP "${result}" result) + # Remove target names from the list of linker flags, since Xcode can't deal with them. + set(link_flags) + foreach(item IN LISTS result) + if (NOT TARGET ${item}) + list(APPEND link_flags ${item}) endif() - string(REPLACE ";-framework " ";-framework;" result "${result}") - string(REPLACE ";" "\" \"" result "${result}") - string(REPLACE "-" "_" target "${target}") - set(${target}_${var} "${result}" PARENT_SCOPE) - endif() -endfunction() - -if(MBGL_PLATFORM STREQUAL "ios") - execute_process( - COMMAND git submodule update --init platform/ios/vendor/mapbox-events-ios - WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") -endif() - -function(write_xcconfig_target_properties) - foreach(target ${ARGN}) - _get_xcconfig_property(${target} INCLUDE_DIRECTORIES) - _get_xcconfig_property(${target} LINK_LIBRARIES) endforeach() - configure_file( - "${CMAKE_SOURCE_DIR}/scripts/config.xcconfig.in" - "${CMAKE_BINARY_DIR}/config.xcconfig" - @ONLY - ) + string(REPLACE ";-framework " ";-framework;" link_flags "${link_flags}") + string(REPLACE ";" "\" \"" link_flags "${link_flags}") + set_xcode_property(${target} XCCONFIG_LINK_LIBRARIES "${link_flags}") endfunction() # Set Xcode project build settings to be consistent with the CXX flags we're # using. (Otherwise, Xcode's defaults may override some of these.) -macro(initialize_xcode_cxx_build_settings target) +function(initialize_xcode_cxx_build_settings target) # -Wall set_xcode_property(${target} GCC_WARN_SIGN_COMPARE YES) set_xcode_property(${target} GCC_WARN_UNINITIALIZED_AUTOS YES) @@ -206,7 +185,7 @@ macro(initialize_xcode_cxx_build_settings target) # -flto set_xcode_property(${target} LLVM_LTO $<$,$>:YES>) -endmacro(initialize_xcode_cxx_build_settings) +endfunction() # CMake 3.1 does not have this yet. set(CMAKE_CXX14_STANDARD_COMPILE_OPTION "-std=c++14") diff --git a/include/mbgl/storage/default_file_source.hpp b/include/mbgl/storage/default_file_source.hpp index b9c8de5052..e048d82af2 100644 --- a/include/mbgl/storage/default_file_source.hpp +++ b/include/mbgl/storage/default_file_source.hpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -55,8 +56,7 @@ public: * callback, which will be executed on the database thread; it is the responsibility * of the SDK bindings to re-execute a user-provided callback on the main thread. */ - void listOfflineRegions(std::function>)>); + void listOfflineRegions(std::function)>); /* * Create an offline region in the database. @@ -71,16 +71,14 @@ public: */ void createOfflineRegion(const OfflineRegionDefinition& definition, const OfflineRegionMetadata& metadata, - std::function)>); + std::function)>); /* * Update an offline region metadata in the database. */ void updateOfflineMetadata(const int64_t regionID, const OfflineRegionMetadata& metadata, - std::function)>); + std::function)>); /* * Register an observer to be notified when the state of the region changes. */ @@ -97,8 +95,9 @@ public: * executed on the database thread; it is the responsibility of the SDK bindings * to re-execute a user-provided callback on the main thread. */ - void getOfflineRegionStatus(OfflineRegion&, std::function)>) const; + void getOfflineRegionStatus( + OfflineRegion&, + std::function)>) const; /* * Remove an offline region from the database and perform any resources evictions diff --git a/include/mbgl/storage/offline.hpp b/include/mbgl/storage/offline.hpp index 2193f8d09e..62353446fa 100644 --- a/include/mbgl/storage/offline.hpp +++ b/include/mbgl/storage/offline.hpp @@ -210,4 +210,6 @@ private: const OfflineRegionMetadata metadata; }; +using OfflineRegions = std::vector; + } // namespace mbgl diff --git a/platform/android/config.cmake b/platform/android/config.cmake index 001a45e613..bd65bc517f 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -97,6 +97,7 @@ macro(mbgl_platform_core) target_link_libraries(mbgl-core PRIVATE nunicode + PUBLIC expected PUBLIC -llog PUBLIC -landroid PUBLIC -ljnigraphics diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp index 4960ae2845..4f94a1c3a5 100644 --- a/platform/android/src/offline/offline_manager.cpp +++ b/platform/android/src/offline/offline_manager.cpp @@ -26,15 +26,18 @@ void OfflineManager::listOfflineRegions(jni::JNIEnv& env_, jni::Object(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()), jFileSource = std::shared_ptr(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()) - ](std::exception_ptr error, mbgl::optional> regions) mutable { + ](mbgl::expected regions) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); - if (error) { - OfflineManager::ListOfflineRegionsCallback::onError(*env, jni::Object(*callback), error); - } else if (regions) { - OfflineManager::ListOfflineRegionsCallback::onList(*env, jni::Object(*jFileSource), jni::Object(*callback), std::move(regions)); + if (regions) { + OfflineManager::ListOfflineRegionsCallback::onList( + *env, jni::Object(*jFileSource), + jni::Object(*callback), std::move(*regions)); + } else { + OfflineManager::ListOfflineRegionsCallback::onError( + *env, jni::Object(*callback), regions.error()); } }); } @@ -59,19 +62,19 @@ void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, //Keep a shared ptr to a global reference of the callback and file source so they are not GC'd in the meanwhile callback = std::shared_ptr(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()), jFileSource = std::shared_ptr(jFileSource_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()) - ](std::exception_ptr error, mbgl::optional region) mutable { + ](mbgl::expected region) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); - if (error) { - OfflineManager::CreateOfflineRegionCallback::onError(*env, jni::Object(*callback), error); - } else if (region) { + if (region) { OfflineManager::CreateOfflineRegionCallback::onCreate( *env, jni::Object(*jFileSource), - jni::Object(*callback), std::move(region) + jni::Object(*callback), std::move(*region) ); + } else { + OfflineManager::CreateOfflineRegionCallback::onError(*env, jni::Object(*callback), region.error()); } }); } diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp index 27de76fb00..fe4dbecf14 100644 --- a/platform/android/src/offline/offline_region.cpp +++ b/platform/android/src/offline/offline_region.cpp @@ -107,14 +107,14 @@ void OfflineRegion::getOfflineRegionStatus(jni::JNIEnv& env_, jni::Object(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()) - ](std::exception_ptr error, mbgl::optional status) mutable { + ](mbgl::expected status) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); - if (error) { - OfflineRegionStatusCallback::onError(*env, jni::Object(*callback), error); - } else if (status) { - OfflineRegionStatusCallback::onStatus(*env, jni::Object(*callback), std::move(status)); + if (status) { + OfflineRegionStatusCallback::onStatus(*env, jni::Object(*callback), std::move(*status)); + } else { + OfflineRegionStatusCallback::onError(*env, jni::Object(*callback), status.error()); } }); } @@ -144,14 +144,14 @@ void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, jni::ArraygetID(), metadata, [ //Ensure the object is not gc'd in the meanwhile callback = std::shared_ptr(callback_.NewGlobalRef(env_).release()->Get(), GenericGlobalRefDeleter()) - ](std::exception_ptr error, mbgl::optional data) mutable { + ](mbgl::expected data) mutable { // Reattach, the callback comes from a different thread android::UniqueEnv env = android::AttachEnv(); - if (error) { - OfflineRegionUpdateMetadataCallback::onError(*env, jni::Object(*callback), error); - } else if (data) { - OfflineRegionUpdateMetadataCallback::onUpdate(*env, jni::Object(*callback), std::move(data)); + if (data) { + OfflineRegionUpdateMetadataCallback::onUpdate(*env, jni::Object(*callback), std::move(*data)); + } else { + OfflineRegionUpdateMetadataCallback::onError(*env, jni::Object(*callback), data.error()); } }); } diff --git a/platform/darwin/src/MGLOfflinePack.mm b/platform/darwin/src/MGLOfflinePack.mm index 9d903ee841..7bbc681c88 100644 --- a/platform/darwin/src/MGLOfflinePack.mm +++ b/platform/darwin/src/MGLOfflinePack.mm @@ -141,7 +141,7 @@ private: mbgl::DefaultFileSource *mbglFileSource = [[MGLOfflineStorage sharedOfflineStorage] mbglFileSource]; __weak MGLOfflinePack *weakSelf = self; - mbglFileSource->getOfflineRegionStatus(*_mbglOfflineRegion, [&, weakSelf](__unused std::exception_ptr exception, mbgl::optional status) { + mbglFileSource->getOfflineRegionStatus(*_mbglOfflineRegion, [&, weakSelf](mbgl::expected status) { if (status) { mbgl::OfflineRegionStatus checkedStatus = *status; dispatch_async(dispatch_get_main_queue(), ^{ diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm index e6c10e942b..05e1b06338 100644 --- a/platform/darwin/src/MGLOfflineStorage.mm +++ b/platform/darwin/src/MGLOfflineStorage.mm @@ -288,16 +288,16 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio const mbgl::OfflineTilePyramidRegionDefinition regionDefinition = [(id )region offlineRegionDefinition]; mbgl::OfflineRegionMetadata metadata(context.length); [context getBytes:&metadata[0] length:metadata.size()]; - self.mbglFileSource->createOfflineRegion(regionDefinition, metadata, [&, completion](std::exception_ptr exception, mbgl::optional mbglOfflineRegion) { + self.mbglFileSource->createOfflineRegion(regionDefinition, metadata, [&, completion](mbgl::expected mbglOfflineRegion) { NSError *error; - if (exception) { - NSString *errorDescription = @(mbgl::util::toString(exception).c_str()); + if (!mbglOfflineRegion) { + NSString *errorDescription = @(mbgl::util::toString(mbglOfflineRegion.error()).c_str()); error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:errorDescription ? @{ NSLocalizedDescriptionKey: errorDescription, } : nil]; } if (completion) { - MGLOfflinePack *pack = mbglOfflineRegion ? [[MGLOfflinePack alloc] initWithMBGLRegion:new mbgl::OfflineRegion(std::move(*mbglOfflineRegion))] : nil; + MGLOfflinePack *pack = mbglOfflineRegion ? [[MGLOfflinePack alloc] initWithMBGLRegion:new mbgl::OfflineRegion(std::move(mbglOfflineRegion.value()))] : nil; dispatch_async(dispatch_get_main_queue(), [&, completion, error, pack](void) { completion(pack, error); }); @@ -347,17 +347,17 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio } - (void)getPacksWithCompletionHandler:(void (^)(NSArray *packs, NSError * _Nullable error))completion { - self.mbglFileSource->listOfflineRegions([&, completion](std::exception_ptr exception, mbgl::optional> regions) { + self.mbglFileSource->listOfflineRegions([&, completion](mbgl::expected result) { NSError *error; - if (exception) { + NSMutableArray *packs; + if (!result) { error = [NSError errorWithDomain:MGLErrorDomain code:-1 userInfo:@{ - NSLocalizedDescriptionKey: @(mbgl::util::toString(exception).c_str()), + NSLocalizedDescriptionKey: @(mbgl::util::toString(result.error()).c_str()), }]; - } - NSMutableArray *packs; - if (regions) { - packs = [NSMutableArray arrayWithCapacity:regions->size()]; - for (mbgl::OfflineRegion ®ion : *regions) { + } else { + auto& regions = result.value(); + packs = [NSMutableArray arrayWithCapacity:regions.size()]; + for (auto ®ion : regions) { MGLOfflinePack *pack = [[MGLOfflinePack alloc] initWithMBGLRegion:new mbgl::OfflineRegion(std::move(region))]; [packs addObject:pack]; } diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp index 051e1b125c..93f10eea72 100644 --- a/platform/default/default_file_source.cpp +++ b/platform/default/default_file_source.cpp @@ -45,61 +45,44 @@ public: onlineFileSource.setResourceTransform(std::move(transform)); } - void listRegions(std::function>)> callback) { - try { - callback({}, offlineDatabase->listRegions()); - } catch (...) { - callback(std::current_exception(), {}); - } + void listRegions(std::function)> callback) { + callback(offlineDatabase->listRegions()); } void createRegion(const OfflineRegionDefinition& definition, const OfflineRegionMetadata& metadata, - std::function)> callback) { - try { - callback({}, offlineDatabase->createRegion(definition, metadata)); - } catch (...) { - callback(std::current_exception(), {}); - } + std::function)> callback) { + callback(offlineDatabase->createRegion(definition, metadata)); } void updateMetadata(const int64_t regionID, const OfflineRegionMetadata& metadata, - std::function)> callback) { - try { - callback({}, offlineDatabase->updateMetadata(regionID, metadata)); - } catch (...) { - callback(std::current_exception(), {}); - } + std::function)> callback) { + callback(offlineDatabase->updateMetadata(regionID, metadata)); } - void getRegionStatus(int64_t regionID, std::function)> callback) { + void getRegionStatus(int64_t regionID, std::function)> callback) { if (auto download = getDownload(regionID)) { - callback({}, download->getStatus()); + callback(download.value()->getStatus()); } else { - callback(std::current_exception(), {}); + callback(unexpected(download.error())); } } void deleteRegion(OfflineRegion&& region, std::function callback) { - try { - downloads.erase(region.getID()); - offlineDatabase->deleteRegion(std::move(region)); - callback({}); - } catch (...) { - callback(std::current_exception()); - } + downloads.erase(region.getID()); + callback(offlineDatabase->deleteRegion(std::move(region))); } void setRegionObserver(int64_t regionID, std::unique_ptr observer) { if (auto download = getDownload(regionID)) { - download->setObserver(std::move(observer)); + download.value()->setObserver(std::move(observer)); } } void setRegionDownloadState(int64_t regionID, OfflineRegionDownloadState state) { if (auto download = getDownload(regionID)) { - download->setState(state); + download.value()->setState(state); } } @@ -185,17 +168,16 @@ public: } private: - OfflineDownload* getDownload(int64_t regionID) { + expected getDownload(int64_t regionID) { auto it = downloads.find(regionID); if (it != downloads.end()) { return it->second.get(); } auto definition = offlineDatabase->getRegionDefinition(regionID); if (!definition) { - return nullptr; + return unexpected(definition.error()); } - - auto download = std::make_unique(regionID, std::move(*definition), + auto download = std::make_unique(regionID, std::move(definition.value()), *offlineDatabase, onlineFileSource); return downloads.emplace(regionID, std::move(download)).first->second.get(); } @@ -266,19 +248,19 @@ std::unique_ptr DefaultFileSource::request(const Resource& resourc return std::move(req); } -void DefaultFileSource::listOfflineRegions(std::function>)> callback) { +void DefaultFileSource::listOfflineRegions(std::function)> callback) { impl->actor().invoke(&Impl::listRegions, callback); } void DefaultFileSource::createOfflineRegion(const OfflineRegionDefinition& definition, const OfflineRegionMetadata& metadata, - std::function)> callback) { + std::function)> callback) { impl->actor().invoke(&Impl::createRegion, definition, metadata, callback); } void DefaultFileSource::updateOfflineMetadata(const int64_t regionID, const OfflineRegionMetadata& metadata, - std::function)> callback) { + std::function)> callback) { impl->actor().invoke(&Impl::updateMetadata, regionID, metadata, callback); } @@ -294,7 +276,7 @@ void DefaultFileSource::setOfflineRegionDownloadState(OfflineRegion& region, Off impl->actor().invoke(&Impl::setRegionDownloadState, region.getID(), state); } -void DefaultFileSource::getOfflineRegionStatus(OfflineRegion& region, std::function)> callback) const { +void DefaultFileSource::getOfflineRegionStatus(OfflineRegion& region, std::function)> callback) const { impl->actor().invoke(&Impl::getRegionStatus, region.getID(), callback); } diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp index cfa7f52977..7516185f27 100644 --- a/platform/default/mbgl/storage/offline_database.cpp +++ b/platform/default/mbgl/storage/offline_database.cpp @@ -592,14 +592,15 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile, return true; } -std::vector OfflineDatabase::listRegions() try { +expected OfflineDatabase::listRegions() try { mapbox::sqlite::Query query{ getStatement("SELECT id, definition, description FROM regions") }; - std::vector result; + OfflineRegions result; while (query.run()) { const auto id = query.get(0); const auto definition = query.get(1); const auto description = query.get>(2); try { + // Construct, then move because this constructor is private. OfflineRegion region(id, decodeOfflineRegionDefinition(definition), description); result.emplace_back(std::move(region)); } catch (const std::exception& ex) { @@ -608,14 +609,16 @@ std::vector OfflineDatabase::listRegions() try { Log::Error(Event::General, "%s", ex.what()); } } - return result; + // Explicit move to avoid triggering the copy constructor. + return { std::move(result) }; } catch (const mapbox::sqlite::Exception& ex) { handleError(ex, "list regions"); - return {}; + return unexpected(std::current_exception()); } -optional OfflineDatabase::createRegion(const OfflineRegionDefinition& definition, - const OfflineRegionMetadata& metadata) try { +expected +OfflineDatabase::createRegion(const OfflineRegionDefinition& definition, + const OfflineRegionMetadata& metadata) try { // clang-format off mapbox::sqlite::Query query{ getStatement( "INSERT INTO regions (definition, description) " @@ -628,10 +631,11 @@ optional OfflineDatabase::createRegion(const OfflineRegionDefinit return OfflineRegion(query.lastInsertRowId(), definition, metadata); } catch (const mapbox::sqlite::Exception& ex) { handleError(ex, "create region"); - return nullopt; + return unexpected(std::current_exception()); } -optional OfflineDatabase::updateMetadata(const int64_t regionID, const OfflineRegionMetadata& metadata) try { +expected +OfflineDatabase::updateMetadata(const int64_t regionID, const OfflineRegionMetadata& metadata) try { // clang-format off mapbox::sqlite::Query query{ getStatement( "UPDATE regions SET description = ?1 " @@ -644,10 +648,10 @@ optional OfflineDatabase::updateMetadata(const int64_t re return metadata; } catch (const mapbox::sqlite::Exception& ex) { handleError(ex, "update region metadata"); - return nullopt; + return unexpected(std::current_exception()); } -void OfflineDatabase::deleteRegion(OfflineRegion&& region) try { +std::exception_ptr OfflineDatabase::deleteRegion(OfflineRegion&& region) try { { mapbox::sqlite::Query query{ getStatement("DELETE FROM regions WHERE id = ?") }; query.bind(1, region.getID()); @@ -660,9 +664,10 @@ void OfflineDatabase::deleteRegion(OfflineRegion&& region) try { // Ensure that the cached offlineTileCount value is recalculated. offlineMapboxTileCount = {}; + return nullptr; } catch (const mapbox::sqlite::Exception& ex) { handleError(ex, "delete region"); - return; + return std::current_exception(); } optional> OfflineDatabase::getRegionResource(int64_t regionID, const Resource& resource) try { @@ -848,7 +853,7 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) { } } -optional OfflineDatabase::getRegionDefinition(int64_t regionID) try { +expected OfflineDatabase::getRegionDefinition(int64_t regionID) try { mapbox::sqlite::Query query{ getStatement("SELECT definition FROM regions WHERE id = ?1") }; query.bind(1, regionID); query.run(); @@ -856,10 +861,10 @@ optional OfflineDatabase::getRegionDefinition(int64_t r return decodeOfflineRegionDefinition(query.get(0)); } catch (const mapbox::sqlite::Exception& ex) { handleError(ex, "load region"); - return nullopt; + return unexpected(std::current_exception()); } -optional OfflineDatabase::getRegionCompletedStatus(int64_t regionID) try { +expected OfflineDatabase::getRegionCompletedStatus(int64_t regionID) try { OfflineRegionStatus result; std::tie(result.completedResourceCount, result.completedResourceSize) @@ -873,7 +878,7 @@ optional OfflineDatabase::getRegionCompletedStatus(int64_t return result; } catch (const mapbox::sqlite::Exception& ex) { handleError(ex, "get region status"); - return nullopt; + return unexpected(std::current_exception()); } std::pair OfflineDatabase::getCompletedResourceCountAndSize(int64_t regionID) { diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp index cdad11b79e..fbe6c707e1 100644 --- a/platform/default/mbgl/storage/offline_database.hpp +++ b/platform/default/mbgl/storage/offline_database.hpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -47,14 +48,15 @@ public: // Return value is (inserted, stored size) std::pair put(const Resource&, const Response&); - std::vector listRegions(); + expected listRegions(); - optional createRegion(const OfflineRegionDefinition&, - const OfflineRegionMetadata&); + expected createRegion(const OfflineRegionDefinition&, + const OfflineRegionMetadata&); - optional updateMetadata(const int64_t regionID, const OfflineRegionMetadata&); + expected + updateMetadata(const int64_t regionID, const OfflineRegionMetadata&); - void deleteRegion(OfflineRegion&&); + std::exception_ptr deleteRegion(OfflineRegion&&); // Return value is (response, stored size) optional> getRegionResource(int64_t regionID, const Resource&); @@ -62,8 +64,8 @@ public: uint64_t putRegionResource(int64_t regionID, const Resource&, const Response&); void putRegionResources(int64_t regionID, const std::list>&, OfflineRegionStatus&); - optional getRegionDefinition(int64_t regionID); - optional getRegionCompletedStatus(int64_t regionID); + expected getRegionDefinition(int64_t regionID); + expected getRegionCompletedStatus(int64_t regionID); void setOfflineMapboxTileCountLimit(uint64_t); uint64_t getOfflineMapboxTileCountLimit(); diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index b77c67fbb3..48329cf63a 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -3690,7 +3690,10 @@ baseConfigurationReference = 55D8C9941D0F133500F42F10 /* config.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; - HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)"; + HEADER_SEARCH_PATHS = ( + "$(mbgl_core_INCLUDE_DIRECTORIES)", + "$(mbgl_filesource_INCLUDE_DIRECTORIES)", + ); INFOPLIST_FILE = test/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_CFLAGS = "-fvisibility=hidden"; @@ -3714,7 +3717,10 @@ baseConfigurationReference = 55D8C9941D0F133500F42F10 /* config.xcconfig */; buildSettings = { CLANG_ENABLE_MODULES = YES; - HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)"; + HEADER_SEARCH_PATHS = ( + "$(mbgl_core_INCLUDE_DIRECTORIES)", + "$(mbgl_filesource_INCLUDE_DIRECTORIES)", + ); INFOPLIST_FILE = test/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; OTHER_CFLAGS = "-fvisibility=hidden"; diff --git a/scripts/config.xcconfig.in b/scripts/config.xcconfig.in index 357732c9ae..69ca2424a1 100644 --- a/scripts/config.xcconfig.in +++ b/scripts/config.xcconfig.in @@ -1,9 +1,9 @@ // Do not edit -- generated by CMake // mbgl-core -mbgl_core_INCLUDE_DIRECTORIES = "@mbgl_core_INCLUDE_DIRECTORIES@" -mbgl_core_LINK_LIBRARIES = "@mbgl_core_LINK_LIBRARIES@" +mbgl_core_INCLUDE_DIRECTORIES = "$," ">" +mbgl_core_LINK_LIBRARIES = "$" // mbgl-filesource -mbgl_filesource_INCLUDE_DIRECTORIES = "@mbgl_filesource_INCLUDE_DIRECTORIES@" -mbgl_filesource_LINK_LIBRARIES = "@mbgl_filesource_LINK_LIBRARIES@" +mbgl_filesource_INCLUDE_DIRECTORIES = "$," ">" +mbgl_filesource_LINK_LIBRARIES = "$" diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index de40d8caf7..a1fd2ea619 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -436,7 +436,8 @@ TEST(OfflineDatabase, UpdateMetadata) { OfflineRegionMetadata newmetadata {{ 4, 5, 6 }}; db.updateMetadata(region->getID(), newmetadata); - EXPECT_EQ(db.listRegions().at(0).getMetadata(), newmetadata); + auto regions = db.listRegions().value(); + EXPECT_EQ(regions.at(0).getMetadata(), newmetadata); EXPECT_EQ(0u, log.uncheckedCount()); } @@ -449,7 +450,7 @@ TEST(OfflineDatabase, ListRegions) { auto region = db.createRegion(definition, metadata); ASSERT_TRUE(region); - std::vector regions = db.listRegions(); + auto regions = db.listRegions().value(); ASSERT_EQ(1u, regions.size()); EXPECT_EQ(region->getID(), regions.at(0).getID()); @@ -499,7 +500,8 @@ TEST(OfflineDatabase, DeleteRegion) { db.deleteRegion(std::move(*region)); - ASSERT_EQ(0u, db.listRegions().size()); + auto regions = db.listRegions().value(); + ASSERT_EQ(0u, regions.size()); EXPECT_EQ(0u, log.uncheckedCount()); } @@ -841,10 +843,9 @@ TEST(OfflineDatabase, BatchInsertionMapboxTileCountExceeded) { EXPECT_EQ(0u, status.completedTileCount); EXPECT_EQ(0u, status.completedResourceCount); - const auto completedStatus = db.getRegionCompletedStatus(region->getID()); - ASSERT_TRUE(completedStatus); - EXPECT_EQ(1u, completedStatus->completedTileCount); - EXPECT_EQ(2u, completedStatus->completedResourceCount); + const auto completedStatus = db.getRegionCompletedStatus(region->getID()).value(); + EXPECT_EQ(1u, completedStatus.completedTileCount); + EXPECT_EQ(2u, completedStatus.completedResourceCount); EXPECT_EQ(0u, log.uncheckedCount()); } @@ -858,7 +859,8 @@ TEST(OfflineDatabase, MigrateFromV2Schema) { { OfflineDatabase db(filename, 0); auto regions = db.listRegions(); - for (auto& region : regions) { + ASSERT_TRUE(regions); + for (auto& region : regions.value()) { db.deleteRegion(std::move(region)); } } @@ -878,7 +880,7 @@ TEST(OfflineDatabase, MigrateFromV3Schema) { { OfflineDatabase db(filename, 0); - auto regions = db.listRegions(); + auto regions = db.listRegions().value(); for (auto& region : regions) { db.deleteRegion(std::move(region)); } @@ -897,7 +899,7 @@ TEST(OfflineDatabase, MigrateFromV4Schema) { { OfflineDatabase db(filename, 0); - auto regions = db.listRegions(); + auto regions = db.listRegions().value(); for (auto& region : regions) { db.deleteRegion(std::move(region)); } @@ -923,7 +925,7 @@ TEST(OfflineDatabase, MigrateFromV5Schema) { { OfflineDatabase db(filename, 0); - auto regions = db.listRegions(); + auto regions = db.listRegions().value(); for (auto& region : regions) { db.deleteRegion(std::move(region)); } @@ -1046,16 +1048,15 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(DisallowedIO)) { EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't write resource: authorization denied"))); EXPECT_EQ(0u, log.uncheckedCount()); - const auto regions = db.listRegions(); - EXPECT_TRUE(regions.empty()); + EXPECT_FALSE(db.listRegions()); EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't list regions: authorization denied"))); EXPECT_EQ(0u, log.uncheckedCount()); - EXPECT_EQ(nullopt, db.createRegion(definition, {})); + EXPECT_FALSE(db.createRegion(definition, {})); EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't create region: authorization denied"))); EXPECT_EQ(0u, log.uncheckedCount()); - EXPECT_EQ(nullopt, db.updateMetadata(region->getID(), {})); + EXPECT_FALSE(db.updateMetadata(region->getID(), {})); EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't update region metadata: authorization denied"))); EXPECT_EQ(0u, log.uncheckedCount()); @@ -1077,15 +1078,15 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(DisallowedIO)) { EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't write region resources: authorization denied"))); EXPECT_EQ(0u, log.uncheckedCount()); - EXPECT_EQ(nullopt, db.getRegionDefinition(region->getID())); + EXPECT_FALSE(db.getRegionDefinition(region->getID())); EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't load region: authorization denied"))); EXPECT_EQ(0u, log.uncheckedCount()); - EXPECT_EQ(nullopt, db.getRegionCompletedStatus(region->getID())); + EXPECT_FALSE(db.getRegionCompletedStatus(region->getID())); EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't get region status: authorization denied"))); EXPECT_EQ(0u, log.uncheckedCount()); - db.deleteRegion(std::move(*region)); + EXPECT_TRUE(db.deleteRegion(std::move(*region))); EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't delete region: authorization denied"))); EXPECT_EQ(0u, log.uncheckedCount()); diff --git a/test/storage/offline_download.test.cpp b/test/storage/offline_download.test.cpp index f979d42601..93b4dd623a 100644 --- a/test/storage/offline_download.test.cpp +++ b/test/storage/offline_download.test.cpp @@ -65,7 +65,7 @@ public: OfflineDatabase db; std::size_t size = 0; - optional createRegion() { + auto createRegion() { OfflineRegionDefinition definition { "", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 1.0 }; OfflineRegionMetadata metadata; return db.createRegion(definition, metadata); -- cgit v1.2.1 From 084c28f0bb3969aaa09078c278f08f83e389eda2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 14 Aug 2018 13:04:00 -0700 Subject: [core] recreate offline database when it is deleted out from under our feet --- platform/default/mbgl/storage/offline_database.cpp | 7 ++++-- platform/default/sqlite3.cpp | 4 ++++ platform/default/sqlite3.hpp | 25 +++++++++++----------- test/storage/offline_database.test.cpp | 8 +++---- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp index 7516185f27..79bc3c8f27 100644 --- a/platform/default/mbgl/storage/offline_database.cpp +++ b/platform/default/mbgl/storage/offline_database.cpp @@ -79,8 +79,11 @@ void OfflineDatabase::initialize() { void OfflineDatabase::handleError(const mapbox::sqlite::Exception& ex, const char* action) { if (ex.code == mapbox::sqlite::ResultCode::NotADB || - ex.code == mapbox::sqlite::ResultCode::Corrupt) { - // Corrupted; delete database so that we have a clean slate for the next operation. + ex.code == mapbox::sqlite::ResultCode::Corrupt || + (ex.code == mapbox::sqlite::ResultCode::ReadOnly && + ex.extendedCode == mapbox::sqlite::ExtendedResultCode::ReadOnlyDBMoved)) { + // The database was corruped, moved away, or deleted. We're going to start fresh with a + // clean slate for the next operation. Log::Error(Event::Database, static_cast(ex.code), "Can't %s: %s", action, ex.what()); try { removeExisting(); diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp index fed5a3a185..faaa85efd8 100644 --- a/platform/default/sqlite3.cpp +++ b/platform/default/sqlite3.cpp @@ -45,6 +45,10 @@ public: DatabaseImpl(sqlite3* db_) : db(db_) { + const int error = sqlite3_extended_result_codes(db, true); + if (error != SQLITE_OK) { + mbgl::Log::Warning(mbgl::Event::Database, error, "Failed to enable extended result codes: %s", sqlite3_errmsg(db)); + } } ~DatabaseImpl() diff --git a/platform/default/sqlite3.hpp b/platform/default/sqlite3.hpp index 612e92acc6..16f76a0d1a 100644 --- a/platform/default/sqlite3.hpp +++ b/platform/default/sqlite3.hpp @@ -15,7 +15,7 @@ enum OpenFlag : int { ReadWriteCreate = 0b110, }; -enum class ResultCode : int { +enum class ResultCode : uint8_t { OK = 0, Error = 1, Internal = 2, @@ -40,24 +40,25 @@ enum class ResultCode : int { NoLFS = 22, Auth = 23, Range = 25, - NotADB = 26 + NotADB = 26, +}; + +enum class ExtendedResultCode : uint8_t { + Unknown = 0, + ReadOnlyDBMoved = 4, }; class Exception : public std::runtime_error { public: - Exception(int err, const char* msg) - : std::runtime_error(msg), code(static_cast(err)) { - } - Exception(ResultCode err, const char* msg) - : std::runtime_error(msg), code(err) { - } + Exception(ResultCode err, const char* msg) : Exception(static_cast(err), msg) {} + Exception(int err, const char* msg) : Exception(err, std::string{ msg }) {} Exception(int err, const std::string& msg) - : std::runtime_error(msg), code(static_cast(err)) { - } - Exception(ResultCode err, const std::string& msg) - : std::runtime_error(msg), code(err) { + : std::runtime_error(msg), + code(static_cast(err)), + extendedCode(static_cast(err >> 8)) { } const ResultCode code = ResultCode::OK; + const ExtendedResultCode extendedCode = ExtendedResultCode::Unknown; }; class DatabaseImpl; diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index a1fd2ea619..346cd6da80 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -32,7 +32,7 @@ static FixtureLog::Message error(ResultCode code, const char* message) { return { EventSeverity::Error, Event::Database, static_cast(code), message }; } -static FixtureLog::Message warning(ResultCode code, const char* message) { +static __attribute__((unused)) FixtureLog::Message warning(ResultCode code, const char* message) { return { EventSeverity::Warning, Event::Database, static_cast(code), message }; } @@ -232,7 +232,7 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(Invalid)) { // Checking two possibilities for the error string because it apparently changes between SQLite versions. EXPECT_EQ(1u, log.count(error(ResultCode::NotADB, "Can't open database: file is encrypted or is not a database"), true) + log.count(error(ResultCode::NotADB, "Can't open database: file is not a database"), true)); - EXPECT_EQ(1u, log.count(warning(static_cast(-1), "Removing existing incompatible offline database"))); + EXPECT_EQ(1u, log.count({ EventSeverity::Warning, Event::Database, -1, "Removing existing incompatible offline database" })); // Now try inserting and reading back to make sure we have a valid database. for (const auto& res : { fixture::resource, fixture::tile }) { @@ -977,7 +977,7 @@ TEST(OfflineDatabase, CorruptDatabaseOnOpen) { // This database is corrupt in a way that will prevent opening the database. OfflineDatabase db(filename); EXPECT_EQ(1u, log.count(error(ResultCode::Corrupt, "Can't open database: database disk image is malformed"), true)); - EXPECT_EQ(1u, log.count(warning(static_cast(-1), "Removing existing incompatible offline database"))); + EXPECT_EQ(1u, log.count({ EventSeverity::Warning, Event::Database, -1, "Removing existing incompatible offline database" })); EXPECT_EQ(0u, log.uncheckedCount()); // Now try inserting and reading back to make sure we have a valid database. @@ -1007,7 +1007,7 @@ TEST(OfflineDatabase, CorruptDatabaseOnQuery) { // The first request fails because the database is corrupt and has to be recreated. EXPECT_EQ(nullopt, db.get(fixture::tile)); EXPECT_EQ(1u, log.count(error(ResultCode::Corrupt, "Can't read resource: database disk image is malformed"), true)); - EXPECT_EQ(1u, log.count(warning(static_cast(-1), "Removing existing incompatible offline database"))); + EXPECT_EQ(1u, log.count({ EventSeverity::Warning, Event::Database, -1, "Removing existing incompatible offline database" })); EXPECT_EQ(0u, log.uncheckedCount()); // Now try inserting and reading back to make sure we have a valid database. -- cgit v1.2.1 From 9d72bf8a1a708ce66ebc1a3c8823013964b62c1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Tue, 14 Aug 2018 13:28:28 -0700 Subject: [build] make sure we're also updating the mapbox-ios-events submodule --- cmake/mbgl.cmake | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cmake/mbgl.cmake b/cmake/mbgl.cmake index 3abc974feb..233ae6e8b8 100644 --- a/cmake/mbgl.cmake +++ b/cmake/mbgl.cmake @@ -64,9 +64,14 @@ if(WITH_NODEJS) endfunction() # Run submodule update + set(MBGL_SUBMODULES mapbox-gl-js) + if (MBGL_PLATFORM STREQUAL "ios") + list(APPEND MBGL_SUBMODULES platform/ios/vendor/mapbox-events-ios) + endif() + message(STATUS "Updating submodules...") execute_process( - COMMAND git submodule update --init mapbox-gl-js + COMMAND git submodule update --init ${MBGL_SUBMODULES} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}") if(NOT EXISTS "${CMAKE_SOURCE_DIR}/mapbox-gl-js/node_modules") @@ -80,7 +85,7 @@ if(WITH_NODEJS) # Add target for running submodule update during builds add_custom_target( update-submodules ALL - COMMAND git submodule update --init mapbox-gl-js + COMMAND git submodule update --init ${MBGL_SUBMODULES} WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}" COMMENT "Updating submodules..." ) -- cgit v1.2.1 From b1ab362c11519848571d50087c18fe73f5730632 Mon Sep 17 00:00:00 2001 From: tobrun Date: Tue, 14 Aug 2018 15:46:25 +0200 Subject: [android] - store release so files with debugging information --- circle.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/circle.yml b/circle.yml index f6b8c6f47a..bf903a2f36 100644 --- a/circle.yml +++ b/circle.yml @@ -426,6 +426,12 @@ jobs: --test platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/androidTest/debug/MapboxGLAndroidSDKTestApp-debug-androidTest.apk \ --device-ids sailfish --os-version-ids 26 --locales en --orientations portrait --timeout 20m fi + - run: + name: gzip debugable .so files + command: | + gzip platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/debug/obj/armeabi-v7a/libmapbox-gl.so + - store_artifacts: + path: platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/debug/obj/armeabi-v7a/libmapbox-gl.so.gz - store_artifacts: path: platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/debug destination: . @@ -491,9 +497,24 @@ jobs: - *save-mason_packages-cache - *save-ccache - *save-gradle-cache + - run: + name: gzip debugable .so files + command: | + gzip platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/arm64-v8a/libmapbox-gl.so && \ + gzip platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/armeabi-v7a/libmapbox-gl.so && \ + gzip platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86/libmapbox-gl.so && \ + gzip platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86_64/libmapbox-gl.so - store_artifacts: path: platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/release destination: . + - store_artifacts: + path: platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/arm64-v8a/libmapbox-gl.so.gz + - store_artifacts: + path: platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/armeabi-v7a/libmapbox-gl.so.gz + - store_artifacts: + path: platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86/libmapbox-gl.so.gz + - store_artifacts: + path: platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/release/obj/x86_64/libmapbox-gl.so.gz - run: name: Record size command: platform/android/scripts/metrics.sh -- cgit v1.2.1 From c2113fdb9806f6978072156538cefb787c46b0e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 15 Aug 2018 11:47:51 +0200 Subject: [android] bumped Snapshot version building on master to 6.5.0 --- platform/android/MapboxGLAndroidSDK/gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties index 77a93829f9..e8abad77e1 100644 --- a/platform/android/MapboxGLAndroidSDK/gradle.properties +++ b/platform/android/MapboxGLAndroidSDK/gradle.properties @@ -1,5 +1,5 @@ GROUP=com.mapbox.mapboxsdk -VERSION_NAME=6.4.0-SNAPSHOT +VERSION_NAME=6.5.0-SNAPSHOT POM_DESCRIPTION=Mapbox GL Android SDK POM_URL=https://github.com/mapbox/mapbox-gl-native -- cgit v1.2.1 From 1771875b120083ce025f6e7a5c08b16284c06700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 15 Aug 2018 14:40:39 +0200 Subject: [android] hide peer constructors --- .../main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java | 2 +- .../main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/light/Light.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java | 2 +- .../main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java | 2 +- .../src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java index ddb4d04fff..dd20a4b957 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/BackgroundLayer.java @@ -28,7 +28,7 @@ public class BackgroundLayer extends Layer { * @param nativePtr pointer used by core */ @Keep - public BackgroundLayer(long nativePtr) { + BackgroundLayer(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java index 8abd78ace2..9d2b9d89a5 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CircleLayer.java @@ -28,7 +28,7 @@ public class CircleLayer extends Layer { * @param nativePtr pointer used by core */ @Keep - public CircleLayer(long nativePtr) { + CircleLayer(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java index 79b68bbfc0..c03f8689fc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/CustomLayer.java @@ -16,7 +16,7 @@ public class CustomLayer extends Layer { } @Keep - public CustomLayer(long nativePtr) { + CustomLayer(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java index 6efe04e39d..2de0de06d9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillExtrusionLayer.java @@ -28,7 +28,7 @@ public class FillExtrusionLayer extends Layer { * @param nativePtr pointer used by core */ @Keep - public FillExtrusionLayer(long nativePtr) { + FillExtrusionLayer(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java index aaa20d6f3a..6e28900c26 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/FillLayer.java @@ -28,7 +28,7 @@ public class FillLayer extends Layer { * @param nativePtr pointer used by core */ @Keep - public FillLayer(long nativePtr) { + FillLayer(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java index 6d7cece124..f1076ecd96 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HeatmapLayer.java @@ -28,7 +28,7 @@ public class HeatmapLayer extends Layer { * @param nativePtr pointer used by core */ @Keep - public HeatmapLayer(long nativePtr) { + HeatmapLayer(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java index f906104e91..f706e5a234 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/HillshadeLayer.java @@ -28,7 +28,7 @@ public class HillshadeLayer extends Layer { * @param nativePtr pointer used by core */ @Keep - public HillshadeLayer(long nativePtr) { + HillshadeLayer(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java index 92aa54e55f..605f883bdb 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Layer.java @@ -18,7 +18,7 @@ public abstract class Layer { private boolean invalidated; @Keep - public Layer(long nativePtr) { + protected Layer(long nativePtr) { checkThread(); this.nativePtr = nativePtr; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java index 4a742cd7a6..d6519c991f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/LineLayer.java @@ -28,7 +28,7 @@ public class LineLayer extends Layer { * @param nativePtr pointer used by core */ @Keep - public LineLayer(long nativePtr) { + LineLayer(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java index 83e228cba0..50837a97be 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/RasterLayer.java @@ -28,7 +28,7 @@ public class RasterLayer extends Layer { * @param nativePtr pointer used by core */ @Keep - public RasterLayer(long nativePtr) { + RasterLayer(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java index f2ddb600a5..4389f6cb21 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/SymbolLayer.java @@ -28,7 +28,7 @@ public class SymbolLayer extends Layer { * @param nativePtr pointer used by core */ @Keep - public SymbolLayer(long nativePtr) { + SymbolLayer(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs index 2d4db2b55d..6ed58b1928 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/layer.java.ejs @@ -33,7 +33,7 @@ public class <%- camelize(type) %>Layer extends Layer { * @param nativePtr pointer used by core */ @Keep - public <%- camelize(type) %>Layer(long nativePtr) { + <%- camelize(type) %>Layer(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java index c0cf33e150..f3886d6cce 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/Light.java @@ -29,7 +29,7 @@ public class Light { * @param nativePtr pointer used by core */ @Keep - public Light(long nativePtr) { + Light(long nativePtr) { checkThread(); this.nativePtr = nativePtr; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs index 59b07d32d4..7c9893a3a4 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/light/light.java.ejs @@ -33,7 +33,7 @@ public class Light { * @param nativePtr pointer used by core */ @Keep - public Light(long nativePtr) { + Light(long nativePtr) { checkThread(); this.nativePtr = nativePtr; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java index 33d8ba03ee..65cd908ae4 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java @@ -29,7 +29,7 @@ public class GeoJsonSource extends Source { * @param nativePtr - pointer to native peer */ @Keep - public GeoJsonSource(long nativePtr) { + GeoJsonSource(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java index d84105a05c..d0ca5e050b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java @@ -35,7 +35,7 @@ public class ImageSource extends Source { * @param nativePtr - pointer to native peer */ @Keep - public ImageSource(long nativePtr) { + ImageSource(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java index dc3635ca86..4c2b39375a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterDemSource.java @@ -21,7 +21,7 @@ public class RasterDemSource extends Source { * @param nativePtr - pointer to native peer */ @Keep - private RasterDemSource(long nativePtr) { + RasterDemSource(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java index 6bd0456e0c..dac9b02166 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/RasterSource.java @@ -19,7 +19,7 @@ public class RasterSource extends Source { * @param nativePtr - pointer to native peer */ @Keep - public RasterSource(long nativePtr) { + RasterSource(long nativePtr) { super(nativePtr); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java index 53c8148580..14d9ef1cc5 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/Source.java @@ -18,7 +18,7 @@ public abstract class Source { * @param nativePtr - pointer to native peer */ @Keep - public Source(long nativePtr) { + protected Source(long nativePtr) { checkThread(); this.nativePtr = nativePtr; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java index 393d8c2b81..5888eaa7e1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/VectorSource.java @@ -28,7 +28,7 @@ public class VectorSource extends Source { * @param nativePtr - pointer to native peer */ @Keep - public VectorSource(long nativePtr) { + VectorSource(long nativePtr) { super(nativePtr); } -- cgit v1.2.1 From 7795c76ce84cf3b6ce0e5d51ce8a83dda6c7fc01 Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Tue, 14 Aug 2018 17:49:07 -0700 Subject: [macos] Rename Guides to Appendices --- platform/macos/jazzy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/macos/jazzy.yml b/platform/macos/jazzy.yml index 915c1f46a9..5f1a214541 100644 --- a/platform/macos/jazzy.yml +++ b/platform/macos/jazzy.yml @@ -15,7 +15,7 @@ umbrella_header: src/Mapbox.h framework_root: ../darwin/src custom_categories: - - name: Guides + - name: Appendices children: - Working with GeoJSON Data - Predicates and Expressions -- cgit v1.2.1 From 2424582ee3b343da7d2582fc739c5587361dad21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Wed, 15 Aug 2018 08:46:58 -0700 Subject: [macos] Canonicalized another exception name --- platform/macos/CHANGELOG.md | 1 + platform/macos/src/MGLMapView+IBAdditions.mm | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 1c1454de4d..64cbc4fb00 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -4,6 +4,7 @@ - Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) - Fix the `-[MGLMapView annotationAtPoint:]` method near tile boundaries at high zoom. ([#12472](https://github.com/mapbox/mapbox-gl-native/issues/12472)) +* Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) ## Styles and rendering diff --git a/platform/macos/src/MGLMapView+IBAdditions.mm b/platform/macos/src/MGLMapView+IBAdditions.mm index cef2863ee6..0c65abc031 100644 --- a/platform/macos/src/MGLMapView+IBAdditions.mm +++ b/platform/macos/src/MGLMapView+IBAdditions.mm @@ -1,5 +1,7 @@ #import "MGLMapView+IBAdditions.h" +#import "MGLStyle.h" + #import "MGLMapView_Private.h" @implementation MGLMapView (IBAdditions) @@ -17,7 +19,7 @@ [NSCharacterSet whitespaceAndNewlineCharacterSet]]; NSURL *url = URLString.length ? [NSURL URLWithString:URLString] : nil; if (URLString.length && !url) { - [NSException raise:@"Invalid style URL" + [NSException raise:MGLInvalidStyleURLException format:@"“%@” is not a valid style URL.", URLString]; } self.styleURL = url; -- cgit v1.2.1 From d3e34907a37374da64dadf9065b0b19240acea85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Wed, 15 Aug 2018 08:56:54 -0700 Subject: [ios, macos] Copyedited changelogs --- platform/ios/CHANGELOG.md | 6 +++--- platform/macos/CHANGELOG.md | 10 +++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index e3ad4d5b3e..80053ef21b 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -9,19 +9,19 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) * Fix the behavior of `-[MGLMapView visibleFeaturesAtPoint:]` near tile boundaries at high zoom. ([#12472](https://github.com/mapbox/mapbox-gl-native/issues/12472)) -## 4.3.0 +## 4.3.0 - August 15, 2018 ### Styles and rendering * Added an `MGLMapView.preferredFramesPerSecond` property that controls the rate at which the map view is rendered. The default rate now adapts to device capabilities to provide a smoother experience. ([#12501](https://github.com/mapbox/mapbox-gl-native/issues/12501)) +* Token string syntax (`"{token}"`) in `MGLSymbolStyleLayer` `text` and `iconImageName` properties is now correctly converted to the appropriate `NSExpression` equivalent. ([#11659](https://github.com/mapbox/mapbox-gl-native/issues/11659)) +* Fixed a crash when switching between two styles having layers with the same identifier but different layer types. ([#12432](https://github.com/mapbox/mapbox-gl-native/issues/12432)) * Added a new option to `MGLSymbolPlacement`, `MGLSymbolPlacementLineCenter`, that places the label relative to the center of the geometry. ([#12337](https://github.com/mapbox/mapbox-gl-native/pull/12337)) ### Other changes * Fixed a crash that occurred when the user started a gesture before the drift animation for a previous gesture was complete. ([#12148](https://github.com/mapbox/mapbox-gl-native/pull/12148)) -* Token string syntax (`"{token}"`) in `MGLSymbolStyleLayer` `text` and `iconImageName` properties is now correctly converted to the appropriate `NSExpression` equivalent. ([#11659](https://github.com/mapbox/mapbox-gl-native/issues/11659)) * Added an `MGLMapView.locationManager` property and `MGLLocationManager` protocol for tracking user location using a custom alternative to `CLLocationManager`. ([#12013](https://github.com/mapbox/mapbox-gl-native/pull/12013)) -* Fixed a crash when switching between two styles having layers with the same identifier but different layer types. ([#12432](https://github.com/mapbox/mapbox-gl-native/issues/12432)) * Fixed an issue where the symbols for `MGLMapPointForCoordinate` could not be found. ([#12445](https://github.com/mapbox/mapbox-gl-native/issues/12445)) * Fixed an issue causing country and ocean labels to disappear after calling `-[MGLStyle localizeLabelsIntoLocale:]` when the system language is set to Simplified Chinese. ([#12164](https://github.com/mapbox/mapbox-gl-native/issues/12164)) * Fixed a crash that occurred when `MMELocationManager` was deallocated and the delegate was reporting updates. ([#12542](https://github.com/mapbox/mapbox-gl-native/pull/12542)) diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 64cbc4fb00..af3c89c356 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -6,11 +6,19 @@ - Fix the `-[MGLMapView annotationAtPoint:]` method near tile boundaries at high zoom. ([#12472](https://github.com/mapbox/mapbox-gl-native/issues/12472)) * Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) +# 0.10.0 - August 15, 2018 + ## Styles and rendering * Token string syntax (`"{token}"`) in `MGLSymbolStyleLayer` `text` and `iconImageName` properties is now correctly converted to the appropriate `NSExpression` equivalent. ([#11659](https://github.com/mapbox/mapbox-gl-native/issues/11659)) * Fixed a crash when switching between two styles having layers with the same identifier but different layer types. ([#12432](https://github.com/mapbox/mapbox-gl-native/issues/12432)) -* * Added a new option to `MGLSymbolPlacement`, `MGLSymbolPlacementLineCenter`, that places the label relative to the center of the geometry. ([#12337](https://github.com/mapbox/mapbox-gl-native/pull/12337)) +* Added a new option to `MGLSymbolPlacement`, `MGLSymbolPlacementLineCenter`, that places the label relative to the center of the geometry. ([#12337](https://github.com/mapbox/mapbox-gl-native/pull/12337)) + +## Other changes + +* Fixed an issue where the symbols for `MGLMapPointForCoordinate` could not be found. ([#12445](https://github.com/mapbox/mapbox-gl-native/issues/12445)) +* Fixed an issue causing country and ocean labels to disappear after calling `-[MGLStyle localizeLabelsIntoLocale:]` when the system language is set to Simplified Chinese. ([#12164](https://github.com/mapbox/mapbox-gl-native/issues/12164)) +* Various security related improvements. # 0.9.0 - July 18, 2018 -- cgit v1.2.1 From 2173088203d1f1c8cd2c1ca8915e8b076d52c59a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguye=CC=82=CC=83n?= Date: Wed, 15 Aug 2018 09:01:54 -0700 Subject: [ios, macos] Copyedited changelogs --- platform/ios/CHANGELOG.md | 6 +++--- platform/macos/CHANGELOG.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 80053ef21b..6b535e8fc9 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -4,10 +4,10 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT ## master -* Improved the Swift interface for `MGLMapView.decelerationRate`. ([#12584](https://github.com/mapbox/mapbox-gl-native/issues/12584)) +* The predefined values of `MGLMapView.decelerationRate` are now typed as `MGLMapViewDecelerationRate`s for improved bridging to Swift. ([#12584](https://github.com/mapbox/mapbox-gl-native/pull/12584)) +* When a symbol in an `MGLSymbolStyleLayer` has both an icon and text, both are shown or hidden together based on available space. ([#12521](https://github.com/mapbox/mapbox-gl-native/pull/12521)) +* The `-[MGLMapView visibleFeaturesAtPoint:]` method can now return features near tile boundaries at high zoom levels. ([#12570](https://github.com/mapbox/mapbox-gl-native/pull/12570)) * Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) -* Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) -* Fix the behavior of `-[MGLMapView visibleFeaturesAtPoint:]` near tile boundaries at high zoom. ([#12472](https://github.com/mapbox/mapbox-gl-native/issues/12472)) ## 4.3.0 - August 15, 2018 diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index af3c89c356..5e7751d6f2 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -2,8 +2,8 @@ # master -- Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) -- Fix the `-[MGLMapView annotationAtPoint:]` method near tile boundaries at high zoom. ([#12472](https://github.com/mapbox/mapbox-gl-native/issues/12472)) +* When a symbol in an `MGLSymbolStyleLayer` has both an icon and text, both are shown or hidden together based on available space. ([#12521](https://github.com/mapbox/mapbox-gl-native/pull/12521)) +* The `-[MGLMapView annotationAtPoint:]` method can now return annotations near tile boundaries at high zoom levels. ([#12570](https://github.com/mapbox/mapbox-gl-native/pull/12570)) * Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) # 0.10.0 - August 15, 2018 -- cgit v1.2.1 From 91f934fdb61599744474d5f60f919d3dba5b64e1 Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Wed, 15 Aug 2018 09:45:56 -0700 Subject: [macos] Fix pod name within docs --- platform/macos/docs/pod-README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/macos/docs/pod-README.md b/platform/macos/docs/pod-README.md index 4827124be0..5dbef70efb 100644 --- a/platform/macos/docs/pod-README.md +++ b/platform/macos/docs/pod-README.md @@ -40,7 +40,7 @@ Create a [Podfile](https://guides.cocoapods.org/syntax/podfile.html) with the fo platform :osx, '10.11' target 'TargetNameForYourApp' do - pod 'Mapbox-iOS-SDK', '~> x.y' + pod 'Mapbox-macOS-SDK', '~> x.y' end ``` -- cgit v1.2.1 From 59cdb144b4b4c67fa6b0bc43a95cfde41369fd02 Mon Sep 17 00:00:00 2001 From: Julian Rex Date: Wed, 15 Aug 2018 16:45:11 -0400 Subject: [ios, macos] Update change logs prior to release of v4.3.0 (#12650) * [ios, macos] Update security vulnerability details in changelogs * [ios] Updated change log to reference LTO changes. --- platform/ios/CHANGELOG.md | 10 +++++++--- platform/macos/CHANGELOG.md | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 6b535e8fc9..0bb97eaec3 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -18,14 +18,18 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Fixed a crash when switching between two styles having layers with the same identifier but different layer types. ([#12432](https://github.com/mapbox/mapbox-gl-native/issues/12432)) * Added a new option to `MGLSymbolPlacement`, `MGLSymbolPlacementLineCenter`, that places the label relative to the center of the geometry. ([#12337](https://github.com/mapbox/mapbox-gl-native/pull/12337)) +## User location + +* Added an `MGLMapView.locationManager` property and `MGLLocationManager` protocol for tracking user location using a custom alternative to `CLLocationManager`. ([#12013](https://github.com/mapbox/mapbox-gl-native/pull/12013)) +* Fixed a crash that occurred when `MMELocationManager` was deallocated and the delegate was reporting updates. ([#12542](https://github.com/mapbox/mapbox-gl-native/pull/12542)) + ### Other changes * Fixed a crash that occurred when the user started a gesture before the drift animation for a previous gesture was complete. ([#12148](https://github.com/mapbox/mapbox-gl-native/pull/12148)) -* Added an `MGLMapView.locationManager` property and `MGLLocationManager` protocol for tracking user location using a custom alternative to `CLLocationManager`. ([#12013](https://github.com/mapbox/mapbox-gl-native/pull/12013)) * Fixed an issue where the symbols for `MGLMapPointForCoordinate` could not be found. ([#12445](https://github.com/mapbox/mapbox-gl-native/issues/12445)) * Fixed an issue causing country and ocean labels to disappear after calling `-[MGLStyle localizeLabelsIntoLocale:]` when the system language is set to Simplified Chinese. ([#12164](https://github.com/mapbox/mapbox-gl-native/issues/12164)) -* Fixed a crash that occurred when `MMELocationManager` was deallocated and the delegate was reporting updates. ([#12542](https://github.com/mapbox/mapbox-gl-native/pull/12542)) -* Various security related improvements. +* Closed a security vulnerability introduced in 4.1.0 that would potentially allow the owner of a style to compromise apps loading that style. ([#12571](https://github.com/mapbox/mapbox-gl-native/pull/12571)) +* Reduced binary size and improved performance by enabling LTO. ([#12502](https://github.com/mapbox/mapbox-gl-native/pull/12502)) ## 4.2.0 - July 18, 2018 diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 5e7751d6f2..41063670a8 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -18,7 +18,7 @@ * Fixed an issue where the symbols for `MGLMapPointForCoordinate` could not be found. ([#12445](https://github.com/mapbox/mapbox-gl-native/issues/12445)) * Fixed an issue causing country and ocean labels to disappear after calling `-[MGLStyle localizeLabelsIntoLocale:]` when the system language is set to Simplified Chinese. ([#12164](https://github.com/mapbox/mapbox-gl-native/issues/12164)) -* Various security related improvements. +* Closed a security vulnerability introduced in 0.8.0 that would potentially allow the owner of a style to compromise apps loading that style. ([#12571](https://github.com/mapbox/mapbox-gl-native/pull/12571)) # 0.9.0 - July 18, 2018 -- cgit v1.2.1 From 1847ef0fa90cf183d9a4035b49d7d59e9f392838 Mon Sep 17 00:00:00 2001 From: Julian Rex Date: Wed, 15 Aug 2018 18:02:08 -0400 Subject: [ios, macos] Update podspecs for 4.3.0 and 0.10.0 releases. (#12651) --- platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec | 2 +- platform/ios/Mapbox-iOS-SDK-symbols.podspec | 2 +- platform/ios/Mapbox-iOS-SDK.podspec | 2 +- platform/macos/Mapbox-macOS-SDK-symbols.podspec | 2 +- platform/macos/Mapbox-macOS-SDK.podspec | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec index ff680615ce..427a99d603 100644 --- a/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec +++ b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.3.0-beta.1' + version = '4.3.0' m.name = 'Mapbox-iOS-SDK-nightly-dynamic' m.version = "#{version}-nightly" diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec index d04fbc445f..162b4abcb8 100644 --- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec +++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.3.0-beta.1' + version = '4.3.0' m.name = 'Mapbox-iOS-SDK-symbols' m.version = "#{version}-symbols" diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec index b8e620f264..309d84e52e 100644 --- a/platform/ios/Mapbox-iOS-SDK.podspec +++ b/platform/ios/Mapbox-iOS-SDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '4.3.0-beta.1' + version = '4.3.0' m.name = 'Mapbox-iOS-SDK' m.version = version diff --git a/platform/macos/Mapbox-macOS-SDK-symbols.podspec b/platform/macos/Mapbox-macOS-SDK-symbols.podspec index 58f4bad09b..7ab9aa4de2 100644 --- a/platform/macos/Mapbox-macOS-SDK-symbols.podspec +++ b/platform/macos/Mapbox-macOS-SDK-symbols.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '0.8.0' + version = '0.10.0' m.name = 'Mapbox-macOS-SDK-symbols' m.version = "#{version}-symbols" diff --git a/platform/macos/Mapbox-macOS-SDK.podspec b/platform/macos/Mapbox-macOS-SDK.podspec index 6af7cb001f..756f3828b6 100644 --- a/platform/macos/Mapbox-macOS-SDK.podspec +++ b/platform/macos/Mapbox-macOS-SDK.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |m| - version = '0.8.0' + version = '0.10.0' m.name = 'Mapbox-macOS-SDK' m.version = version -- cgit v1.2.1 From fbc39fa42afab40ecd9fa4da0cf9f05a50285b03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Wed, 15 Aug 2018 18:24:27 +0200 Subject: [android] changelog for v6.4.0 (cherry picked from commit 5aee8d9) --- platform/android/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index daef4095f9..b314165143 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -6,6 +6,10 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to - Don't default-show text/icons that depend on the placement of a paired icon/text [#12483](https://github.com/mapbox/mapbox-gl-native/issues/12483) - Fix symbol querying for markers near tile boundaries at high zoom. ([#12472](https://github.com/mapbox/mapbox-gl-native/issues/12472)) +## 6.4.0 - August 15, 2018 + - Use unconverted bearing value for LatLngBounds calculation [#12616](https://github.com/mapbox/mapbox-gl-native/pull/12616) + - Store release so files with debugging information [#12628](https://github.com/mapbox/mapbox-gl-native/pull/12628) + ## 6.4.0-beta.1 - August 9, 2018 - Don't prefetch tiles for geojson sources [#12529](https://github.com/mapbox/mapbox-gl-native/pull/12529) - Enable LTO in release builds [#12546](https://github.com/mapbox/mapbox-gl-native/pull/12546) -- cgit v1.2.1 From 369e6880dbca54c115bbfdf84ff41f80badbde93 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 15 Aug 2018 21:40:16 +0200 Subject: [android] - update changelog with fixed security vulnerability --- platform/android/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md index b314165143..ccae27f51d 100644 --- a/platform/android/CHANGELOG.md +++ b/platform/android/CHANGELOG.md @@ -9,6 +9,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to ## 6.4.0 - August 15, 2018 - Use unconverted bearing value for LatLngBounds calculation [#12616](https://github.com/mapbox/mapbox-gl-native/pull/12616) - Store release so files with debugging information [#12628](https://github.com/mapbox/mapbox-gl-native/pull/12628) + - Close a security vulnerability introduced in v6.2.0 that would potentially allow the owner of a style to compromise apps loading that style. ## 6.4.0-beta.1 - August 9, 2018 - Don't prefetch tiles for geojson sources [#12529](https://github.com/mapbox/mapbox-gl-native/pull/12529) -- cgit v1.2.1 From 19325b0293dc99a641311ebabd55c9554d0ee38e Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Thu, 16 Aug 2018 10:26:17 -0700 Subject: [build] More diagnostics for npm install failures --- cmake/mbgl.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/mbgl.cmake b/cmake/mbgl.cmake index 233ae6e8b8..9dd29375ef 100644 --- a/cmake/mbgl.cmake +++ b/cmake/mbgl.cmake @@ -42,11 +42,12 @@ if(WITH_NODEJS) if("${DIRECTORY}/package.json" IS_NEWER_THAN "${DIRECTORY}/node_modules/.${NAME}.stamp") message(STATUS "Running 'npm install' for ${NAME}...") execute_process( - COMMAND "${NodeJS_EXECUTABLE}" "${npm_EXECUTABLE}" install --ignore-scripts + COMMAND "${NodeJS_EXECUTABLE}" "${npm_EXECUTABLE}" install --verbose --ignore-scripts WORKING_DIRECTORY "${DIRECTORY}" RESULT_VARIABLE NPM_INSTALL_FAILED OUTPUT_VARIABLE NPM_OUTPUT ERROR_VARIABLE NPM_OUTPUT) + message(STATUS "Finished 'npm install' for ${NAME}...") if(NOT NPM_INSTALL_FAILED) execute_process(COMMAND ${CMAKE_COMMAND} -E touch "${DIRECTORY}/node_modules/.${NAME}.stamp") else() -- cgit v1.2.1 From 790b9f5c827101a47fd06fbfa944d36e3f0b285c Mon Sep 17 00:00:00 2001 From: Jason Wray Date: Mon, 16 Jul 2018 12:18:43 -0400 Subject: [ios] Add experimental frame rate measurements to MGLMapView Includes: average frame rate, average frame render duration, and instantaneous frame render duration. --- platform/ios/app/MBXViewController.m | 24 ++++++++++++---------- platform/ios/ios.xcodeproj/project.pbxproj | 2 ++ platform/ios/src/MGLMapView.mm | 32 ++++++++++++++++++++++++++++++ platform/ios/src/MGLMapView_Experimental.h | 32 ++++++++++++++++++++++++++++++ 4 files changed, 80 insertions(+), 10 deletions(-) create mode 100644 platform/ios/src/MGLMapView_Experimental.h diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m index 71bad66aee..259c1191bc 100644 --- a/platform/ios/app/MBXViewController.m +++ b/platform/ios/app/MBXViewController.m @@ -9,6 +9,7 @@ #import "MBXEmbeddedMapViewController.h" #import +#import "../src/MGLMapView_Experimental.h" #import @@ -195,7 +196,7 @@ CLLocationCoordinate2D randomWorldCoordinate() { @property (nonatomic) BOOL customUserLocationAnnnotationEnabled; @property (nonatomic, getter=isLocalizingLabels) BOOL localizingLabels; @property (nonatomic) BOOL reuseQueueStatsEnabled; -@property (nonatomic) BOOL showZoomLevelEnabled; +@property (nonatomic) BOOL mapInfoHUDEnabled; @property (nonatomic) BOOL shouldLimitCameraChanges; @property (nonatomic) BOOL randomWalk; @end @@ -280,7 +281,7 @@ CLLocationCoordinate2D randomWorldCoordinate() { [defaults setInteger:self.mapView.userTrackingMode forKey:@"MBXUserTrackingMode"]; [defaults setBool:self.mapView.showsUserLocation forKey:@"MBXShowsUserLocation"]; [defaults setInteger:self.mapView.debugMask forKey:@"MBXDebugMask"]; - [defaults setBool:self.showZoomLevelEnabled forKey:@"MBXShowsZoomLevelHUD"]; + [defaults setBool:self.mapInfoHUDEnabled forKey:@"MBXShowsZoomLevelHUD"]; [defaults synchronize]; } @@ -308,7 +309,7 @@ CLLocationCoordinate2D randomWorldCoordinate() { } if ([defaults boolForKey:@"MBXShowsZoomLevelHUD"]) { - self.showZoomLevelEnabled = YES; + self.mapInfoHUDEnabled = YES; [self updateHUD]; } } @@ -439,7 +440,7 @@ CLLocationCoordinate2D randomWorldCoordinate() { [NSString stringWithFormat:@"%@ Reuse Queue Stats", (_reuseQueueStatsEnabled ? @"Hide" :@"Show")], @"Start World Tour", @"Random Tour", - [NSString stringWithFormat:@"%@ Zoom/Pitch/Direction Label", (_showZoomLevelEnabled ? @"Hide" :@"Show")], + [NSString stringWithFormat:@"%@ Map Info HUD", (_mapInfoHUDEnabled ? @"Hide" :@"Show")], @"Embedded Map View", [NSString stringWithFormat:@"%@ Second Map", ([self.view viewWithTag:2] == nil ? @"Show" : @"Hide")], [NSString stringWithFormat:@"Show Labels in %@", (_localizingLabels ? @"Default Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])], @@ -657,14 +658,14 @@ CLLocationCoordinate2D randomWorldCoordinate() { { self.reuseQueueStatsEnabled = !self.reuseQueueStatsEnabled; self.hudLabel.hidden = !self.reuseQueueStatsEnabled; - self.showZoomLevelEnabled = NO; + self.mapInfoHUDEnabled = NO; [self updateHUD]; break; } case MBXSettingsMiscellaneousShowZoomLevel: { - self.showZoomLevelEnabled = !self.showZoomLevelEnabled; - self.hudLabel.hidden = !self.showZoomLevelEnabled; + self.mapInfoHUDEnabled = !self.mapInfoHUDEnabled; + self.hudLabel.hidden = !self.mapInfoHUDEnabled; self.reuseQueueStatsEnabled = NO; [self updateHUD]; break; @@ -2191,7 +2192,7 @@ CLLocationCoordinate2D randomWorldCoordinate() { } - (void)updateHUD { - if (!self.reuseQueueStatsEnabled && !self.showZoomLevelEnabled) return; + if (!self.reuseQueueStatsEnabled && !self.mapInfoHUDEnabled) return; if (self.hudLabel.hidden) self.hudLabel.hidden = NO; @@ -2203,8 +2204,11 @@ CLLocationCoordinate2D randomWorldCoordinate() { queuedAnnotations += queue.count; } hudString = [NSString stringWithFormat:@"Visible: %ld Queued: %ld", (unsigned long)self.mapView.visibleAnnotations.count, (unsigned long)queuedAnnotations]; - } else if (self.showZoomLevelEnabled) { - hudString = [NSString stringWithFormat:@"%.2f ∕ ↕\U0000FE0E%.f° ∕ %.f°", self.mapView.zoomLevel, self.mapView.camera.pitch, self.mapView.direction]; + } else if (self.mapInfoHUDEnabled) { + if (!self.mapView.experimental_enableFrameRateMeasurement) self.mapView.experimental_enableFrameRateMeasurement = YES; + hudString = [NSString stringWithFormat:@"%.f FPS (%.1fms) ∕ %.2f ∕ ↕\U0000FE0E%.f° ∕ %.f°", + roundf(self.mapView.averageFrameRate), self.mapView.averageFrameTime, + self.mapView.zoomLevel, self.mapView.camera.pitch, self.mapView.direction]; } [self.hudLabel setTitle:hudString forState:UIControlStateNormal]; diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 48329cf63a..eab0d85417 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -1008,6 +1008,7 @@ 96E0272C1E57C7E5004B8E66 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = ""; }; 96E0272D1E57C7E6004B8E66 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vi; path = vi.lproj/Localizable.strings; sourceTree = ""; }; 96E0272E1E57C7E7004B8E66 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Localizable.strings"; sourceTree = ""; }; + 96F017292118FBAE00892778 /* MGLMapView_Experimental.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapView_Experimental.h; sourceTree = ""; }; 96F3F73B1F5711F1003E2D2C /* MGLUserLocationHeadingIndicator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLUserLocationHeadingIndicator.h; sourceTree = ""; }; AC518DFD201BB55A00EBC820 /* MGLTelemetryConfig.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MGLTelemetryConfig.h; sourceTree = ""; }; AC518DFE201BB55A00EBC820 /* MGLTelemetryConfig.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLTelemetryConfig.m; sourceTree = ""; }; @@ -1955,6 +1956,7 @@ CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */, DA704CC01F65A475004B3F28 /* MGLMapAccessibilityElement.h */, DA704CC11F65A475004B3F28 /* MGLMapAccessibilityElement.mm */, + 96F017292118FBAE00892778 /* MGLMapView_Experimental.h */, DA17BE2F1CC4BAC300402C41 /* MGLMapView_Private.h */, DA8848361CBAFB8500AB86E3 /* MGLMapView.h */, DA88484A1CBAFB9800AB86E3 /* MGLMapView.mm */, diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 7423c23c7b..2a231838a4 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -244,6 +244,12 @@ public: @property (nonatomic) MGLUserLocation *userLocation; @property (nonatomic) NSMutableDictionary *> *annotationViewReuseQueueByIdentifier; +/// Experimental rendering performance measurement. +@property (nonatomic) BOOL experimental_enableFrameRateMeasurement; +@property (nonatomic) CGFloat averageFrameRate; +@property (nonatomic) CFTimeInterval frameTime; +@property (nonatomic) CFTimeInterval averageFrameTime; + @end @implementation MGLMapView @@ -300,6 +306,11 @@ public: BOOL _accessibilityValueAnnouncementIsPending; MGLReachability *_reachability; + + /// Experimental rendering performance measurement. + CFTimeInterval _frameCounterStartTime; + NSInteger _frameCount; + CFTimeInterval _frameDurations; } #pragma mark - Setup & Teardown - @@ -1108,6 +1119,27 @@ public: [self.glView display]; } + + if (self.experimental_enableFrameRateMeasurement) + { + CFTimeInterval now = CACurrentMediaTime(); + + self.frameTime = now - _displayLink.timestamp; + _frameDurations += self.frameTime; + + _frameCount++; + + CFTimeInterval elapsed = now - _frameCounterStartTime; + + if (elapsed >= 1.0) { + self.averageFrameRate = _frameCount / elapsed; + self.averageFrameTime = (_frameDurations / _frameCount) * 1000; + + _frameCount = 0; + _frameDurations = 0; + _frameCounterStartTime = now; + } + } } - (void)setNeedsGLDisplay diff --git a/platform/ios/src/MGLMapView_Experimental.h b/platform/ios/src/MGLMapView_Experimental.h new file mode 100644 index 0000000000..94f8d67fb0 --- /dev/null +++ b/platform/ios/src/MGLMapView_Experimental.h @@ -0,0 +1,32 @@ +#import + +@interface MGLMapView (Experimental) + +#pragma mark Rendering Performance Measurement + +/** Enable rendering performance measurement. */ +@property (nonatomic) BOOL experimental_enableFrameRateMeasurement; + +/** + Average frames per second over the previous second, updated once per second. + + Requires `experimental_enableFrameRateMeasurement`. + */ +@property (nonatomic, readonly) CGFloat averageFrameRate; + +/** + Frame render duration for the previous frame, updated instantaneously. + + Requires `experimental_enableFrameRateMeasurement`. + */ +@property (nonatomic, readonly) CFTimeInterval frameTime; + +/** + Average frame render duration over the previous second, updated once per + second. + + Requires `experimental_enableFrameRateMeasurement`. + */ +@property (nonatomic, readonly) CFTimeInterval averageFrameTime; + +@end -- cgit v1.2.1 From 8ca419fb2ebbba427f2f27ba3d794fb3d6cc5797 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Tue, 17 Jul 2018 15:33:50 -0700 Subject: [core] Evict unused font stacks from GlyphManager --- include/mbgl/util/font_stack.hpp | 7 +++++ src/mbgl/renderer/renderer_impl.cpp | 4 +++ src/mbgl/style/parser.cpp | 28 +++--------------- src/mbgl/text/glyph_manager.cpp | 7 +++++ src/mbgl/text/glyph_manager.hpp | 3 ++ src/mbgl/util/font_stack.cpp | 40 ++++++++++++++++++++++++++ test/fixtures/style_parser/text-font.info.json | 16 +++++------ 7 files changed, 73 insertions(+), 32 deletions(-) diff --git a/include/mbgl/util/font_stack.hpp b/include/mbgl/util/font_stack.hpp index d0b431e9ea..ace60a4ba6 100644 --- a/include/mbgl/util/font_stack.hpp +++ b/include/mbgl/util/font_stack.hpp @@ -1,7 +1,11 @@ #pragma once +#include +#include + #include #include +#include namespace mbgl { @@ -14,4 +18,7 @@ struct FontStackHash { std::size_t operator()(const FontStack&) const; }; +// Statically evaluate layer properties to determine what font stacks are used. +std::set fontStacks(const std::vector>&); + } // namespace mbgl diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp index fea27403c9..d3f72b89b9 100644 --- a/src/mbgl/renderer/renderer_impl.cpp +++ b/src/mbgl/renderer/renderer_impl.cpp @@ -173,6 +173,10 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) { renderLayers.at(entry.first)->setImpl(entry.second.after); } + if (!layerDiff.removed.empty() || !layerDiff.added.empty() || !layerDiff.changed.empty()) { + glyphManager->evict(fontStacks(*updateParameters.layers)); + } + // Update layers for class and zoom changes. for (const auto& entry : renderLayers) { RenderLayer& layer = *entry.second; diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp index 8d14d7972c..0a90919f0b 100644 --- a/src/mbgl/style/parser.cpp +++ b/src/mbgl/style/parser.cpp @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -274,31 +273,12 @@ void Parser::parseLayer(const std::string& id, const JSValue& value, std::unique } std::vector Parser::fontStacks() const { - std::set result; - + std::vector> impls; + impls.reserve(layers.size()); for (const auto& layer : layers) { - if (layer->is() && !layer->as()->getTextField().isUndefined()) { - layer->as()->getTextFont().match( - [&] (Undefined) { - result.insert({"Open Sans Regular", "Arial Unicode MS Regular"}); - }, - [&] (const FontStack& constant) { - result.insert(constant); - }, - [&] (const auto& function) { - for (const auto& value : function.possibleOutputs()) { - if (value) { - result.insert(*value); - } else { - Log::Warning(Event::ParseStyle, "Layer '%s' has an invalid value for text-font and will not work offline. Output values must be contained as literals within the expression.", layer->getID().c_str()); - break; - } - } - } - ); - } + impls.emplace_back(layer->baseImpl); } - + std::set result = mbgl::fontStacks(impls); return std::vector(result.begin(), result.end()); } diff --git a/src/mbgl/text/glyph_manager.cpp b/src/mbgl/text/glyph_manager.cpp index 3130418908..8e7cfe5ba7 100644 --- a/src/mbgl/text/glyph_manager.cpp +++ b/src/mbgl/text/glyph_manager.cpp @@ -5,6 +5,7 @@ #include #include #include +#include namespace mbgl { @@ -153,4 +154,10 @@ void GlyphManager::removeRequestor(GlyphRequestor& requestor) { } } +void GlyphManager::evict(const std::set& keep) { + util::erase_if(entries, [&] (const auto& entry) { + return keep.count(entry.first) == 0; + }); +} + } // namespace mbgl diff --git a/src/mbgl/text/glyph_manager.hpp b/src/mbgl/text/glyph_manager.hpp index 84db2c4be5..642471bbf2 100644 --- a/src/mbgl/text/glyph_manager.hpp +++ b/src/mbgl/text/glyph_manager.hpp @@ -42,6 +42,9 @@ public: void setObserver(GlyphManagerObserver*); + // Remove glyphs for all but the supplied font stacks. + void evict(const std::set&); + private: Glyph generateLocalSDF(const FontStack& fontStack, GlyphID glyphID); diff --git a/src/mbgl/util/font_stack.cpp b/src/mbgl/util/font_stack.cpp index fb3b1b60a2..177d5e6f31 100644 --- a/src/mbgl/util/font_stack.cpp +++ b/src/mbgl/util/font_stack.cpp @@ -1,10 +1,14 @@ #include +#include +#include #include #include namespace mbgl { +using namespace style; + std::string fontStackToString(const FontStack& fontStack) { return boost::algorithm::join(fontStack, ","); } @@ -13,4 +17,40 @@ std::size_t FontStackHash::operator()(const FontStack& fontStack) const { return boost::hash_range(fontStack.begin(), fontStack.end()); } +std::set fontStacks(const std::vector>& layers) { + std::set result; + + for (const auto& layer : layers) { + if (layer->type != LayerType::Symbol) { + continue; + } + + const SymbolLayer::Impl& impl = dynamic_cast(*layer); + if (impl.layout.get().isUndefined()) { + continue; + } + + impl.layout.get().match( + [&] (Undefined) { + result.insert({"Open Sans Regular", "Arial Unicode MS Regular"}); + }, + [&] (const FontStack& constant) { + result.insert(constant); + }, + [&] (const auto& function) { + for (const auto& value : function.possibleOutputs()) { + if (value) { + result.insert(*value); + } else { + Log::Warning(Event::ParseStyle, "Layer '%s' has an invalid value for text-font and will not render text. Output values must be contained as literals within the expression.", impl.id.c_str()); + break; + } + } + } + ); + } + + return result; +} + } // namespace mbgl diff --git a/test/fixtures/style_parser/text-font.info.json b/test/fixtures/style_parser/text-font.info.json index 0fb9658269..dba9c707df 100644 --- a/test/fixtures/style_parser/text-font.info.json +++ b/test/fixtures/style_parser/text-font.info.json @@ -1,14 +1,14 @@ { "default": { "log": [ - [1, "WARNING", "ParseStyle", "Layer 'invalid expression - get' has an invalid value for text-font and will not work offline. Output values must be contained as literals within the expression."], - [1, "WARNING", "ParseStyle", "Layer 'invalid expression - case' has an invalid value for text-font and will not work offline. Output values must be contained as literals within the expression."], - [1, "WARNING", "ParseStyle", "Layer 'invalid expression - match' has an invalid value for text-font and will not work offline. Output values must be contained as literals within the expression."], - [1, "WARNING", "ParseStyle", "Layer 'invalid expression - at' has an invalid value for text-font and will not work offline. Output values must be contained as literals within the expression."], - [1, "WARNING", "ParseStyle", "Layer 'invalid expression - coalesce' has an invalid value for text-font and will not work offline. Output values must be contained as literals within the expression."], - [1, "WARNING", "ParseStyle", "Layer 'invalid expression - step' has an invalid value for text-font and will not work offline. Output values must be contained as literals within the expression."], - [1, "WARNING", "ParseStyle", "Layer 'invalid expression - let/var' has an invalid value for text-font and will not work offline. Output values must be contained as literals within the expression."], - [1, "WARNING", "ParseStyle", "Layer 'invalid expression - identity function' has an invalid value for text-font and will not work offline. Output values must be contained as literals within the expression."] + [1, "WARNING", "ParseStyle", "Layer 'invalid expression - get' has an invalid value for text-font and will not render text. Output values must be contained as literals within the expression."], + [1, "WARNING", "ParseStyle", "Layer 'invalid expression - case' has an invalid value for text-font and will not render text. Output values must be contained as literals within the expression."], + [1, "WARNING", "ParseStyle", "Layer 'invalid expression - match' has an invalid value for text-font and will not render text. Output values must be contained as literals within the expression."], + [1, "WARNING", "ParseStyle", "Layer 'invalid expression - at' has an invalid value for text-font and will not render text. Output values must be contained as literals within the expression."], + [1, "WARNING", "ParseStyle", "Layer 'invalid expression - coalesce' has an invalid value for text-font and will not render text. Output values must be contained as literals within the expression."], + [1, "WARNING", "ParseStyle", "Layer 'invalid expression - step' has an invalid value for text-font and will not render text. Output values must be contained as literals within the expression."], + [1, "WARNING", "ParseStyle", "Layer 'invalid expression - let/var' has an invalid value for text-font and will not render text. Output values must be contained as literals within the expression."], + [1, "WARNING", "ParseStyle", "Layer 'invalid expression - identity function' has an invalid value for text-font and will not render text. Output values must be contained as literals within the expression."] ] } } -- cgit v1.2.1 From 9df9f5fe2089a0dcd0d039115dec5cc63010603a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 17 Aug 2018 10:56:06 -0700 Subject: [build] simplify Android build --- platform/android/config.cmake | 364 +++++++++++++++++++++--------------------- 1 file changed, 178 insertions(+), 186 deletions(-) diff --git a/platform/android/config.cmake b/platform/android/config.cmake index bd65bc517f..e76a447c88 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -83,6 +83,160 @@ macro(mbgl_platform_core) PRIVATE platform/default/mbgl/map/map_snapshotter.cpp PRIVATE platform/default/mbgl/map/map_snapshotter.hpp PRIVATE platform/linux/src/headless_backend_egl.cpp + + # Conversion C++ -> Java + PRIVATE platform/android/src/conversion/constant.hpp + PRIVATE platform/android/src/conversion/conversion.hpp + PRIVATE platform/android/src/style/conversion/property_expression.hpp + PRIVATE platform/android/src/style/conversion/property_value.hpp + PRIVATE platform/android/src/style/conversion/types.hpp + PRIVATE platform/android/src/style/conversion/types_string_values.hpp + PRIVATE platform/android/src/map/camera_position.cpp + PRIVATE platform/android/src/map/camera_position.hpp + PRIVATE platform/android/src/map/image.cpp + PRIVATE platform/android/src/map/image.hpp + + # Style conversion Java -> C++ + PRIVATE platform/android/src/style/android_conversion.hpp + PRIVATE platform/android/src/style/value.cpp + PRIVATE platform/android/src/style/value.hpp + PRIVATE platform/android/src/style/conversion/url_or_tileset.hpp + + # Style + PRIVATE platform/android/src/style/transition_options.cpp + PRIVATE platform/android/src/style/transition_options.hpp + PRIVATE platform/android/src/style/layers/background_layer.cpp + PRIVATE platform/android/src/style/layers/background_layer.hpp + PRIVATE platform/android/src/style/layers/circle_layer.cpp + PRIVATE platform/android/src/style/layers/circle_layer.hpp + PRIVATE platform/android/src/style/layers/custom_layer.cpp + PRIVATE platform/android/src/style/layers/custom_layer.hpp + PRIVATE platform/android/src/style/layers/fill_extrusion_layer.cpp + PRIVATE platform/android/src/style/layers/fill_extrusion_layer.hpp + PRIVATE platform/android/src/style/layers/fill_layer.cpp + PRIVATE platform/android/src/style/layers/fill_layer.hpp + PRIVATE platform/android/src/style/layers/heatmap_layer.cpp + PRIVATE platform/android/src/style/layers/heatmap_layer.hpp + PRIVATE platform/android/src/style/layers/hillshade_layer.cpp + PRIVATE platform/android/src/style/layers/hillshade_layer.hpp + PRIVATE platform/android/src/style/layers/layer.cpp + PRIVATE platform/android/src/style/layers/layer.hpp + PRIVATE platform/android/src/style/layers/layers.cpp + PRIVATE platform/android/src/style/layers/layers.hpp + PRIVATE platform/android/src/style/layers/line_layer.cpp + PRIVATE platform/android/src/style/layers/line_layer.hpp + PRIVATE platform/android/src/style/layers/raster_layer.cpp + PRIVATE platform/android/src/style/layers/raster_layer.hpp + PRIVATE platform/android/src/style/layers/symbol_layer.cpp + PRIVATE platform/android/src/style/layers/symbol_layer.hpp + PRIVATE platform/android/src/style/layers/unknown_layer.cpp + PRIVATE platform/android/src/style/layers/unknown_layer.hpp + PRIVATE platform/android/src/style/sources/geojson_source.cpp + PRIVATE platform/android/src/style/sources/geojson_source.hpp + PRIVATE platform/android/src/style/sources/custom_geometry_source.cpp + PRIVATE platform/android/src/style/sources/custom_geometry_source.hpp + PRIVATE platform/android/src/style/sources/source.cpp + PRIVATE platform/android/src/style/sources/source.hpp + PRIVATE platform/android/src/style/sources/raster_source.cpp + PRIVATE platform/android/src/style/sources/raster_source.hpp + PRIVATE platform/android/src/style/sources/unknown_source.cpp + PRIVATE platform/android/src/style/sources/unknown_source.hpp + PRIVATE platform/android/src/style/sources/vector_source.cpp + PRIVATE platform/android/src/style/sources/vector_source.hpp + PRIVATE platform/android/src/style/sources/image_source.hpp + PRIVATE platform/android/src/style/sources/image_source.cpp + PRIVATE platform/android/src/style/sources/raster_dem_source.cpp + PRIVATE platform/android/src/style/sources/raster_dem_source.hpp + PRIVATE platform/android/src/style/position.cpp + PRIVATE platform/android/src/style/position.hpp + PRIVATE platform/android/src/style/light.cpp + PRIVATE platform/android/src/style/light.hpp + + # Native map + PRIVATE platform/android/src/native_map_view.cpp + PRIVATE platform/android/src/native_map_view.hpp + PRIVATE platform/android/src/map_renderer.cpp + PRIVATE platform/android/src/map_renderer.hpp + PRIVATE platform/android/src/map_renderer_runnable.cpp + PRIVATE platform/android/src/map_renderer_runnable.hpp + + # Java core classes + PRIVATE platform/android/src/java/lang.cpp + PRIVATE platform/android/src/java/lang.hpp + PRIVATE platform/android/src/java/util.cpp + PRIVATE platform/android/src/java/util.hpp + + # Graphics + PRIVATE platform/android/src/graphics/pointf.cpp + PRIVATE platform/android/src/graphics/pointf.hpp + PRIVATE platform/android/src/graphics/rectf.cpp + PRIVATE platform/android/src/graphics/rectf.hpp + + # GeoJSON + PRIVATE platform/android/src/geojson/feature.cpp + PRIVATE platform/android/src/geojson/feature.hpp + PRIVATE platform/android/src/geojson/feature_collection.cpp + PRIVATE platform/android/src/geojson/feature_collection.hpp + PRIVATE platform/android/src/geojson/geometry.cpp + PRIVATE platform/android/src/geojson/geometry.hpp + PRIVATE platform/android/src/geojson/geometry_collection.cpp + PRIVATE platform/android/src/geojson/geometry_collection.hpp + PRIVATE platform/android/src/geojson/line_string.cpp + PRIVATE platform/android/src/geojson/line_string.hpp + PRIVATE platform/android/src/geojson/multi_line_string.cpp + PRIVATE platform/android/src/geojson/multi_line_string.hpp + PRIVATE platform/android/src/geojson/multi_point.cpp + PRIVATE platform/android/src/geojson/multi_point.hpp + PRIVATE platform/android/src/geojson/multi_polygon.cpp + PRIVATE platform/android/src/geojson/multi_polygon.hpp + PRIVATE platform/android/src/geojson/point.cpp + PRIVATE platform/android/src/geojson/point.hpp + PRIVATE platform/android/src/geojson/polygon.cpp + PRIVATE platform/android/src/geojson/polygon.hpp + + # Geometry + PRIVATE platform/android/src/geometry/lat_lng.cpp + PRIVATE platform/android/src/geometry/lat_lng.hpp + PRIVATE platform/android/src/geometry/lat_lng_bounds.cpp + PRIVATE platform/android/src/geometry/lat_lng_bounds.hpp + PRIVATE platform/android/src/geometry/lat_lng_quad.cpp + PRIVATE platform/android/src/geometry/lat_lng_quad.hpp + PRIVATE platform/android/src/geometry/projected_meters.cpp + PRIVATE platform/android/src/geometry/projected_meters.hpp + + # GSon + PRIVATE platform/android/src/gson/json_array.cpp + PRIVATE platform/android/src/gson/json_array.hpp + PRIVATE platform/android/src/gson/json_element.cpp + PRIVATE platform/android/src/gson/json_element.hpp + PRIVATE platform/android/src/gson/json_object.cpp + PRIVATE platform/android/src/gson/json_object.hpp + PRIVATE platform/android/src/gson/json_primitive.cpp + PRIVATE platform/android/src/gson/json_primitive.hpp + + # Annotation + PRIVATE platform/android/src/annotation/marker.cpp + PRIVATE platform/android/src/annotation/marker.hpp + PRIVATE platform/android/src/annotation/polygon.cpp + PRIVATE platform/android/src/annotation/polygon.hpp + PRIVATE platform/android/src/annotation/polyline.cpp + PRIVATE platform/android/src/annotation/polyline.hpp + + # Snapshots (SDK) + PRIVATE platform/android/src/snapshotter/map_snapshotter.cpp + PRIVATE platform/android/src/snapshotter/map_snapshotter.hpp + PRIVATE platform/android/src/snapshotter/map_snapshot.cpp + PRIVATE platform/android/src/snapshotter/map_snapshot.hpp + + # Main jni bindings + PRIVATE platform/android/src/attach_env.cpp + PRIVATE platform/android/src/attach_env.hpp + PRIVATE platform/android/src/java_types.cpp + PRIVATE platform/android/src/java_types.hpp + + # Main entry point + PRIVATE platform/android/src/jni.hpp + PRIVATE platform/android/src/jni.cpp ) target_include_directories(mbgl-core @@ -118,6 +272,26 @@ macro(mbgl_filesource) PRIVATE platform/android/src/asset_manager_file_source.cpp PRIVATE platform/android/src/asset_manager_file_source.hpp + # FileSource holder + PRIVATE platform/android/src/file_source.cpp + PRIVATE platform/android/src/file_source.hpp + + # Connectivity + PRIVATE platform/android/src/connectivity_listener.cpp + PRIVATE platform/android/src/connectivity_listener.hpp + + # Offline + PRIVATE platform/android/src/offline/offline_manager.cpp + PRIVATE platform/android/src/offline/offline_manager.hpp + PRIVATE platform/android/src/offline/offline_region.cpp + PRIVATE platform/android/src/offline/offline_region.hpp + PRIVATE platform/android/src/offline/offline_region_definition.cpp + PRIVATE platform/android/src/offline/offline_region_definition.hpp + PRIVATE platform/android/src/offline/offline_region_error.cpp + PRIVATE platform/android/src/offline/offline_region_error.hpp + PRIVATE platform/android/src/offline/offline_region_status.cpp + PRIVATE platform/android/src/offline/offline_region_status.hpp + # Database PRIVATE platform/default/sqlite3.cpp ) @@ -133,190 +307,6 @@ macro(mbgl_filesource) ) endmacro() - -## Main library ## - -add_library(mbgl-android STATIC - # Conversion C++ -> Java - platform/android/src/conversion/constant.hpp - platform/android/src/conversion/conversion.hpp - platform/android/src/style/conversion/property_expression.hpp - platform/android/src/style/conversion/property_value.hpp - platform/android/src/style/conversion/types.hpp - platform/android/src/style/conversion/types_string_values.hpp - platform/android/src/map/camera_position.cpp - platform/android/src/map/camera_position.hpp - platform/android/src/map/image.cpp - platform/android/src/map/image.hpp - - # Style conversion Java -> C++ - platform/android/src/style/android_conversion.hpp - platform/android/src/style/value.cpp - platform/android/src/style/value.hpp - platform/android/src/style/conversion/url_or_tileset.hpp - - # Style - platform/android/src/style/transition_options.cpp - platform/android/src/style/transition_options.hpp - platform/android/src/style/layers/background_layer.cpp - platform/android/src/style/layers/background_layer.hpp - platform/android/src/style/layers/circle_layer.cpp - platform/android/src/style/layers/circle_layer.hpp - platform/android/src/style/layers/custom_layer.cpp - platform/android/src/style/layers/custom_layer.hpp - platform/android/src/style/layers/fill_extrusion_layer.cpp - platform/android/src/style/layers/fill_extrusion_layer.hpp - platform/android/src/style/layers/fill_layer.cpp - platform/android/src/style/layers/fill_layer.hpp - platform/android/src/style/layers/heatmap_layer.cpp - platform/android/src/style/layers/heatmap_layer.hpp - platform/android/src/style/layers/hillshade_layer.cpp - platform/android/src/style/layers/hillshade_layer.hpp - platform/android/src/style/layers/layer.cpp - platform/android/src/style/layers/layer.hpp - platform/android/src/style/layers/layers.cpp - platform/android/src/style/layers/layers.hpp - platform/android/src/style/layers/line_layer.cpp - platform/android/src/style/layers/line_layer.hpp - platform/android/src/style/layers/raster_layer.cpp - platform/android/src/style/layers/raster_layer.hpp - platform/android/src/style/layers/symbol_layer.cpp - platform/android/src/style/layers/symbol_layer.hpp - platform/android/src/style/layers/unknown_layer.cpp - platform/android/src/style/layers/unknown_layer.hpp - platform/android/src/style/sources/geojson_source.cpp - platform/android/src/style/sources/geojson_source.hpp - platform/android/src/style/sources/custom_geometry_source.cpp - platform/android/src/style/sources/custom_geometry_source.hpp - platform/android/src/style/sources/source.cpp - platform/android/src/style/sources/source.hpp - platform/android/src/style/sources/raster_source.cpp - platform/android/src/style/sources/raster_source.hpp - platform/android/src/style/sources/unknown_source.cpp - platform/android/src/style/sources/unknown_source.hpp - platform/android/src/style/sources/vector_source.cpp - platform/android/src/style/sources/vector_source.hpp - platform/android/src/style/sources/image_source.hpp - platform/android/src/style/sources/image_source.cpp - platform/android/src/style/sources/raster_dem_source.cpp - platform/android/src/style/sources/raster_dem_source.hpp - platform/android/src/style/position.cpp - platform/android/src/style/position.hpp - platform/android/src/style/light.cpp - platform/android/src/style/light.hpp - - # FileSource holder - platform/android/src/file_source.cpp - platform/android/src/file_source.hpp - - # Connectivity - platform/android/src/connectivity_listener.cpp - platform/android/src/connectivity_listener.hpp - - # Native map - platform/android/src/native_map_view.cpp - platform/android/src/native_map_view.hpp - platform/android/src/map_renderer.cpp - platform/android/src/map_renderer.hpp - platform/android/src/map_renderer_runnable.cpp - platform/android/src/map_renderer_runnable.hpp - - # Java core classes - platform/android/src/java/lang.cpp - platform/android/src/java/lang.hpp - platform/android/src/java/util.cpp - platform/android/src/java/util.hpp - - # Graphics - platform/android/src/graphics/pointf.cpp - platform/android/src/graphics/pointf.hpp - platform/android/src/graphics/rectf.cpp - platform/android/src/graphics/rectf.hpp - - # GeoJSON - platform/android/src/geojson/feature.cpp - platform/android/src/geojson/feature.hpp - platform/android/src/geojson/feature_collection.cpp - platform/android/src/geojson/feature_collection.hpp - platform/android/src/geojson/geometry.cpp - platform/android/src/geojson/geometry.hpp - platform/android/src/geojson/geometry_collection.cpp - platform/android/src/geojson/geometry_collection.hpp - platform/android/src/geojson/line_string.cpp - platform/android/src/geojson/line_string.hpp - platform/android/src/geojson/multi_line_string.cpp - platform/android/src/geojson/multi_line_string.hpp - platform/android/src/geojson/multi_point.cpp - platform/android/src/geojson/multi_point.hpp - platform/android/src/geojson/multi_polygon.cpp - platform/android/src/geojson/multi_polygon.hpp - platform/android/src/geojson/point.cpp - platform/android/src/geojson/point.hpp - platform/android/src/geojson/polygon.cpp - platform/android/src/geojson/polygon.hpp - - # Geometry - platform/android/src/geometry/lat_lng.cpp - platform/android/src/geometry/lat_lng.hpp - platform/android/src/geometry/lat_lng_bounds.cpp - platform/android/src/geometry/lat_lng_bounds.hpp - platform/android/src/geometry/lat_lng_quad.cpp - platform/android/src/geometry/lat_lng_quad.hpp - platform/android/src/geometry/projected_meters.cpp - platform/android/src/geometry/projected_meters.hpp - - # GSon - platform/android/src/gson/json_array.cpp - platform/android/src/gson/json_array.hpp - platform/android/src/gson/json_element.cpp - platform/android/src/gson/json_element.hpp - platform/android/src/gson/json_object.cpp - platform/android/src/gson/json_object.hpp - platform/android/src/gson/json_primitive.cpp - platform/android/src/gson/json_primitive.hpp - - # Annotation - platform/android/src/annotation/marker.cpp - platform/android/src/annotation/marker.hpp - platform/android/src/annotation/polygon.cpp - platform/android/src/annotation/polygon.hpp - platform/android/src/annotation/polyline.cpp - platform/android/src/annotation/polyline.hpp - - # Offline - platform/android/src/offline/offline_manager.cpp - platform/android/src/offline/offline_manager.hpp - platform/android/src/offline/offline_region.cpp - platform/android/src/offline/offline_region.hpp - platform/android/src/offline/offline_region_definition.cpp - platform/android/src/offline/offline_region_definition.hpp - platform/android/src/offline/offline_region_error.cpp - platform/android/src/offline/offline_region_error.hpp - platform/android/src/offline/offline_region_status.cpp - platform/android/src/offline/offline_region_status.hpp - - # Snapshots (SDK) - platform/android/src/snapshotter/map_snapshotter.cpp - platform/android/src/snapshotter/map_snapshotter.hpp - platform/android/src/snapshotter/map_snapshot.cpp - platform/android/src/snapshotter/map_snapshot.hpp - - # Main jni bindings - platform/android/src/attach_env.cpp - platform/android/src/attach_env.hpp - platform/android/src/java_types.cpp - platform/android/src/java_types.hpp - - # Main entry point - platform/android/src/jni.hpp - platform/android/src/jni.cpp -) - -target_link_libraries(mbgl-android - PUBLIC mbgl-filesource - PUBLIC mbgl-core -) - ## Shared library add_library(mapbox-gl SHARED @@ -324,7 +314,8 @@ add_library(mapbox-gl SHARED ) target_link_libraries(mapbox-gl - PRIVATE mbgl-android + PRIVATE mbgl-core + PRIVATE mbgl-filesource ) ## Test library ## @@ -343,7 +334,8 @@ macro(mbgl_platform_test) ) target_link_libraries(mbgl-test - PRIVATE mbgl-android + PRIVATE mbgl-core + PRIVATE mbgl-filesource ) endmacro() -- cgit v1.2.1 From 112bbc7ab289298094d6e6593437a71ec8029caa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Fri, 17 Aug 2018 15:38:47 -0700 Subject: [core] make style/conversion.hpp implementation private --- benchmark/function/camera_function.benchmark.cpp | 2 +- .../function/composite_function.benchmark.cpp | 2 +- benchmark/function/source_function.benchmark.cpp | 2 +- benchmark/parse/filter.benchmark.cpp | 2 +- cmake/core-files.cmake | 2 + include/mbgl/style/conversion.hpp | 290 +------------------- include/mbgl/style/conversion/constant.hpp | 35 +-- include/mbgl/style/conversion/coordinate.hpp | 1 + .../conversion/custom_geometry_source_options.hpp | 1 + include/mbgl/style/conversion/filter.hpp | 1 + include/mbgl/style/conversion/function.hpp | 22 +- include/mbgl/style/conversion/geojson.hpp | 3 +- include/mbgl/style/conversion/geojson_options.hpp | 3 +- include/mbgl/style/conversion/layer.hpp | 1 + include/mbgl/style/conversion/light.hpp | 1 + include/mbgl/style/conversion/position.hpp | 3 +- include/mbgl/style/conversion/property_value.hpp | 50 +--- include/mbgl/style/conversion/source.hpp | 3 +- include/mbgl/style/conversion/tileset.hpp | 1 + .../mbgl/style/conversion/transition_options.hpp | 1 + include/mbgl/style/conversion_impl.hpp | 302 +++++++++++++++++++++ include/mbgl/style/expression/assertion.hpp | 2 +- include/mbgl/style/expression/case.hpp | 2 +- include/mbgl/style/expression/coalesce.hpp | 2 +- .../mbgl/style/expression/compound_expression.hpp | 2 +- include/mbgl/style/expression/parsing_context.hpp | 1 + include/mbgl/style/layer.hpp | 1 + platform/android/config.cmake | 7 +- platform/android/src/native_map_view.cpp | 2 +- platform/android/src/style/android_conversion.hpp | 2 +- platform/android/src/style/conversion/filter.hpp | 2 +- .../android/src/style/conversion/latlngquad.hpp | 2 +- .../src/style/conversion/url_or_tileset.hpp | 2 +- platform/android/src/style/layers/layer.cpp | 2 +- .../android/src/style/sources/geojson_source.cpp | 2 +- .../android/src/style/sources/image_source.cpp | 2 +- platform/android/src/style/sources/source.cpp | 2 +- platform/darwin/src/MGLConversion.h | 2 +- platform/node/src/node_conversion.hpp | 2 +- platform/node/src/node_expression.hpp | 2 +- platform/qt/src/qmapboxgl.cpp | 2 +- platform/qt/src/qt_conversion.hpp | 2 +- .../style/conversion/color_ramp_property_value.cpp | 2 +- src/mbgl/style/conversion/constant.cpp | 56 ++++ src/mbgl/style/conversion/coordinate.cpp | 1 + .../conversion/custom_geometry_source_options.cpp | 1 + src/mbgl/style/conversion/filter.cpp | 3 +- src/mbgl/style/conversion/function.cpp | 68 +++++ src/mbgl/style/conversion/geojson.cpp | 1 + src/mbgl/style/conversion/geojson_options.cpp | 1 + src/mbgl/style/conversion/get_json_type.cpp | 1 + src/mbgl/style/conversion/json.hpp | 2 +- src/mbgl/style/conversion/layer.cpp | 1 + src/mbgl/style/conversion/light.cpp | 1 + src/mbgl/style/conversion/position.cpp | 1 + src/mbgl/style/conversion/property_value.cpp | 83 ++++++ src/mbgl/style/conversion/source.cpp | 1 + src/mbgl/style/conversion/tileset.cpp | 1 + src/mbgl/style/conversion/transition_options.cpp | 1 + src/mbgl/style/expression/array_assertion.cpp | 1 + src/mbgl/style/expression/assertion.cpp | 1 + src/mbgl/style/expression/at.cpp | 1 + src/mbgl/style/expression/boolean_operator.cpp | 1 + src/mbgl/style/expression/case.cpp | 1 + src/mbgl/style/expression/coalesce.cpp | 1 + src/mbgl/style/expression/coercion.cpp | 1 + src/mbgl/style/expression/collator_expression.cpp | 1 + src/mbgl/style/expression/comparison.cpp | 1 + src/mbgl/style/expression/compound_expression.cpp | 1 + src/mbgl/style/expression/interpolate.cpp | 1 + src/mbgl/style/expression/is_expression.cpp | 3 +- src/mbgl/style/expression/length.cpp | 1 + src/mbgl/style/expression/let.cpp | 1 + src/mbgl/style/expression/literal.cpp | 1 + src/mbgl/style/expression/match.cpp | 1 + src/mbgl/style/expression/parsing_context.cpp | 1 + src/mbgl/style/expression/step.cpp | 1 + src/mbgl/style/layer.cpp | 1 + src/mbgl/style/layers/background_layer.cpp | 2 +- src/mbgl/style/layers/circle_layer.cpp | 2 +- src/mbgl/style/layers/fill_extrusion_layer.cpp | 2 +- src/mbgl/style/layers/fill_layer.cpp | 2 +- src/mbgl/style/layers/heatmap_layer.cpp | 2 +- src/mbgl/style/layers/hillshade_layer.cpp | 2 +- src/mbgl/style/layers/layer.cpp.ejs | 2 +- src/mbgl/style/layers/line_layer.cpp | 2 +- src/mbgl/style/layers/raster_layer.cpp | 2 +- src/mbgl/style/layers/symbol_layer.cpp | 2 +- src/mbgl/style/parser.cpp | 2 +- src/mbgl/style/rapidjson_conversion.hpp | 2 +- test/style/conversion/light.test.cpp | 2 +- test/style/expression/expression.test.cpp | 2 +- 92 files changed, 616 insertions(+), 431 deletions(-) create mode 100644 include/mbgl/style/conversion_impl.hpp create mode 100644 src/mbgl/style/conversion/property_value.cpp diff --git a/benchmark/function/camera_function.benchmark.cpp b/benchmark/function/camera_function.benchmark.cpp index 51d2e22293..0ce7d7c763 100644 --- a/benchmark/function/camera_function.benchmark.cpp +++ b/benchmark/function/camera_function.benchmark.cpp @@ -1,9 +1,9 @@ #include -#include #include #include #include +#include using namespace mbgl; using namespace mbgl::style; diff --git a/benchmark/function/composite_function.benchmark.cpp b/benchmark/function/composite_function.benchmark.cpp index f16254641f..8064d548fa 100644 --- a/benchmark/function/composite_function.benchmark.cpp +++ b/benchmark/function/composite_function.benchmark.cpp @@ -2,10 +2,10 @@ #include -#include #include #include #include +#include using namespace mbgl; using namespace mbgl::style; diff --git a/benchmark/function/source_function.benchmark.cpp b/benchmark/function/source_function.benchmark.cpp index 2164b2a418..b75cc143d2 100644 --- a/benchmark/function/source_function.benchmark.cpp +++ b/benchmark/function/source_function.benchmark.cpp @@ -2,9 +2,9 @@ #include -#include #include #include +#include using namespace mbgl; using namespace mbgl::style; diff --git a/benchmark/parse/filter.benchmark.cpp b/benchmark/parse/filter.benchmark.cpp index 4e39237138..1ae2b0f2bc 100644 --- a/benchmark/parse/filter.benchmark.cpp +++ b/benchmark/parse/filter.benchmark.cpp @@ -1,9 +1,9 @@ #include #include -#include #include #include +#include #include #include diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake index 02335fef7a..2d0bd003c7 100644 --- a/cmake/core-files.cmake +++ b/cmake/core-files.cmake @@ -363,6 +363,7 @@ set(MBGL_CORE_FILES # style include/mbgl/style/color_ramp_property_value.hpp include/mbgl/style/conversion.hpp + include/mbgl/style/conversion_impl.hpp include/mbgl/style/filter.hpp include/mbgl/style/image.hpp include/mbgl/style/layer.hpp @@ -437,6 +438,7 @@ set(MBGL_CORE_FILES src/mbgl/style/conversion/layer.cpp src/mbgl/style/conversion/light.cpp src/mbgl/style/conversion/position.cpp + src/mbgl/style/conversion/property_value.cpp src/mbgl/style/conversion/source.cpp src/mbgl/style/conversion/stringify.hpp src/mbgl/style/conversion/tileset.cpp diff --git a/include/mbgl/style/conversion.hpp b/include/mbgl/style/conversion.hpp index 71c2cec237..2c83d1561b 100644 --- a/include/mbgl/style/conversion.hpp +++ b/include/mbgl/style/conversion.hpp @@ -1,306 +1,26 @@ #pragma once -#include -#include -#include - #include namespace mbgl { namespace style { namespace conversion { -/* - The `conversion` namespace defines conversions from JSON structures conforming to the schema defined by - the Mapbox Style Specification, to the various C++ types that form the C++ model of that domain: - - * `std::unique_ptr` - * `std::unique_ptr` - * `Filter` - * `PropertyValue` - - A single template function serves as the public interface: - - template - optional convert(const Convertible& input, Error& error); - - Where `T` is one of the above types. If the conversion fails, the result is empty, and the - error parameter includes diagnostic text suitable for presentation to a library user. Otherwise, - a filled optional is returned. - - `Convertible` is a type that encapsulates a special form of polymorphism over various underlying types that - can serve as input to the conversion algorithm. For instance, on macOS, we need to support - conversion from both RapidJSON types, and a JSON structure represented with `NSArray`/`NSDictionary`/etc. - On Qt, we need to support conversion from RapidJSON types and QVariant. - - We don't want to use traditional forms of polymorphism to accomplish this: - - * Compile time polymorphism using a template parameter for the actual value type leads to - excessive code bloat and long compile times. - * Runtime polymorphism using virtual methods requires extra heap allocation and ubiquitous - use of std::unique_ptr, unsuitable for this performance-sensitive code. - - Therefore, we're using a custom implementation of runtime polymorphism where we manually create and - dispatch through a table of function pointers (vtable), while keeping the storage for any of the possible - underlying types inline on the stack, using `std::aligned_storage`. - - For a given underlying type T, an explicit specialization of `ConversionTraits` must be provided. This - specialization must provide the following static methods: - - * `isUndefined(v)` -- returns a boolean indication whether `v` is undefined or a JSON null - - * `isArray(v)` -- returns a boolean indicating whether `v` represents a JSON array - * `arrayLength(v)` -- called only if `isArray(v)`; returns a size_t length - * `arrayMember(v)` -- called only if `isArray(v)`; returns `V` or `V&` - - * `isObject(v)` -- returns a boolean indicating whether `v` represents a JSON object - * `objectMember(v, name)` -- called only if `isObject(v)`; `name` is `const char *`; return value: - * is true when evaluated in a boolean context iff the named member exists - * is convertable to a `V` or `V&` when dereferenced - * `eachMember(v, [] (const std::string&, const V&) -> optional {...})` -- called - only if `isObject(v)`; calls the provided lambda once for each key and value of the object; - short-circuits if any call returns an `Error` - - * `toBool(v)` -- returns `optional`, absence indicating `v` is not a JSON boolean - * `toNumber(v)` -- returns `optional`, absence indicating `v` is not a JSON number - * `toDouble(v)` -- returns `optional`, absence indicating `v` is not a JSON number - * `toString(v)` -- returns `optional`, absence indicating `v` is not a JSON string - * `toValue(v)` -- returns `optional`, a variant type, for generic conversion, - absence indicating `v` is not a boolean, number, or string. Numbers should be converted to - unsigned integer, signed integer, or floating point, in descending preference. - - In addition, the type T must be move-constructable. And finally, `Convertible::Storage`, a typedef for - `std::aligned_storage_t`, must be large enough to satisfy the memory requirements for any of the - possible underlying types. (A static assert will fail if this is not the case.) - - `Convertible` itself is movable, but not copyable. A moved-from `Convertible` is in an invalid state; - you must not do anything with it except let it go out of scope. -*/ +// This is a forward-declaration only header intended to minimize dependencies and to improve +// compilation speed. In order to specialize implementations and get access to the actual +// implementation, include . struct Error { std::string message; }; template class ConversionTraits; -class Convertible { -public: - template - Convertible(T&& value) : vtable(vtableForType>()) { - static_assert(sizeof(Storage) >= sizeof(std::decay_t), "Storage must be large enough to hold value type"); - new (static_cast(&storage)) std::decay_t(std::forward(value)); - } - - Convertible(Convertible&& v) - : vtable(v.vtable) - { - if (vtable) { - vtable->move(std::move(v.storage), this->storage); - } - } - - ~Convertible() { - if (vtable) { - vtable->destroy(storage); - } - } - - Convertible& operator=(Convertible&& v) { - if (vtable) { - vtable->destroy(storage); - } - vtable = v.vtable; - if (vtable) { - vtable->move(std::move(v.storage), this->storage); - } - v.vtable = nullptr; - return *this; - } - - Convertible() = delete; - Convertible(const Convertible&) = delete; - Convertible& operator=(const Convertible&) = delete; - - friend inline bool isUndefined(const Convertible& v) { - assert(v.vtable); - return v.vtable->isUndefined(v.storage); - } - - friend inline bool isArray(const Convertible& v) { - assert(v.vtable); - return v.vtable->isArray(v.storage); - } - - friend inline std::size_t arrayLength(const Convertible& v) { - assert(v.vtable); - return v.vtable->arrayLength(v.storage); - } - - friend inline Convertible arrayMember(const Convertible& v, std::size_t i) { - assert(v.vtable); - return v.vtable->arrayMember(v.storage, i); - } - - friend inline bool isObject(const Convertible& v) { - assert(v.vtable); - return v.vtable->isObject(v.storage); - } - - friend inline optional objectMember(const Convertible& v, const char * name) { - assert(v.vtable); - return v.vtable->objectMember(v.storage, name); - } - - friend inline optional eachMember(const Convertible& v, const std::function (const std::string&, const Convertible&)>& fn) { - assert(v.vtable); - return v.vtable->eachMember(v.storage, fn); - } - - friend inline optional toBool(const Convertible& v) { - assert(v.vtable); - return v.vtable->toBool(v.storage); - } - - friend inline optional toNumber(const Convertible& v) { - assert(v.vtable); - return v.vtable->toNumber(v.storage); - } - - friend inline optional toDouble(const Convertible& v) { - assert(v.vtable); - return v.vtable->toDouble(v.storage); - } - - friend inline optional toString(const Convertible& v) { - assert(v.vtable); - return v.vtable->toString(v.storage); - } - - friend inline optional toValue(const Convertible& v) { - assert(v.vtable); - return v.vtable->toValue(v.storage); - } - - friend inline optional toGeoJSON(const Convertible& v, Error& error) { - assert(v.vtable); - return v.vtable->toGeoJSON(v.storage, error); - } - -private: -#if __ANDROID__ - // Android: JSValue* or mbgl::android::Value - using Storage = std::aligned_storage_t<32, 8>; -#elif __QT__ - // Qt: JSValue* or QVariant - using Storage = std::aligned_storage_t<32, 8>; -#else - // Node: JSValue* or v8::Local - // iOS/macOS: JSValue* or id - using Storage = std::aligned_storage_t<8, 8>; -#endif - - struct VTable { - void (*move) (Storage&& src, Storage& dest); - void (*destroy) (Storage&); - - bool (*isUndefined) (const Storage&); - - bool (*isArray) (const Storage&); - std::size_t (*arrayLength) (const Storage&); - Convertible (*arrayMember) (const Storage&, std::size_t); - - bool (*isObject) (const Storage&); - optional (*objectMember) (const Storage&, const char *); - optional (*eachMember) (const Storage&, const std::function (const std::string&, const Convertible&)>&); - - optional (*toBool) (const Storage&); - optional (*toNumber) (const Storage&); - optional (*toDouble) (const Storage&); - optional (*toString) (const Storage&); - optional (*toValue) (const Storage&); - - // https://github.com/mapbox/mapbox-gl-native/issues/5623 - optional (*toGeoJSON) (const Storage&, Error&); - }; - - // Extracted this function from the table below to work around a GCC bug with differing - // visibility settings for capturing lambdas: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947 - template - static auto vtableEachMember(const Storage& s, const std::function(const std::string&, const Convertible&)>& fn) { - return ConversionTraits::eachMember(reinterpret_cast(s), [&](const std::string& k, T&& v) { - return fn(k, Convertible(std::move(v))); - }); - } - - template - static VTable* vtableForType() { - using Traits = ConversionTraits; - static VTable vtable = { - [] (Storage&& src, Storage& dest) { - auto srcValue = reinterpret_cast(src); - new (static_cast(&dest)) T(std::move(srcValue)); - srcValue.~T(); - }, - [] (Storage& s) { - reinterpret_cast(s).~T(); - }, - [] (const Storage& s) { - return Traits::isUndefined(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::isArray(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::arrayLength(reinterpret_cast(s)); - }, - [] (const Storage& s, std::size_t i) { - return Convertible(Traits::arrayMember(reinterpret_cast(s), i)); - }, - [] (const Storage& s) { - return Traits::isObject(reinterpret_cast(s)); - }, - [] (const Storage& s, const char * key) { - optional member = Traits::objectMember(reinterpret_cast(s), key); - if (member) { - return optional(Convertible(std::move(*member))); - } else { - return optional(); - } - }, - vtableEachMember, - [] (const Storage& s) { - return Traits::toBool(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::toNumber(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::toDouble(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::toString(reinterpret_cast(s)); - }, - [] (const Storage& s) { - return Traits::toValue(reinterpret_cast(s)); - }, - [] (const Storage& s, Error& err) { - return Traits::toGeoJSON(reinterpret_cast(s), err); - } - }; - return &vtable; - } - - VTable* vtable; - Storage storage; -}; +class Convertible; template struct Converter; -template -optional convert(const Convertible& value, Error& error, Args&&...args) { - return Converter()(value, error, std::forward(args)...); -} - } // namespace conversion } // namespace style } // namespace mbgl + diff --git a/include/mbgl/style/conversion/constant.hpp b/include/mbgl/style/conversion/constant.hpp index 7d74ec42ce..40657528c4 100644 --- a/include/mbgl/style/conversion/constant.hpp +++ b/include/mbgl/style/conversion/constant.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -30,21 +31,7 @@ struct Converter { template struct Converter::value>> { - optional operator()(const Convertible& value, Error& error) const { - optional string = toString(value); - if (!string) { - error.message = "value must be a string"; - return nullopt; - } - - const auto result = Enum::toEnum(*string); - if (!result) { - error.message = "value must be a valid enumeration value"; - return nullopt; - } - - return *result; - } + optional operator()(const Convertible& value, Error& error) const; }; template <> @@ -54,23 +41,7 @@ struct Converter { template struct Converter> { - optional> operator()(const Convertible& value, Error& error) const { - if (!isArray(value) || arrayLength(value) != N) { - error.message = "value must be an array of " + util::toString(N) + " numbers"; - return nullopt; - } - - std::array result; - for (size_t i = 0; i < N; i++) { - optional n = toNumber(arrayMember(value, i)); - if (!n) { - error.message = "value must be an array of " + util::toString(N) + " numbers"; - return nullopt; - } - result[i] = *n; - } - return result; - } + optional> operator()(const Convertible& value, Error& error) const; }; template <> diff --git a/include/mbgl/style/conversion/coordinate.hpp b/include/mbgl/style/conversion/coordinate.hpp index e11db5e32f..1346ed738a 100644 --- a/include/mbgl/style/conversion/coordinate.hpp +++ b/include/mbgl/style/conversion/coordinate.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/custom_geometry_source_options.hpp b/include/mbgl/style/conversion/custom_geometry_source_options.hpp index f0f505e54f..090e5b6239 100644 --- a/include/mbgl/style/conversion/custom_geometry_source_options.hpp +++ b/include/mbgl/style/conversion/custom_geometry_source_options.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/filter.hpp b/include/mbgl/style/conversion/filter.hpp index 9daf6ea7a4..2d7ad0afc7 100644 --- a/include/mbgl/style/conversion/filter.hpp +++ b/include/mbgl/style/conversion/filter.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/function.hpp b/include/mbgl/style/conversion/function.hpp index 49825a3410..ba9acd7a3b 100644 --- a/include/mbgl/style/conversion/function.hpp +++ b/include/mbgl/style/conversion/function.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include #include @@ -16,25 +16,7 @@ std::unique_ptr convertTokenStringToExpression(const std optional> convertFunctionToExpression(expression::type::Type, const Convertible&, Error&, bool convertTokens); template -optional> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens) { - auto expression = convertFunctionToExpression(expression::valueTypeToExpressionType(), value, error, convertTokens); - if (!expression) { - return nullopt; - } - - optional defaultValue; - - auto defaultValueValue = objectMember(value, "default"); - if (defaultValueValue) { - defaultValue = convert(*defaultValueValue, error); - if (!defaultValue) { - error.message = R"(wrong type for "default": )" + error.message; - return nullopt; - } - } - - return PropertyExpression(std::move(*expression), defaultValue); -} +optional> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens); } // namespace conversion } // namespace style diff --git a/include/mbgl/style/conversion/geojson.hpp b/include/mbgl/style/conversion/geojson.hpp index 403c5f953b..90c1d64197 100644 --- a/include/mbgl/style/conversion/geojson.hpp +++ b/include/mbgl/style/conversion/geojson.hpp @@ -1,7 +1,8 @@ #pragma once -#include #include +#include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/geojson_options.hpp b/include/mbgl/style/conversion/geojson_options.hpp index 3f625babb6..89511848dd 100644 --- a/include/mbgl/style/conversion/geojson_options.hpp +++ b/include/mbgl/style/conversion/geojson_options.hpp @@ -1,7 +1,8 @@ #pragma once -#include #include +#include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/layer.hpp b/include/mbgl/style/conversion/layer.hpp index 2df6c9e381..9cf019378b 100644 --- a/include/mbgl/style/conversion/layer.hpp +++ b/include/mbgl/style/conversion/layer.hpp @@ -2,6 +2,7 @@ #include #include +#include #include diff --git a/include/mbgl/style/conversion/light.hpp b/include/mbgl/style/conversion/light.hpp index 289fca2e31..2f6f8628b8 100644 --- a/include/mbgl/style/conversion/light.hpp +++ b/include/mbgl/style/conversion/light.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/position.hpp b/include/mbgl/style/conversion/position.hpp index 044c45862d..10db5c6ec1 100644 --- a/include/mbgl/style/conversion/position.hpp +++ b/include/mbgl/style/conversion/position.hpp @@ -1,7 +1,8 @@ #pragma once -#include #include +#include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/property_value.hpp b/include/mbgl/style/conversion/property_value.hpp index fa6752867b..f6f36db983 100644 --- a/include/mbgl/style/conversion/property_value.hpp +++ b/include/mbgl/style/conversion/property_value.hpp @@ -1,9 +1,9 @@ #pragma once #include -#include #include #include +#include #include #include #include @@ -16,53 +16,7 @@ namespace conversion { template struct Converter> { - optional> operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const { - using namespace mbgl::style::expression; - - if (isUndefined(value)) { - return PropertyValue(); - } - - optional> expression; - - if (isExpression(value)) { - ParsingContext ctx(valueTypeToExpressionType()); - ParseResult parsed = ctx.parseLayerPropertyExpression(value); - if (!parsed) { - error.message = ctx.getCombinedErrors(); - return nullopt; - } - expression = PropertyExpression(std::move(*parsed)); - } else if (isObject(value)) { - expression = convertFunctionToExpression(value, error, convertTokens); - } else { - optional constant = convert(value, error); - if (!constant) { - return nullopt; - } - return convertTokens ? maybeConvertTokens(*constant) : PropertyValue(*constant); - } - - if (!expression) { - return nullopt; - } else if (!allowDataExpressions && !(*expression).isFeatureConstant()) { - error.message = "data expressions not supported"; - return nullopt; - } else if (!(*expression).isFeatureConstant() || !(*expression).isZoomConstant()) { - return { std::move(*expression) }; - } else if ((*expression).getExpression().getKind() == Kind::Literal) { - optional constant = fromExpressionValue( - static_cast((*expression).getExpression()).getValue()); - if (!constant) { - return nullopt; - } - return PropertyValue(*constant); - } else { - assert(false); - error.message = "expected a literal expression"; - return nullopt; - } - } + optional> operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const; template PropertyValue maybeConvertTokens(const S& t) const { diff --git a/include/mbgl/style/conversion/source.hpp b/include/mbgl/style/conversion/source.hpp index 2cf2e36da4..19bc1ce6b6 100644 --- a/include/mbgl/style/conversion/source.hpp +++ b/include/mbgl/style/conversion/source.hpp @@ -1,7 +1,8 @@ #pragma once -#include #include +#include +#include #include diff --git a/include/mbgl/style/conversion/tileset.hpp b/include/mbgl/style/conversion/tileset.hpp index 1fb4acf70d..88661c358c 100644 --- a/include/mbgl/style/conversion/tileset.hpp +++ b/include/mbgl/style/conversion/tileset.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion/transition_options.hpp b/include/mbgl/style/conversion/transition_options.hpp index 0563f39ac3..a72d757d3c 100644 --- a/include/mbgl/style/conversion/transition_options.hpp +++ b/include/mbgl/style/conversion/transition_options.hpp @@ -2,6 +2,7 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/include/mbgl/style/conversion_impl.hpp b/include/mbgl/style/conversion_impl.hpp new file mode 100644 index 0000000000..27b2ee1917 --- /dev/null +++ b/include/mbgl/style/conversion_impl.hpp @@ -0,0 +1,302 @@ +#pragma once + +#include +#include +#include +#include + +#include + +namespace mbgl { +namespace style { +namespace conversion { + +/* + The `conversion` namespace defines conversions from JSON structures conforming to the schema defined by + the Mapbox Style Specification, to the various C++ types that form the C++ model of that domain: + + * `std::unique_ptr` + * `std::unique_ptr` + * `Filter` + * `PropertyValue` + + A single template function serves as the public interface: + + template + optional convert(const Convertible& input, Error& error); + + Where `T` is one of the above types. If the conversion fails, the result is empty, and the + error parameter includes diagnostic text suitable for presentation to a library user. Otherwise, + a filled optional is returned. + + `Convertible` is a type that encapsulates a special form of polymorphism over various underlying types that + can serve as input to the conversion algorithm. For instance, on macOS, we need to support + conversion from both RapidJSON types, and a JSON structure represented with `NSArray`/`NSDictionary`/etc. + On Qt, we need to support conversion from RapidJSON types and QVariant. + + We don't want to use traditional forms of polymorphism to accomplish this: + + * Compile time polymorphism using a template parameter for the actual value type leads to + excessive code bloat and long compile times. + * Runtime polymorphism using virtual methods requires extra heap allocation and ubiquitous + use of std::unique_ptr, unsuitable for this performance-sensitive code. + + Therefore, we're using a custom implementation of runtime polymorphism where we manually create and + dispatch through a table of function pointers (vtable), while keeping the storage for any of the possible + underlying types inline on the stack, using `std::aligned_storage`. + + For a given underlying type T, an explicit specialization of `ConversionTraits` must be provided. This + specialization must provide the following static methods: + + * `isUndefined(v)` -- returns a boolean indication whether `v` is undefined or a JSON null + + * `isArray(v)` -- returns a boolean indicating whether `v` represents a JSON array + * `arrayLength(v)` -- called only if `isArray(v)`; returns a size_t length + * `arrayMember(v)` -- called only if `isArray(v)`; returns `V` or `V&` + + * `isObject(v)` -- returns a boolean indicating whether `v` represents a JSON object + * `objectMember(v, name)` -- called only if `isObject(v)`; `name` is `const char *`; return value: + * is true when evaluated in a boolean context iff the named member exists + * is convertable to a `V` or `V&` when dereferenced + * `eachMember(v, [] (const std::string&, const V&) -> optional {...})` -- called + only if `isObject(v)`; calls the provided lambda once for each key and value of the object; + short-circuits if any call returns an `Error` + + * `toBool(v)` -- returns `optional`, absence indicating `v` is not a JSON boolean + * `toNumber(v)` -- returns `optional`, absence indicating `v` is not a JSON number + * `toDouble(v)` -- returns `optional`, absence indicating `v` is not a JSON number + * `toString(v)` -- returns `optional`, absence indicating `v` is not a JSON string + * `toValue(v)` -- returns `optional`, a variant type, for generic conversion, + absence indicating `v` is not a boolean, number, or string. Numbers should be converted to + unsigned integer, signed integer, or floating point, in descending preference. + + In addition, the type T must be move-constructable. And finally, `Convertible::Storage`, a typedef for + `std::aligned_storage_t`, must be large enough to satisfy the memory requirements for any of the + possible underlying types. (A static assert will fail if this is not the case.) + + `Convertible` itself is movable, but not copyable. A moved-from `Convertible` is in an invalid state; + you must not do anything with it except let it go out of scope. +*/ + +template +class ConversionTraits; + +class Convertible { +public: + template + Convertible(T&& value) : vtable(vtableForType>()) { + static_assert(sizeof(Storage) >= sizeof(std::decay_t), "Storage must be large enough to hold value type"); + new (static_cast(&storage)) std::decay_t(std::forward(value)); + } + + Convertible(Convertible&& v) + : vtable(v.vtable) + { + if (vtable) { + vtable->move(std::move(v.storage), this->storage); + } + } + + ~Convertible() { + if (vtable) { + vtable->destroy(storage); + } + } + + Convertible& operator=(Convertible&& v) { + if (vtable) { + vtable->destroy(storage); + } + vtable = v.vtable; + if (vtable) { + vtable->move(std::move(v.storage), this->storage); + } + v.vtable = nullptr; + return *this; + } + + Convertible() = delete; + Convertible(const Convertible&) = delete; + Convertible& operator=(const Convertible&) = delete; + + friend inline bool isUndefined(const Convertible& v) { + assert(v.vtable); + return v.vtable->isUndefined(v.storage); + } + + friend inline bool isArray(const Convertible& v) { + assert(v.vtable); + return v.vtable->isArray(v.storage); + } + + friend inline std::size_t arrayLength(const Convertible& v) { + assert(v.vtable); + return v.vtable->arrayLength(v.storage); + } + + friend inline Convertible arrayMember(const Convertible& v, std::size_t i) { + assert(v.vtable); + return v.vtable->arrayMember(v.storage, i); + } + + friend inline bool isObject(const Convertible& v) { + assert(v.vtable); + return v.vtable->isObject(v.storage); + } + + friend inline optional objectMember(const Convertible& v, const char * name) { + assert(v.vtable); + return v.vtable->objectMember(v.storage, name); + } + + friend inline optional eachMember(const Convertible& v, const std::function (const std::string&, const Convertible&)>& fn) { + assert(v.vtable); + return v.vtable->eachMember(v.storage, fn); + } + + friend inline optional toBool(const Convertible& v) { + assert(v.vtable); + return v.vtable->toBool(v.storage); + } + + friend inline optional toNumber(const Convertible& v) { + assert(v.vtable); + return v.vtable->toNumber(v.storage); + } + + friend inline optional toDouble(const Convertible& v) { + assert(v.vtable); + return v.vtable->toDouble(v.storage); + } + + friend inline optional toString(const Convertible& v) { + assert(v.vtable); + return v.vtable->toString(v.storage); + } + + friend inline optional toValue(const Convertible& v) { + assert(v.vtable); + return v.vtable->toValue(v.storage); + } + + friend inline optional toGeoJSON(const Convertible& v, Error& error) { + assert(v.vtable); + return v.vtable->toGeoJSON(v.storage, error); + } + +private: +#if __ANDROID__ + // Android: JSValue* or mbgl::android::Value + using Storage = std::aligned_storage_t<32, 8>; +#elif __QT__ + // Qt: JSValue* or QVariant + using Storage = std::aligned_storage_t<32, 8>; +#else + // Node: JSValue* or v8::Local + // iOS/macOS: JSValue* or id + using Storage = std::aligned_storage_t<8, 8>; +#endif + + struct VTable { + void (*move) (Storage&& src, Storage& dest); + void (*destroy) (Storage&); + + bool (*isUndefined) (const Storage&); + + bool (*isArray) (const Storage&); + std::size_t (*arrayLength) (const Storage&); + Convertible (*arrayMember) (const Storage&, std::size_t); + + bool (*isObject) (const Storage&); + optional (*objectMember) (const Storage&, const char *); + optional (*eachMember) (const Storage&, const std::function (const std::string&, const Convertible&)>&); + + optional (*toBool) (const Storage&); + optional (*toNumber) (const Storage&); + optional (*toDouble) (const Storage&); + optional (*toString) (const Storage&); + optional (*toValue) (const Storage&); + + // https://github.com/mapbox/mapbox-gl-native/issues/5623 + optional (*toGeoJSON) (const Storage&, Error&); + }; + + // Extracted this function from the table below to work around a GCC bug with differing + // visibility settings for capturing lambdas: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947 + template + static auto vtableEachMember(const Storage& s, const std::function(const std::string&, const Convertible&)>& fn) { + return ConversionTraits::eachMember(reinterpret_cast(s), [&](const std::string& k, T&& v) { + return fn(k, Convertible(std::move(v))); + }); + } + + template + static VTable* vtableForType() { + using Traits = ConversionTraits; + static VTable vtable = { + [] (Storage&& src, Storage& dest) { + auto srcValue = reinterpret_cast(src); + new (static_cast(&dest)) T(std::move(srcValue)); + srcValue.~T(); + }, + [] (Storage& s) { + reinterpret_cast(s).~T(); + }, + [] (const Storage& s) { + return Traits::isUndefined(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::isArray(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::arrayLength(reinterpret_cast(s)); + }, + [] (const Storage& s, std::size_t i) { + return Convertible(Traits::arrayMember(reinterpret_cast(s), i)); + }, + [] (const Storage& s) { + return Traits::isObject(reinterpret_cast(s)); + }, + [] (const Storage& s, const char * key) { + optional member = Traits::objectMember(reinterpret_cast(s), key); + if (member) { + return optional(Convertible(std::move(*member))); + } else { + return optional(); + } + }, + vtableEachMember, + [] (const Storage& s) { + return Traits::toBool(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::toNumber(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::toDouble(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::toString(reinterpret_cast(s)); + }, + [] (const Storage& s) { + return Traits::toValue(reinterpret_cast(s)); + }, + [] (const Storage& s, Error& err) { + return Traits::toGeoJSON(reinterpret_cast(s), err); + } + }; + return &vtable; + } + + VTable* vtable; + Storage storage; +}; + +template +optional convert(const Convertible& value, Error& error, Args&&...args) { + return Converter()(value, error, std::forward(args)...); +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/include/mbgl/style/expression/assertion.hpp b/include/mbgl/style/expression/assertion.hpp index 90da16b068..239cdf2ea6 100644 --- a/include/mbgl/style/expression/assertion.hpp +++ b/include/mbgl/style/expression/assertion.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include #include diff --git a/include/mbgl/style/expression/case.hpp b/include/mbgl/style/expression/case.hpp index 02dc3bc4c2..7cd007d3c7 100644 --- a/include/mbgl/style/expression/case.hpp +++ b/include/mbgl/style/expression/case.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include #include diff --git a/include/mbgl/style/expression/coalesce.hpp b/include/mbgl/style/expression/coalesce.hpp index cd60cee02e..c4216f234f 100644 --- a/include/mbgl/style/expression/coalesce.hpp +++ b/include/mbgl/style/expression/coalesce.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include #include diff --git a/include/mbgl/style/expression/compound_expression.hpp b/include/mbgl/style/expression/compound_expression.hpp index ef10dadb55..b54720a258 100644 --- a/include/mbgl/style/expression/compound_expression.hpp +++ b/include/mbgl/style/expression/compound_expression.hpp @@ -1,10 +1,10 @@ #pragma once #include -#include #include #include #include +#include #include #include diff --git a/include/mbgl/style/expression/parsing_context.hpp b/include/mbgl/style/expression/parsing_context.hpp index c19974a4f7..66014e33d4 100644 --- a/include/mbgl/style/expression/parsing_context.hpp +++ b/include/mbgl/style/expression/parsing_context.hpp @@ -7,6 +7,7 @@ #include #include +#include #include #include #include diff --git a/include/mbgl/style/layer.hpp b/include/mbgl/style/layer.hpp index e0f71d2689..3b7969ea79 100644 --- a/include/mbgl/style/layer.hpp +++ b/include/mbgl/style/layer.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/platform/android/config.cmake b/platform/android/config.cmake index e76a447c88..be9d95ef0a 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -345,6 +345,11 @@ add_library(example-custom-layer SHARED platform/android/src/example_custom_layer.cpp ) +target_include_directories(example-custom-layer + PRIVATE include +) + target_link_libraries(example-custom-layer - PRIVATE mbgl-core + PRIVATE -llog + PRIVATE -lGLESv2 ) diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp index 8da44c10cb..8c76332b39 100755 --- a/platform/android/src/native_map_view.cpp +++ b/platform/android/src/native_map_view.cpp @@ -30,8 +30,8 @@ // Java -> C++ conversion #include "style/android_conversion.hpp" -#include #include +#include // C++ -> Java conversion #include "conversion/conversion.hpp" diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp index 510a9f8444..8559720b2f 100644 --- a/platform/android/src/style/android_conversion.hpp +++ b/platform/android/src/style/android_conversion.hpp @@ -5,8 +5,8 @@ #include #include #include -#include #include +#include #include diff --git a/platform/android/src/style/conversion/filter.hpp b/platform/android/src/style/conversion/filter.hpp index c154e88e7c..241c98713a 100644 --- a/platform/android/src/style/conversion/filter.hpp +++ b/platform/android/src/style/conversion/filter.hpp @@ -1,8 +1,8 @@ #pragma once #include "../android_conversion.hpp" -#include #include +#include #include diff --git a/platform/android/src/style/conversion/latlngquad.hpp b/platform/android/src/style/conversion/latlngquad.hpp index 9d1a83e164..9588336855 100644 --- a/platform/android/src/style/conversion/latlngquad.hpp +++ b/platform/android/src/style/conversion/latlngquad.hpp @@ -1,8 +1,8 @@ #pragma once #include -#include #include +#include #include namespace mbgl { diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp index 92c1182a63..d6bf86639c 100644 --- a/platform/android/src/style/conversion/url_or_tileset.hpp +++ b/platform/android/src/style/conversion/url_or_tileset.hpp @@ -4,8 +4,8 @@ #include #include -#include #include +#include #include diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp index c3ae9e40cd..6c08893411 100644 --- a/platform/android/src/style/layers/layer.cpp +++ b/platform/android/src/style/layers/layer.cpp @@ -18,10 +18,10 @@ #include // Java -> C++ conversion -#include #include #include #include +#include // C++ -> Java conversion #include "../conversion/property_value.hpp" diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp index 6d9ab9e22c..14067503f1 100644 --- a/platform/android/src/style/sources/geojson_source.cpp +++ b/platform/android/src/style/sources/geojson_source.cpp @@ -5,9 +5,9 @@ // Java -> C++ conversion #include "../android_conversion.hpp" #include "../conversion/filter.hpp" -#include #include #include +#include // C++ -> Java conversion #include "../../conversion/conversion.hpp" diff --git a/platform/android/src/style/sources/image_source.cpp b/platform/android/src/style/sources/image_source.cpp index 249387ea51..278564485d 100644 --- a/platform/android/src/style/sources/image_source.cpp +++ b/platform/android/src/style/sources/image_source.cpp @@ -5,7 +5,7 @@ // C++ -> Java conversion #include "../../conversion/conversion.hpp" -#include +#include #include #include "../../bitmap.hpp" diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp index 8f14ebc43e..d2e2426c0b 100644 --- a/platform/android/src/style/sources/source.cpp +++ b/platform/android/src/style/sources/source.cpp @@ -7,8 +7,8 @@ #include // Java -> C++ conversion -#include #include +#include // C++ -> Java conversion #include "../conversion/property_value.hpp" diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h index 92a6720e6a..9057ed7824 100644 --- a/platform/darwin/src/MGLConversion.h +++ b/platform/darwin/src/MGLConversion.h @@ -1,4 +1,4 @@ -#include +#include NS_ASSUME_NONNULL_BEGIN diff --git a/platform/node/src/node_conversion.hpp b/platform/node/src/node_conversion.hpp index 7c5bbf4386..ea6652c5e2 100644 --- a/platform/node/src/node_conversion.hpp +++ b/platform/node/src/node_conversion.hpp @@ -8,8 +8,8 @@ #include #include -#include #include +#include namespace mbgl { namespace style { diff --git a/platform/node/src/node_expression.hpp b/platform/node/src/node_expression.hpp index 05af217bde..a53f8c18db 100644 --- a/platform/node/src/node_expression.hpp +++ b/platform/node/src/node_expression.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include #include diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp index 480174810c..d584012830 100644 --- a/platform/qt/src/qmapboxgl.cpp +++ b/platform/qt/src/qmapboxgl.cpp @@ -13,11 +13,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include diff --git a/platform/qt/src/qt_conversion.hpp b/platform/qt/src/qt_conversion.hpp index 19b0cb54fc..99a262be54 100644 --- a/platform/qt/src/qt_conversion.hpp +++ b/platform/qt/src/qt_conversion.hpp @@ -1,7 +1,7 @@ #pragma once -#include #include +#include #include #include diff --git a/src/mbgl/style/conversion/color_ramp_property_value.cpp b/src/mbgl/style/conversion/color_ramp_property_value.cpp index f29438b6a2..0da16c67ee 100644 --- a/src/mbgl/style/conversion/color_ramp_property_value.cpp +++ b/src/mbgl/style/conversion/color_ramp_property_value.cpp @@ -1,6 +1,6 @@ #include -#include #include +#include #include #include #include diff --git a/src/mbgl/style/conversion/constant.cpp b/src/mbgl/style/conversion/constant.cpp index d432b5f051..de4ab22269 100644 --- a/src/mbgl/style/conversion/constant.cpp +++ b/src/mbgl/style/conversion/constant.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { @@ -31,6 +32,38 @@ optional Converter::operator()(const Convertible& valu return *converted; } +template +optional Converter::value>>::operator()(const Convertible& value, Error& error) const { + optional string = toString(value); + if (!string) { + error.message = "value must be a string"; + return nullopt; + } + + const auto result = Enum::toEnum(*string); + if (!result) { + error.message = "value must be a valid enumeration value"; + return nullopt; + } + + return *result; +} + +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; +template optional Converter::operator()(const Convertible&, Error&) const; + optional Converter::operator()(const Convertible& value, Error& error) const { optional string = toString(value); if (!string) { @@ -47,6 +80,29 @@ optional Converter::operator()(const Convertible& value, Error& er return *color; } +template +optional> Converter>::operator()(const Convertible& value, Error& error) const { + if (!isArray(value) || arrayLength(value) != N) { + error.message = "value must be an array of " + util::toString(N) + " numbers"; + return nullopt; + } + + std::array result; + for (size_t i = 0; i < N; i++) { + optional n = toNumber(arrayMember(value, i)); + if (!n) { + error.message = "value must be an array of " + util::toString(N) + " numbers"; + return nullopt; + } + result[i] = *n; + } + return result; +} + +template optional> Converter>::operator()(const Convertible&, Error&) const; +template optional> Converter>::operator()(const Convertible&, Error&) const; +template optional> Converter>::operator()(const Convertible&, Error&) const; + optional> Converter>::operator()(const Convertible& value, Error& error) const { if (!isArray(value)) { error.message = "value must be an array"; diff --git a/src/mbgl/style/conversion/coordinate.cpp b/src/mbgl/style/conversion/coordinate.cpp index 20abd45e26..ee03bffb30 100644 --- a/src/mbgl/style/conversion/coordinate.cpp +++ b/src/mbgl/style/conversion/coordinate.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/custom_geometry_source_options.cpp b/src/mbgl/style/conversion/custom_geometry_source_options.cpp index 8983f9f479..491509c28f 100644 --- a/src/mbgl/style/conversion/custom_geometry_source_options.cpp +++ b/src/mbgl/style/conversion/custom_geometry_source_options.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/filter.cpp b/src/mbgl/style/conversion/filter.cpp index 5114c61778..fc25ab0b0d 100644 --- a/src/mbgl/style/conversion/filter.cpp +++ b/src/mbgl/style/conversion/filter.cpp @@ -1,10 +1,11 @@ #include +#include #include -#include #include #include #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/function.cpp b/src/mbgl/style/conversion/function.cpp index 1cc49e483a..6aadaad3b3 100644 --- a/src/mbgl/style/conversion/function.cpp +++ b/src/mbgl/style/conversion/function.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include #include @@ -70,6 +72,72 @@ std::unique_ptr convertTokenStringToExpression(const std::string& so } } +template +optional> convertFunctionToExpression(const Convertible& value, Error& error, bool convertTokens) { + auto expression = convertFunctionToExpression(expression::valueTypeToExpressionType(), value, error, convertTokens); + if (!expression) { + return nullopt; + } + + optional defaultValue; + + auto defaultValueValue = objectMember(value, "default"); + if (defaultValueValue) { + defaultValue = convert(*defaultValueValue, error); + if (!defaultValue) { + error.message = R"(wrong type for "default": )" + error.message; + return nullopt; + } + } + + return PropertyExpression(std::move(*expression), defaultValue); +} + +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional>> + convertFunctionToExpression>(const Convertible&, Error&, bool); +template optional>> + convertFunctionToExpression>(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional>> + convertFunctionToExpression>(const Convertible&, Error&, bool); +template optional>> + convertFunctionToExpression>(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); +template optional> + convertFunctionToExpression(const Convertible&, Error&, bool); + // Ad-hoc Converters for double and int64_t. We should replace float with double wholesale, // and promote the int64_t Converter to general use (and it should check that the input is // an integer). diff --git a/src/mbgl/style/conversion/geojson.cpp b/src/mbgl/style/conversion/geojson.cpp index e39a1a80eb..c2d34c5491 100644 --- a/src/mbgl/style/conversion/geojson.cpp +++ b/src/mbgl/style/conversion/geojson.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/geojson_options.cpp b/src/mbgl/style/conversion/geojson_options.cpp index 77340e5f1d..11bd7cc507 100644 --- a/src/mbgl/style/conversion/geojson_options.cpp +++ b/src/mbgl/style/conversion/geojson_options.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/get_json_type.cpp b/src/mbgl/style/conversion/get_json_type.cpp index cd3b4608b1..2e9d35a957 100644 --- a/src/mbgl/style/conversion/get_json_type.cpp +++ b/src/mbgl/style/conversion/get_json_type.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/conversion/json.hpp b/src/mbgl/style/conversion/json.hpp index a823f6d383..3a7bf2b557 100644 --- a/src/mbgl/style/conversion/json.hpp +++ b/src/mbgl/style/conversion/json.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include diff --git a/src/mbgl/style/conversion/layer.cpp b/src/mbgl/style/conversion/layer.cpp index d36ca494da..085d7ae4c6 100644 --- a/src/mbgl/style/conversion/layer.cpp +++ b/src/mbgl/style/conversion/layer.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include diff --git a/src/mbgl/style/conversion/light.cpp b/src/mbgl/style/conversion/light.cpp index 7b96c89a1c..e8723216ee 100644 --- a/src/mbgl/style/conversion/light.cpp +++ b/src/mbgl/style/conversion/light.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/conversion/position.cpp b/src/mbgl/style/conversion/position.cpp index a19f57bff3..df6c868ee8 100644 --- a/src/mbgl/style/conversion/position.cpp +++ b/src/mbgl/style/conversion/position.cpp @@ -1,5 +1,6 @@ #include #include +#include #include diff --git a/src/mbgl/style/conversion/property_value.cpp b/src/mbgl/style/conversion/property_value.cpp new file mode 100644 index 0000000000..8a93c24767 --- /dev/null +++ b/src/mbgl/style/conversion/property_value.cpp @@ -0,0 +1,83 @@ +#include +#include +#include + +namespace mbgl { +namespace style { +namespace conversion { + +template +optional> Converter>::operator()(const Convertible& value, Error& error, bool allowDataExpressions, bool convertTokens) const { + using namespace mbgl::style::expression; + + if (isUndefined(value)) { + return PropertyValue(); + } + + optional> expression; + + if (isExpression(value)) { + ParsingContext ctx(valueTypeToExpressionType()); + ParseResult parsed = ctx.parseLayerPropertyExpression(value); + if (!parsed) { + error.message = ctx.getCombinedErrors(); + return nullopt; + } + expression = PropertyExpression(std::move(*parsed)); + } else if (isObject(value)) { + expression = convertFunctionToExpression(value, error, convertTokens); + } else { + optional constant = convert(value, error); + if (!constant) { + return nullopt; + } + return convertTokens ? maybeConvertTokens(*constant) : PropertyValue(*constant); + } + + if (!expression) { + return nullopt; + } else if (!allowDataExpressions && !(*expression).isFeatureConstant()) { + error.message = "data expressions not supported"; + return nullopt; + } else if (!(*expression).isFeatureConstant() || !(*expression).isZoomConstant()) { + return { std::move(*expression) }; + } else if ((*expression).getExpression().getKind() == Kind::Literal) { + optional constant = fromExpressionValue( + static_cast((*expression).getExpression()).getValue()); + if (!constant) { + return nullopt; + } + return PropertyValue(*constant); + } else { + assert(false); + error.message = "expected a literal expression"; + return nullopt; + } +} + +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional>> Converter>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional>> Converter>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional>> Converter>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional>> Converter>>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; +template optional> Converter>::operator()(conversion::Convertible const&, conversion::Error&, bool, bool) const; + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/src/mbgl/style/conversion/source.cpp b/src/mbgl/style/conversion/source.cpp index ce0cb24ce0..5ecbd3b474 100644 --- a/src/mbgl/style/conversion/source.cpp +++ b/src/mbgl/style/conversion/source.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/src/mbgl/style/conversion/tileset.cpp b/src/mbgl/style/conversion/tileset.cpp index b566af0a18..40575838ea 100644 --- a/src/mbgl/style/conversion/tileset.cpp +++ b/src/mbgl/style/conversion/tileset.cpp @@ -1,4 +1,5 @@ #include +#include #include #include diff --git a/src/mbgl/style/conversion/transition_options.cpp b/src/mbgl/style/conversion/transition_options.cpp index 924032a0c0..6e39dca24f 100644 --- a/src/mbgl/style/conversion/transition_options.cpp +++ b/src/mbgl/style/conversion/transition_options.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/expression/array_assertion.cpp b/src/mbgl/style/expression/array_assertion.cpp index 4049301b0b..9df586bdc3 100644 --- a/src/mbgl/style/expression/array_assertion.cpp +++ b/src/mbgl/style/expression/array_assertion.cpp @@ -1,5 +1,6 @@ #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/assertion.cpp b/src/mbgl/style/expression/assertion.cpp index 2434d7a2f8..7e93003ac3 100644 --- a/src/mbgl/style/expression/assertion.cpp +++ b/src/mbgl/style/expression/assertion.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/expression/at.cpp b/src/mbgl/style/expression/at.cpp index 725e5ddb51..648f247830 100644 --- a/src/mbgl/style/expression/at.cpp +++ b/src/mbgl/style/expression/at.cpp @@ -1,4 +1,5 @@ #include +#include #include diff --git a/src/mbgl/style/expression/boolean_operator.cpp b/src/mbgl/style/expression/boolean_operator.cpp index 68e96129aa..fa472270ce 100644 --- a/src/mbgl/style/expression/boolean_operator.cpp +++ b/src/mbgl/style/expression/boolean_operator.cpp @@ -1,4 +1,5 @@ #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/expression/case.cpp b/src/mbgl/style/expression/case.cpp index e885c0ce6b..0c2ff0d7cd 100644 --- a/src/mbgl/style/expression/case.cpp +++ b/src/mbgl/style/expression/case.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/coalesce.cpp b/src/mbgl/style/expression/coalesce.cpp index 0090f16009..cdbf452f7f 100644 --- a/src/mbgl/style/expression/coalesce.cpp +++ b/src/mbgl/style/expression/coalesce.cpp @@ -1,5 +1,6 @@ #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/expression/coercion.cpp b/src/mbgl/style/expression/coercion.cpp index f5a4d70f66..486658ddda 100644 --- a/src/mbgl/style/expression/coercion.cpp +++ b/src/mbgl/style/expression/coercion.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/collator_expression.cpp b/src/mbgl/style/expression/collator_expression.cpp index b27eedbc76..07346633a2 100644 --- a/src/mbgl/style/expression/collator_expression.cpp +++ b/src/mbgl/style/expression/collator_expression.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/comparison.cpp b/src/mbgl/style/expression/comparison.cpp index 6179c3ce88..cdcdb5d59c 100644 --- a/src/mbgl/style/expression/comparison.cpp +++ b/src/mbgl/style/expression/comparison.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp index 4c476a3749..f8c2376cb3 100644 --- a/src/mbgl/style/expression/compound_expression.cpp +++ b/src/mbgl/style/expression/compound_expression.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include diff --git a/src/mbgl/style/expression/interpolate.cpp b/src/mbgl/style/expression/interpolate.cpp index 54fbc6e1d7..8725e9e86d 100644 --- a/src/mbgl/style/expression/interpolate.cpp +++ b/src/mbgl/style/expression/interpolate.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/is_expression.cpp b/src/mbgl/style/expression/is_expression.cpp index 77212f6a1e..acf074c25b 100644 --- a/src/mbgl/style/expression/is_expression.cpp +++ b/src/mbgl/style/expression/is_expression.cpp @@ -1,8 +1,7 @@ #include #include #include - -#include +#include #include diff --git a/src/mbgl/style/expression/length.cpp b/src/mbgl/style/expression/length.cpp index ad7a15675a..f1b58d7952 100644 --- a/src/mbgl/style/expression/length.cpp +++ b/src/mbgl/style/expression/length.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/let.cpp b/src/mbgl/style/expression/let.cpp index 242a995b0b..592ceed58a 100644 --- a/src/mbgl/style/expression/let.cpp +++ b/src/mbgl/style/expression/let.cpp @@ -1,5 +1,6 @@ #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/literal.cpp b/src/mbgl/style/expression/literal.cpp index 345a52de9b..c69341d298 100644 --- a/src/mbgl/style/expression/literal.cpp +++ b/src/mbgl/style/expression/literal.cpp @@ -1,4 +1,5 @@ #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/match.cpp b/src/mbgl/style/expression/match.cpp index 4b4984811f..0f05001a97 100644 --- a/src/mbgl/style/expression/match.cpp +++ b/src/mbgl/style/expression/match.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/expression/parsing_context.cpp b/src/mbgl/style/expression/parsing_context.cpp index b3f6b1acee..ef17caed33 100644 --- a/src/mbgl/style/expression/parsing_context.cpp +++ b/src/mbgl/style/expression/parsing_context.cpp @@ -24,6 +24,7 @@ #include #include +#include #include diff --git a/src/mbgl/style/expression/step.cpp b/src/mbgl/style/expression/step.cpp index a1ca0a702e..39b04c04a0 100644 --- a/src/mbgl/style/expression/step.cpp +++ b/src/mbgl/style/expression/step.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include diff --git a/src/mbgl/style/layer.cpp b/src/mbgl/style/layer.cpp index 31ff5bf47a..e08b71e6b3 100644 --- a/src/mbgl/style/layer.cpp +++ b/src/mbgl/style/layer.cpp @@ -2,6 +2,7 @@ #include #include #include +#include namespace mbgl { namespace style { diff --git a/src/mbgl/style/layers/background_layer.cpp b/src/mbgl/style/layers/background_layer.cpp index e47b41daa8..f2e85ce7e7 100644 --- a/src/mbgl/style/layers/background_layer.cpp +++ b/src/mbgl/style/layers/background_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/circle_layer.cpp b/src/mbgl/style/layers/circle_layer.cpp index 1dae77547b..c301a83c9e 100644 --- a/src/mbgl/style/layers/circle_layer.cpp +++ b/src/mbgl/style/layers/circle_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/fill_extrusion_layer.cpp b/src/mbgl/style/layers/fill_extrusion_layer.cpp index db90415daa..74cdb9abe6 100644 --- a/src/mbgl/style/layers/fill_extrusion_layer.cpp +++ b/src/mbgl/style/layers/fill_extrusion_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/fill_layer.cpp b/src/mbgl/style/layers/fill_layer.cpp index 2da131b6b2..bdfc000736 100644 --- a/src/mbgl/style/layers/fill_layer.cpp +++ b/src/mbgl/style/layers/fill_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/heatmap_layer.cpp b/src/mbgl/style/layers/heatmap_layer.cpp index df00558135..a90aab7009 100644 --- a/src/mbgl/style/layers/heatmap_layer.cpp +++ b/src/mbgl/style/layers/heatmap_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/hillshade_layer.cpp b/src/mbgl/style/layers/hillshade_layer.cpp index fb96c681cc..aed49f6441 100644 --- a/src/mbgl/style/layers/hillshade_layer.cpp +++ b/src/mbgl/style/layers/hillshade_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/layer.cpp.ejs b/src/mbgl/style/layers/layer.cpp.ejs index 4e80a7bf74..b5fb1a97a4 100644 --- a/src/mbgl/style/layers/layer.cpp.ejs +++ b/src/mbgl/style/layers/layer.cpp.ejs @@ -8,12 +8,12 @@ #include _layer.hpp> #include _layer_impl.hpp> #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/line_layer.cpp b/src/mbgl/style/layers/line_layer.cpp index c744adad95..1b84c2d73e 100644 --- a/src/mbgl/style/layers/line_layer.cpp +++ b/src/mbgl/style/layers/line_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/raster_layer.cpp b/src/mbgl/style/layers/raster_layer.cpp index 45d3240833..7bd01c92e1 100644 --- a/src/mbgl/style/layers/raster_layer.cpp +++ b/src/mbgl/style/layers/raster_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/layers/symbol_layer.cpp b/src/mbgl/style/layers/symbol_layer.cpp index 48af6b13aa..4ea138a7f5 100644 --- a/src/mbgl/style/layers/symbol_layer.cpp +++ b/src/mbgl/style/layers/symbol_layer.cpp @@ -3,12 +3,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include namespace mbgl { diff --git a/src/mbgl/style/parser.cpp b/src/mbgl/style/parser.cpp index 0a90919f0b..114a666f08 100644 --- a/src/mbgl/style/parser.cpp +++ b/src/mbgl/style/parser.cpp @@ -1,12 +1,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include diff --git a/src/mbgl/style/rapidjson_conversion.hpp b/src/mbgl/style/rapidjson_conversion.hpp index 79bd9c928b..be335101e9 100644 --- a/src/mbgl/style/rapidjson_conversion.hpp +++ b/src/mbgl/style/rapidjson_conversion.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #include #include diff --git a/test/style/conversion/light.test.cpp b/test/style/conversion/light.test.cpp index f111e40ff3..092c476277 100644 --- a/test/style/conversion/light.test.cpp +++ b/test/style/conversion/light.test.cpp @@ -1,9 +1,9 @@ #include -#include #include #include #include +#include #include #include #include diff --git a/test/style/expression/expression.test.cpp b/test/style/expression/expression.test.cpp index 0b46facf42..982a769b93 100644 --- a/test/style/expression/expression.test.cpp +++ b/test/style/expression/expression.test.cpp @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include #include -- cgit v1.2.1 From ff077e9ea9bd521e92ec071409b734d8da15d4fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Thu, 16 Aug 2018 15:37:38 +0200 Subject: [android] obtain paths to file directories on a worker thread --- .../src/main/java/com/mapbox/mapboxsdk/Mapbox.java | 5 + .../mapboxsdk/maps/renderer/MapRenderer.java | 2 +- .../mapbox/mapboxsdk/offline/OfflineManager.java | 2 +- .../mapboxsdk/snapshotter/MapSnapshotter.java | 2 +- .../com/mapbox/mapboxsdk/storage/FileSource.java | 104 ++++++++++++++++++++- 5 files changed, 107 insertions(+), 8 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java index 6897cf66df..8c9cd362d3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java @@ -11,6 +11,9 @@ import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.exceptions.MapboxConfigurationException; import com.mapbox.mapboxsdk.maps.Telemetry; import com.mapbox.mapboxsdk.net.ConnectivityReceiver; +import com.mapbox.mapboxsdk.storage.FileSource; +import com.mapbox.mapboxsdk.utils.ThreadUtils; + import timber.log.Timber; /** @@ -42,8 +45,10 @@ public final class Mapbox { */ @UiThread public static synchronized Mapbox getInstance(@NonNull Context context, @Nullable String accessToken) { + ThreadUtils.checkThread("Mapbox"); if (INSTANCE == null) { Context appContext = context.getApplicationContext(); + FileSource.initializeFileDirsPaths(appContext); INSTANCE = new Mapbox(appContext, accessToken); if (isAccessTokenValid(accessToken)) { initializeTelemetry(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java index 1129b8000e..492f653dae 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java @@ -28,7 +28,7 @@ public abstract class MapRenderer implements MapRendererScheduler { public MapRenderer(Context context, String localIdeographFontFamily) { FileSource fileSource = FileSource.getInstance(context); float pixelRatio = context.getResources().getDisplayMetrics().density; - String programCacheDir = context.getCacheDir().getAbsolutePath(); + String programCacheDir = FileSource.getInternalCachePath(context); // Initialise native peer nativeInitialize(this, fileSource, pixelRatio, programCacheDir, localIdeographFontFamily); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java index dbf425986d..f6dd7ff7a1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java @@ -109,7 +109,7 @@ public class OfflineManager { @Override public void run() { try { - String path = context.getCacheDir().getAbsolutePath() + File.separator + "mbgl-cache.db"; + String path = FileSource.getInternalCachePath(context) + File.separator + "mbgl-cache.db"; File file = new File(path); if (file.exists()) { file.delete(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java index 2aea565d8b..354a8fb6cd 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java @@ -217,7 +217,7 @@ public class MapSnapshotter { checkThread(); this.context = context.getApplicationContext(); FileSource fileSource = FileSource.getInstance(context); - String programCacheDir = context.getCacheDir().getAbsolutePath(); + String programCacheDir = FileSource.getInternalCachePath(context); nativeInitialize(this, fileSource, options.pixelRatio, options.width, options.height, options.styleUrl, options.styleJson, options.region, options.cameraPosition, diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java index c8d02c05d9..495e425976 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java @@ -4,6 +4,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; +import android.os.AsyncTask; import android.os.Environment; import android.support.annotation.Keep; import android.support.annotation.NonNull; @@ -11,6 +12,10 @@ import android.support.annotation.UiThread; import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.utils.ThreadUtils; + +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; import timber.log.Timber; @@ -20,6 +25,11 @@ import timber.log.Timber; */ public class FileSource { + private static String resourcesCachePath; + private static String internalCachePath; + private static final Lock resourcesCachePathLoaderLock = new ReentrantLock(); + private static final Lock internalCachePathLoaderLock = new ReentrantLock(); + /** * This callback allows implementors to transform URLs before they are requested * from the internet. This can be used add or remove custom parameters, or reroute @@ -51,19 +61,20 @@ public class FileSource { @UiThread public static synchronized FileSource getInstance(Context context) { if (INSTANCE == null) { - String cachePath = getCachePath(context); - INSTANCE = new FileSource(cachePath, context.getResources().getAssets()); + INSTANCE = new FileSource(getResourcesCachePath(context), context.getResources().getAssets()); } return INSTANCE; } /** - * Get the cache path for a context. + * Get files directory path for a context. * - * @param context the context to derive the cache path from - * @return the cache path + * @param context the context to derive the files directory path from + * @return the files directory path + * @deprecated Use {@link #getResourcesCachePath(Context)} instead. */ + @Deprecated public static String getCachePath(Context context) { // Default value boolean setStorageExternal = MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL; @@ -122,6 +133,89 @@ public class FileSource { return false; } + /** + * Initializes file directories paths. + * + * @param context the context to derive paths from + */ + @UiThread + public static void initializeFileDirsPaths(Context context) { + ThreadUtils.checkThread("FileSource"); + lockPathLoaders(); + if (resourcesCachePath == null || internalCachePath == null) { + new FileDirsPathsTask().execute(context); + } + } + + private static class FileDirsPathsTask extends AsyncTask { + + @Override + protected void onCancelled() { + unlockPathLoaders(); + } + + @Override + protected String[] doInBackground(Context... contexts) { + return new String[] { + getCachePath(contexts[0]), + contexts[0].getCacheDir().getAbsolutePath() + }; + } + + @Override + protected void onPostExecute(String[] paths) { + resourcesCachePath = paths[0]; + internalCachePath = paths[1]; + unlockPathLoaders(); + } + } + + /** + * Get files directory path for a context. + * + * @param context the context to derive the files directory path from + * @return the files directory path + */ + public static String getResourcesCachePath(Context context) { + resourcesCachePathLoaderLock.lock(); + try { + if (resourcesCachePath == null) { + resourcesCachePath = getCachePath(context); + } + return resourcesCachePath; + } finally { + resourcesCachePathLoaderLock.unlock(); + } + } + + /** + * Get internal cache path for a context. + * + * @param context the context to derive the internal cache path from + * @return the internal cache path + */ + public static String getInternalCachePath(Context context) { + internalCachePathLoaderLock.lock(); + try { + if (internalCachePath == null) { + internalCachePath = context.getCacheDir().getAbsolutePath(); + } + return internalCachePath; + } finally { + internalCachePathLoaderLock.unlock(); + } + } + + private static void lockPathLoaders() { + internalCachePathLoaderLock.lock(); + resourcesCachePathLoaderLock.lock(); + } + + private static void unlockPathLoaders() { + resourcesCachePathLoaderLock.unlock(); + internalCachePathLoaderLock.unlock(); + } + @Keep private long nativePtr; -- cgit v1.2.1 From 036a75037ab2d7d015fedb4896c8f17b37574c6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 20 Aug 2018 12:31:35 +0200 Subject: [build] also generate debugging symbols for Release builds in Xcode --- cmake/mbgl.cmake | 3 +++ 1 file changed, 3 insertions(+) diff --git a/cmake/mbgl.cmake b/cmake/mbgl.cmake index 9dd29375ef..2381c01205 100644 --- a/cmake/mbgl.cmake +++ b/cmake/mbgl.cmake @@ -191,6 +191,9 @@ function(initialize_xcode_cxx_build_settings target) # -flto set_xcode_property(${target} LLVM_LTO $<$,$>:YES>) + + # Make releases debuggable. + set_xcode_property(${target} GCC_GENERATE_DEBUGGING_SYMBOLS YES) endfunction() # CMake 3.1 does not have this yet. -- cgit v1.2.1 From 1b4398f7aab99f6604f56957209551fb7372a9d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 20 Aug 2018 12:46:57 +0200 Subject: [core] downgrade event severity for erroneous DDS rendering to Warning --- src/mbgl/renderer/render_layer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mbgl/renderer/render_layer.cpp b/src/mbgl/renderer/render_layer.cpp index a667d5837e..4cd033da75 100644 --- a/src/mbgl/renderer/render_layer.cpp +++ b/src/mbgl/renderer/render_layer.cpp @@ -91,7 +91,7 @@ void RenderLayer::checkRenderability(const PaintParameters& parameters, activeBindingCount - parameters.context.minimumRequiredVertexBindingCount); hasRenderFailures = true; } else if (activeBindingCount > parameters.context.minimumRequiredVertexBindingCount) { - Log::Error(Event::OpenGL, + Log::Warning(Event::OpenGL, "The layer '%s' uses more data-driven properties than some devices may support. " "Though it will render correctly on this device, it may have rendering errors " "on other devices. To ensure compatibility with all devices, use %d fewer " -- cgit v1.2.1 From bded6c65d59b6da9e7cd6d4787e5f707a62a8285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 20 Aug 2018 13:32:44 +0200 Subject: [build] use plain text files for file lists to simplify integration with other build systems --- CMakeLists.txt | 3 - cmake/benchmark-files.cmake | 28 -- cmake/benchmark-files.txt | 26 ++ cmake/benchmark.cmake | 5 +- cmake/core-files.cmake | 767 ---------------------------------- cmake/core-files.txt | 765 +++++++++++++++++++++++++++++++++ cmake/core.cmake | 5 +- cmake/files.cmake.ejs | 13 - cmake/files.txt.ejs | 10 + cmake/filesource-files.txt | 24 ++ cmake/filesource.cmake | 28 +- cmake/mbgl.cmake | 18 + cmake/test-files.cmake | 155 ------- cmake/test-files.txt | 153 +++++++ cmake/test.cmake | 9 +- platform/android/config.cmake | 237 +---------- platform/android/core-files.txt | 202 +++++++++ platform/android/filesource-files.txt | 28 ++ scripts/generate-cmake-files.js | 12 +- 19 files changed, 1243 insertions(+), 1245 deletions(-) delete mode 100644 cmake/benchmark-files.cmake create mode 100644 cmake/benchmark-files.txt delete mode 100644 cmake/core-files.cmake create mode 100644 cmake/core-files.txt delete mode 100644 cmake/files.cmake.ejs create mode 100644 cmake/files.txt.ejs create mode 100644 cmake/filesource-files.txt delete mode 100644 cmake/test-files.cmake create mode 100644 cmake/test-files.txt create mode 100644 platform/android/core-files.txt create mode 100644 platform/android/filesource-files.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index a02b4b9173..d524f2e754 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -146,16 +146,13 @@ if (COMMAND mbgl_filesource) include(cmake/filesource.cmake) endif() -include(cmake/core-files.cmake) include(cmake/core.cmake) if(COMMAND mbgl_platform_test) - include(cmake/test-files.cmake) include(cmake/test.cmake) endif() if(COMMAND mbgl_platform_benchmark) - include(cmake/benchmark-files.cmake) include(cmake/benchmark.cmake) endif() diff --git a/cmake/benchmark-files.cmake b/cmake/benchmark-files.cmake deleted file mode 100644 index 21547eb9c4..0000000000 --- a/cmake/benchmark-files.cmake +++ /dev/null @@ -1,28 +0,0 @@ -# This file is generated. Do not edit. Regenerate this with scripts/generate-cmake-files.js - -set(MBGL_BENCHMARK_FILES - # api - benchmark/api/query.benchmark.cpp - benchmark/api/render.benchmark.cpp - - # benchmark - benchmark/include/mbgl/benchmark.hpp - benchmark/src/main.cpp - benchmark/src/mbgl/benchmark/benchmark.cpp - benchmark/src/mbgl/benchmark/stub_geometry_tile_feature.hpp - - # function - benchmark/function/camera_function.benchmark.cpp - benchmark/function/composite_function.benchmark.cpp - benchmark/function/source_function.benchmark.cpp - - # parse - benchmark/parse/filter.benchmark.cpp - benchmark/parse/tile_mask.benchmark.cpp - benchmark/parse/vector_tile.benchmark.cpp - - # util - benchmark/util/dtoa.benchmark.cpp - benchmark/util/tilecover.benchmark.cpp - -) diff --git a/cmake/benchmark-files.txt b/cmake/benchmark-files.txt new file mode 100644 index 0000000000..16224e9cad --- /dev/null +++ b/cmake/benchmark-files.txt @@ -0,0 +1,26 @@ +# This file is generated. Do not edit. Regenerate this with scripts/generate-cmake-files.js + +# api +benchmark/api/query.benchmark.cpp +benchmark/api/render.benchmark.cpp + +# benchmark +benchmark/include/mbgl/benchmark.hpp +benchmark/src/main.cpp +benchmark/src/mbgl/benchmark/benchmark.cpp +benchmark/src/mbgl/benchmark/stub_geometry_tile_feature.hpp + +# function +benchmark/function/camera_function.benchmark.cpp +benchmark/function/composite_function.benchmark.cpp +benchmark/function/source_function.benchmark.cpp + +# parse +benchmark/parse/filter.benchmark.cpp +benchmark/parse/tile_mask.benchmark.cpp +benchmark/parse/vector_tile.benchmark.cpp + +# util +benchmark/util/dtoa.benchmark.cpp +benchmark/util/tilecover.benchmark.cpp + diff --git a/cmake/benchmark.cmake b/cmake/benchmark.cmake index 98fa4dac63..5cac8cc8b6 100644 --- a/cmake/benchmark.cmake +++ b/cmake/benchmark.cmake @@ -1,6 +1,5 @@ -add_executable(mbgl-benchmark - ${MBGL_BENCHMARK_FILES} -) +load_sources_list(MBGL_BENCHMARK_FILES cmake/benchmark-files.txt) +add_executable(mbgl-benchmark ${MBGL_BENCHMARK_FILES}) target_include_directories(mbgl-benchmark PRIVATE src diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake deleted file mode 100644 index 2d0bd003c7..0000000000 --- a/cmake/core-files.cmake +++ /dev/null @@ -1,767 +0,0 @@ -# This file is generated. Do not edit. Regenerate this with scripts/generate-cmake-files.js - -set(MBGL_CORE_FILES - # actor - include/mbgl/actor/actor.hpp - include/mbgl/actor/actor_ref.hpp - include/mbgl/actor/aspiring_actor.hpp - include/mbgl/actor/established_actor.hpp - include/mbgl/actor/mailbox.hpp - include/mbgl/actor/message.hpp - include/mbgl/actor/scheduler.hpp - src/mbgl/actor/mailbox.cpp - src/mbgl/actor/scheduler.cpp - - # algorithm - src/mbgl/algorithm/covered_by_children.hpp - src/mbgl/algorithm/generate_clip_ids.cpp - src/mbgl/algorithm/generate_clip_ids.hpp - src/mbgl/algorithm/generate_clip_ids_impl.hpp - src/mbgl/algorithm/update_renderables.hpp - src/mbgl/algorithm/update_tile_masks.hpp - - # annotation - include/mbgl/annotation/annotation.hpp - src/mbgl/annotation/annotation_manager.cpp - src/mbgl/annotation/annotation_manager.hpp - src/mbgl/annotation/annotation_source.cpp - src/mbgl/annotation/annotation_source.hpp - src/mbgl/annotation/annotation_tile.cpp - src/mbgl/annotation/annotation_tile.hpp - src/mbgl/annotation/fill_annotation_impl.cpp - src/mbgl/annotation/fill_annotation_impl.hpp - src/mbgl/annotation/line_annotation_impl.cpp - src/mbgl/annotation/line_annotation_impl.hpp - src/mbgl/annotation/render_annotation_source.cpp - src/mbgl/annotation/render_annotation_source.hpp - src/mbgl/annotation/shape_annotation_impl.cpp - src/mbgl/annotation/shape_annotation_impl.hpp - src/mbgl/annotation/symbol_annotation_impl.cpp - src/mbgl/annotation/symbol_annotation_impl.hpp - - # csscolorparser - src/csscolorparser/csscolorparser.cpp - src/csscolorparser/csscolorparser.hpp - - # geometry - src/mbgl/geometry/anchor.hpp - src/mbgl/geometry/debug_font_data.hpp - src/mbgl/geometry/dem_data.cpp - src/mbgl/geometry/dem_data.hpp - src/mbgl/geometry/feature_index.cpp - src/mbgl/geometry/feature_index.hpp - src/mbgl/geometry/line_atlas.cpp - src/mbgl/geometry/line_atlas.hpp - - # gl - src/mbgl/gl/attribute.cpp - src/mbgl/gl/attribute.hpp - src/mbgl/gl/color_mode.cpp - src/mbgl/gl/color_mode.hpp - src/mbgl/gl/context.cpp - src/mbgl/gl/context.hpp - src/mbgl/gl/debugging.cpp - src/mbgl/gl/debugging.hpp - src/mbgl/gl/debugging_extension.cpp - src/mbgl/gl/debugging_extension.hpp - src/mbgl/gl/depth_mode.cpp - src/mbgl/gl/depth_mode.hpp - src/mbgl/gl/draw_mode.hpp - src/mbgl/gl/extension.hpp - src/mbgl/gl/features.hpp - src/mbgl/gl/framebuffer.hpp - src/mbgl/gl/gl.cpp - src/mbgl/gl/gl.hpp - src/mbgl/gl/index_buffer.hpp - src/mbgl/gl/object.cpp - src/mbgl/gl/object.hpp - src/mbgl/gl/primitives.hpp - src/mbgl/gl/program.hpp - src/mbgl/gl/program_binary_extension.hpp - src/mbgl/gl/renderbuffer.hpp - src/mbgl/gl/state.hpp - src/mbgl/gl/stencil_mode.cpp - src/mbgl/gl/stencil_mode.hpp - src/mbgl/gl/texture.hpp - src/mbgl/gl/types.hpp - src/mbgl/gl/uniform.cpp - src/mbgl/gl/uniform.hpp - src/mbgl/gl/value.cpp - src/mbgl/gl/value.hpp - src/mbgl/gl/vertex_array.cpp - src/mbgl/gl/vertex_array.hpp - src/mbgl/gl/vertex_array_extension.hpp - src/mbgl/gl/vertex_buffer.hpp - - # layout - src/mbgl/layout/clip_lines.cpp - src/mbgl/layout/clip_lines.hpp - src/mbgl/layout/merge_lines.cpp - src/mbgl/layout/merge_lines.hpp - src/mbgl/layout/symbol_feature.hpp - src/mbgl/layout/symbol_instance.cpp - src/mbgl/layout/symbol_instance.hpp - src/mbgl/layout/symbol_layout.cpp - src/mbgl/layout/symbol_layout.hpp - src/mbgl/layout/symbol_projection.cpp - src/mbgl/layout/symbol_projection.hpp - - # map - include/mbgl/map/camera.hpp - include/mbgl/map/change.hpp - include/mbgl/map/map.hpp - include/mbgl/map/map_observer.hpp - include/mbgl/map/mode.hpp - src/mbgl/map/map.cpp - src/mbgl/map/transform.cpp - src/mbgl/map/transform.hpp - src/mbgl/map/transform_state.cpp - src/mbgl/map/transform_state.hpp - src/mbgl/map/zoom_history.hpp - - # math - include/mbgl/math/clamp.hpp - include/mbgl/math/log2.hpp - include/mbgl/math/minmax.hpp - include/mbgl/math/wrap.hpp - src/mbgl/math/log2.cpp - - # parsedate - src/parsedate/parsedate.cpp - src/parsedate/parsedate.hpp - - # programs - src/mbgl/programs/attributes.hpp - src/mbgl/programs/background_program.cpp - src/mbgl/programs/background_program.hpp - src/mbgl/programs/binary_program.cpp - src/mbgl/programs/binary_program.hpp - src/mbgl/programs/circle_program.cpp - src/mbgl/programs/circle_program.hpp - src/mbgl/programs/clipping_mask_program.hpp - src/mbgl/programs/collision_box_program.cpp - src/mbgl/programs/collision_box_program.hpp - src/mbgl/programs/debug_program.hpp - src/mbgl/programs/extrusion_texture_program.cpp - src/mbgl/programs/extrusion_texture_program.hpp - src/mbgl/programs/fill_extrusion_program.cpp - src/mbgl/programs/fill_extrusion_program.hpp - src/mbgl/programs/fill_program.cpp - src/mbgl/programs/fill_program.hpp - src/mbgl/programs/heatmap_program.cpp - src/mbgl/programs/heatmap_program.hpp - src/mbgl/programs/heatmap_texture_program.cpp - src/mbgl/programs/heatmap_texture_program.hpp - src/mbgl/programs/hillshade_prepare_program.cpp - src/mbgl/programs/hillshade_prepare_program.hpp - src/mbgl/programs/hillshade_program.cpp - src/mbgl/programs/hillshade_program.hpp - src/mbgl/programs/line_program.cpp - src/mbgl/programs/line_program.hpp - src/mbgl/programs/program.hpp - src/mbgl/programs/program_parameters.cpp - src/mbgl/programs/program_parameters.hpp - src/mbgl/programs/programs.hpp - src/mbgl/programs/raster_program.cpp - src/mbgl/programs/raster_program.hpp - src/mbgl/programs/segment.hpp - src/mbgl/programs/symbol_program.cpp - src/mbgl/programs/symbol_program.hpp - src/mbgl/programs/uniforms.hpp - - # renderer - include/mbgl/renderer/backend_scope.hpp - include/mbgl/renderer/mode.hpp - include/mbgl/renderer/query.hpp - include/mbgl/renderer/renderer.hpp - include/mbgl/renderer/renderer_backend.hpp - include/mbgl/renderer/renderer_frontend.hpp - include/mbgl/renderer/renderer_observer.hpp - src/mbgl/renderer/backend_scope.cpp - src/mbgl/renderer/bucket.hpp - src/mbgl/renderer/bucket_parameters.cpp - src/mbgl/renderer/bucket_parameters.hpp - src/mbgl/renderer/cross_faded_property_evaluator.cpp - src/mbgl/renderer/cross_faded_property_evaluator.hpp - src/mbgl/renderer/data_driven_property_evaluator.hpp - src/mbgl/renderer/group_by_layout.cpp - src/mbgl/renderer/group_by_layout.hpp - src/mbgl/renderer/image_atlas.cpp - src/mbgl/renderer/image_atlas.hpp - src/mbgl/renderer/image_manager.cpp - src/mbgl/renderer/image_manager.hpp - src/mbgl/renderer/paint_parameters.cpp - src/mbgl/renderer/paint_parameters.hpp - src/mbgl/renderer/paint_property_binder.hpp - src/mbgl/renderer/paint_property_statistics.hpp - src/mbgl/renderer/possibly_evaluated_property_value.hpp - src/mbgl/renderer/property_evaluation_parameters.hpp - src/mbgl/renderer/property_evaluator.hpp - src/mbgl/renderer/render_layer.cpp - src/mbgl/renderer/render_layer.hpp - src/mbgl/renderer/render_light.cpp - src/mbgl/renderer/render_light.hpp - src/mbgl/renderer/render_pass.hpp - src/mbgl/renderer/render_source.cpp - src/mbgl/renderer/render_source.hpp - src/mbgl/renderer/render_source_observer.hpp - src/mbgl/renderer/render_static_data.cpp - src/mbgl/renderer/render_static_data.hpp - src/mbgl/renderer/render_tile.cpp - src/mbgl/renderer/render_tile.hpp - src/mbgl/renderer/renderer.cpp - src/mbgl/renderer/renderer_backend.cpp - src/mbgl/renderer/renderer_impl.cpp - src/mbgl/renderer/renderer_impl.hpp - src/mbgl/renderer/style_diff.cpp - src/mbgl/renderer/style_diff.hpp - src/mbgl/renderer/tile_mask.hpp - src/mbgl/renderer/tile_parameters.hpp - src/mbgl/renderer/tile_pyramid.cpp - src/mbgl/renderer/tile_pyramid.hpp - src/mbgl/renderer/transition_parameters.hpp - src/mbgl/renderer/update_parameters.hpp - - # renderer/buckets - src/mbgl/renderer/buckets/circle_bucket.cpp - src/mbgl/renderer/buckets/circle_bucket.hpp - src/mbgl/renderer/buckets/debug_bucket.cpp - src/mbgl/renderer/buckets/debug_bucket.hpp - src/mbgl/renderer/buckets/fill_bucket.cpp - src/mbgl/renderer/buckets/fill_bucket.hpp - src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp - src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp - src/mbgl/renderer/buckets/heatmap_bucket.cpp - src/mbgl/renderer/buckets/heatmap_bucket.hpp - src/mbgl/renderer/buckets/hillshade_bucket.cpp - src/mbgl/renderer/buckets/hillshade_bucket.hpp - src/mbgl/renderer/buckets/line_bucket.cpp - src/mbgl/renderer/buckets/line_bucket.hpp - src/mbgl/renderer/buckets/raster_bucket.cpp - src/mbgl/renderer/buckets/raster_bucket.hpp - src/mbgl/renderer/buckets/symbol_bucket.cpp - src/mbgl/renderer/buckets/symbol_bucket.hpp - - # renderer/layers - src/mbgl/renderer/layers/render_background_layer.cpp - src/mbgl/renderer/layers/render_background_layer.hpp - src/mbgl/renderer/layers/render_circle_layer.cpp - src/mbgl/renderer/layers/render_circle_layer.hpp - src/mbgl/renderer/layers/render_custom_layer.cpp - src/mbgl/renderer/layers/render_custom_layer.hpp - src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp - src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp - src/mbgl/renderer/layers/render_fill_layer.cpp - src/mbgl/renderer/layers/render_fill_layer.hpp - src/mbgl/renderer/layers/render_heatmap_layer.cpp - src/mbgl/renderer/layers/render_heatmap_layer.hpp - src/mbgl/renderer/layers/render_hillshade_layer.cpp - src/mbgl/renderer/layers/render_hillshade_layer.hpp - src/mbgl/renderer/layers/render_line_layer.cpp - src/mbgl/renderer/layers/render_line_layer.hpp - src/mbgl/renderer/layers/render_raster_layer.cpp - src/mbgl/renderer/layers/render_raster_layer.hpp - src/mbgl/renderer/layers/render_symbol_layer.cpp - src/mbgl/renderer/layers/render_symbol_layer.hpp - - # renderer/sources - src/mbgl/renderer/sources/render_custom_geometry_source.cpp - src/mbgl/renderer/sources/render_custom_geometry_source.hpp - src/mbgl/renderer/sources/render_geojson_source.cpp - src/mbgl/renderer/sources/render_geojson_source.hpp - src/mbgl/renderer/sources/render_image_source.cpp - src/mbgl/renderer/sources/render_image_source.hpp - src/mbgl/renderer/sources/render_raster_dem_source.cpp - src/mbgl/renderer/sources/render_raster_dem_source.hpp - src/mbgl/renderer/sources/render_raster_source.cpp - src/mbgl/renderer/sources/render_raster_source.hpp - src/mbgl/renderer/sources/render_vector_source.cpp - src/mbgl/renderer/sources/render_vector_source.hpp - - # shaders - src/mbgl/shaders/background.cpp - src/mbgl/shaders/background.hpp - src/mbgl/shaders/background_pattern.cpp - src/mbgl/shaders/background_pattern.hpp - src/mbgl/shaders/circle.cpp - src/mbgl/shaders/circle.hpp - src/mbgl/shaders/clipping_mask.cpp - src/mbgl/shaders/clipping_mask.hpp - src/mbgl/shaders/collision_box.cpp - src/mbgl/shaders/collision_box.hpp - src/mbgl/shaders/collision_circle.cpp - src/mbgl/shaders/collision_circle.hpp - src/mbgl/shaders/debug.cpp - src/mbgl/shaders/debug.hpp - src/mbgl/shaders/extrusion_texture.cpp - src/mbgl/shaders/extrusion_texture.hpp - src/mbgl/shaders/fill.cpp - src/mbgl/shaders/fill.hpp - src/mbgl/shaders/fill_extrusion.cpp - src/mbgl/shaders/fill_extrusion.hpp - src/mbgl/shaders/fill_extrusion_pattern.cpp - src/mbgl/shaders/fill_extrusion_pattern.hpp - src/mbgl/shaders/fill_outline.cpp - src/mbgl/shaders/fill_outline.hpp - src/mbgl/shaders/fill_outline_pattern.cpp - src/mbgl/shaders/fill_outline_pattern.hpp - src/mbgl/shaders/fill_pattern.cpp - src/mbgl/shaders/fill_pattern.hpp - src/mbgl/shaders/heatmap.cpp - src/mbgl/shaders/heatmap.hpp - src/mbgl/shaders/heatmap_texture.cpp - src/mbgl/shaders/heatmap_texture.hpp - src/mbgl/shaders/hillshade.cpp - src/mbgl/shaders/hillshade.hpp - src/mbgl/shaders/hillshade_prepare.cpp - src/mbgl/shaders/hillshade_prepare.hpp - src/mbgl/shaders/line.cpp - src/mbgl/shaders/line.hpp - src/mbgl/shaders/line_pattern.cpp - src/mbgl/shaders/line_pattern.hpp - src/mbgl/shaders/line_sdf.cpp - src/mbgl/shaders/line_sdf.hpp - src/mbgl/shaders/preludes.cpp - src/mbgl/shaders/preludes.hpp - src/mbgl/shaders/raster.cpp - src/mbgl/shaders/raster.hpp - src/mbgl/shaders/shaders.cpp - src/mbgl/shaders/shaders.hpp - src/mbgl/shaders/source.cpp - src/mbgl/shaders/source.hpp - src/mbgl/shaders/symbol_icon.cpp - src/mbgl/shaders/symbol_icon.hpp - src/mbgl/shaders/symbol_sdf.cpp - src/mbgl/shaders/symbol_sdf.hpp - - # sprite - src/mbgl/sprite/sprite_loader.cpp - src/mbgl/sprite/sprite_loader.hpp - src/mbgl/sprite/sprite_loader_observer.hpp - src/mbgl/sprite/sprite_loader_worker.cpp - src/mbgl/sprite/sprite_loader_worker.hpp - src/mbgl/sprite/sprite_parser.cpp - src/mbgl/sprite/sprite_parser.hpp - - # storage - include/mbgl/storage/default_file_source.hpp - include/mbgl/storage/file_source.hpp - include/mbgl/storage/network_status.hpp - include/mbgl/storage/offline.hpp - include/mbgl/storage/online_file_source.hpp - include/mbgl/storage/resource.hpp - include/mbgl/storage/resource_transform.hpp - include/mbgl/storage/response.hpp - src/mbgl/storage/asset_file_source.hpp - src/mbgl/storage/http_file_source.hpp - src/mbgl/storage/local_file_source.hpp - src/mbgl/storage/network_status.cpp - src/mbgl/storage/resource.cpp - src/mbgl/storage/resource_transform.cpp - src/mbgl/storage/response.cpp - - # style - include/mbgl/style/color_ramp_property_value.hpp - include/mbgl/style/conversion.hpp - include/mbgl/style/conversion_impl.hpp - include/mbgl/style/filter.hpp - include/mbgl/style/image.hpp - include/mbgl/style/layer.hpp - include/mbgl/style/layer_type.hpp - include/mbgl/style/light.hpp - include/mbgl/style/position.hpp - include/mbgl/style/property_expression.hpp - include/mbgl/style/property_value.hpp - include/mbgl/style/source.hpp - include/mbgl/style/style.hpp - include/mbgl/style/transition_options.hpp - include/mbgl/style/types.hpp - include/mbgl/style/undefined.hpp - src/mbgl/style/collection.hpp - src/mbgl/style/custom_tile_loader.cpp - src/mbgl/style/custom_tile_loader.hpp - src/mbgl/style/filter.cpp - src/mbgl/style/image.cpp - src/mbgl/style/image_impl.cpp - src/mbgl/style/image_impl.hpp - src/mbgl/style/layer.cpp - src/mbgl/style/layer_impl.cpp - src/mbgl/style/layer_impl.hpp - src/mbgl/style/layer_observer.hpp - src/mbgl/style/layout_property.hpp - src/mbgl/style/light.cpp - src/mbgl/style/light_impl.cpp - src/mbgl/style/light_impl.hpp - src/mbgl/style/light_observer.hpp - src/mbgl/style/observer.hpp - src/mbgl/style/paint_property.hpp - src/mbgl/style/parser.cpp - src/mbgl/style/parser.hpp - src/mbgl/style/properties.hpp - src/mbgl/style/rapidjson_conversion.hpp - src/mbgl/style/source.cpp - src/mbgl/style/source_impl.cpp - src/mbgl/style/source_impl.hpp - src/mbgl/style/source_observer.hpp - src/mbgl/style/style.cpp - src/mbgl/style/style_impl.cpp - src/mbgl/style/style_impl.hpp - src/mbgl/style/types.cpp - - # style/conversion - include/mbgl/style/conversion/color_ramp_property_value.hpp - include/mbgl/style/conversion/constant.hpp - include/mbgl/style/conversion/coordinate.hpp - include/mbgl/style/conversion/custom_geometry_source_options.hpp - include/mbgl/style/conversion/filter.hpp - include/mbgl/style/conversion/function.hpp - include/mbgl/style/conversion/geojson.hpp - include/mbgl/style/conversion/geojson_options.hpp - include/mbgl/style/conversion/get_json_type.hpp - include/mbgl/style/conversion/layer.hpp - include/mbgl/style/conversion/light.hpp - include/mbgl/style/conversion/position.hpp - include/mbgl/style/conversion/property_value.hpp - include/mbgl/style/conversion/source.hpp - include/mbgl/style/conversion/tileset.hpp - include/mbgl/style/conversion/transition_options.hpp - src/mbgl/style/conversion/color_ramp_property_value.cpp - src/mbgl/style/conversion/constant.cpp - src/mbgl/style/conversion/coordinate.cpp - src/mbgl/style/conversion/custom_geometry_source_options.cpp - src/mbgl/style/conversion/filter.cpp - src/mbgl/style/conversion/function.cpp - src/mbgl/style/conversion/geojson.cpp - src/mbgl/style/conversion/geojson_options.cpp - src/mbgl/style/conversion/get_json_type.cpp - src/mbgl/style/conversion/json.hpp - src/mbgl/style/conversion/layer.cpp - src/mbgl/style/conversion/light.cpp - src/mbgl/style/conversion/position.cpp - src/mbgl/style/conversion/property_value.cpp - src/mbgl/style/conversion/source.cpp - src/mbgl/style/conversion/stringify.hpp - src/mbgl/style/conversion/tileset.cpp - src/mbgl/style/conversion/transition_options.cpp - - # style/expression - include/mbgl/style/expression/array_assertion.hpp - include/mbgl/style/expression/assertion.hpp - include/mbgl/style/expression/at.hpp - include/mbgl/style/expression/boolean_operator.hpp - include/mbgl/style/expression/case.hpp - include/mbgl/style/expression/check_subtype.hpp - include/mbgl/style/expression/coalesce.hpp - include/mbgl/style/expression/coercion.hpp - include/mbgl/style/expression/collator.hpp - include/mbgl/style/expression/collator_expression.hpp - include/mbgl/style/expression/comparison.hpp - include/mbgl/style/expression/compound_expression.hpp - include/mbgl/style/expression/dsl.hpp - include/mbgl/style/expression/error.hpp - include/mbgl/style/expression/expression.hpp - include/mbgl/style/expression/find_zoom_curve.hpp - include/mbgl/style/expression/get_covering_stops.hpp - include/mbgl/style/expression/interpolate.hpp - include/mbgl/style/expression/interpolator.hpp - include/mbgl/style/expression/is_constant.hpp - include/mbgl/style/expression/is_expression.hpp - include/mbgl/style/expression/length.hpp - include/mbgl/style/expression/let.hpp - include/mbgl/style/expression/literal.hpp - include/mbgl/style/expression/match.hpp - include/mbgl/style/expression/parsing_context.hpp - include/mbgl/style/expression/step.hpp - include/mbgl/style/expression/type.hpp - include/mbgl/style/expression/value.hpp - src/mbgl/style/expression/array_assertion.cpp - src/mbgl/style/expression/assertion.cpp - src/mbgl/style/expression/at.cpp - src/mbgl/style/expression/boolean_operator.cpp - src/mbgl/style/expression/case.cpp - src/mbgl/style/expression/check_subtype.cpp - src/mbgl/style/expression/coalesce.cpp - src/mbgl/style/expression/coercion.cpp - src/mbgl/style/expression/collator_expression.cpp - src/mbgl/style/expression/comparison.cpp - src/mbgl/style/expression/compound_expression.cpp - src/mbgl/style/expression/dsl.cpp - src/mbgl/style/expression/expression.cpp - src/mbgl/style/expression/find_zoom_curve.cpp - src/mbgl/style/expression/get_covering_stops.cpp - src/mbgl/style/expression/interpolate.cpp - src/mbgl/style/expression/is_constant.cpp - src/mbgl/style/expression/is_expression.cpp - src/mbgl/style/expression/length.cpp - src/mbgl/style/expression/let.cpp - src/mbgl/style/expression/literal.cpp - src/mbgl/style/expression/match.cpp - src/mbgl/style/expression/parsing_context.cpp - src/mbgl/style/expression/step.cpp - src/mbgl/style/expression/util.cpp - src/mbgl/style/expression/util.hpp - src/mbgl/style/expression/value.cpp - - # style/layers - include/mbgl/style/layers/background_layer.hpp - include/mbgl/style/layers/circle_layer.hpp - include/mbgl/style/layers/custom_layer.hpp - include/mbgl/style/layers/fill_extrusion_layer.hpp - include/mbgl/style/layers/fill_layer.hpp - include/mbgl/style/layers/heatmap_layer.hpp - include/mbgl/style/layers/hillshade_layer.hpp - include/mbgl/style/layers/line_layer.hpp - include/mbgl/style/layers/raster_layer.hpp - include/mbgl/style/layers/symbol_layer.hpp - src/mbgl/style/layers/background_layer.cpp - src/mbgl/style/layers/background_layer_impl.cpp - src/mbgl/style/layers/background_layer_impl.hpp - src/mbgl/style/layers/background_layer_properties.cpp - src/mbgl/style/layers/background_layer_properties.hpp - src/mbgl/style/layers/circle_layer.cpp - src/mbgl/style/layers/circle_layer_impl.cpp - src/mbgl/style/layers/circle_layer_impl.hpp - src/mbgl/style/layers/circle_layer_properties.cpp - src/mbgl/style/layers/circle_layer_properties.hpp - src/mbgl/style/layers/custom_layer.cpp - src/mbgl/style/layers/custom_layer_impl.cpp - src/mbgl/style/layers/custom_layer_impl.hpp - src/mbgl/style/layers/fill_extrusion_layer.cpp - src/mbgl/style/layers/fill_extrusion_layer_impl.cpp - src/mbgl/style/layers/fill_extrusion_layer_impl.hpp - src/mbgl/style/layers/fill_extrusion_layer_properties.cpp - src/mbgl/style/layers/fill_extrusion_layer_properties.hpp - src/mbgl/style/layers/fill_layer.cpp - src/mbgl/style/layers/fill_layer_impl.cpp - src/mbgl/style/layers/fill_layer_impl.hpp - src/mbgl/style/layers/fill_layer_properties.cpp - src/mbgl/style/layers/fill_layer_properties.hpp - src/mbgl/style/layers/heatmap_layer.cpp - src/mbgl/style/layers/heatmap_layer_impl.cpp - src/mbgl/style/layers/heatmap_layer_impl.hpp - src/mbgl/style/layers/heatmap_layer_properties.cpp - src/mbgl/style/layers/heatmap_layer_properties.hpp - src/mbgl/style/layers/hillshade_layer.cpp - src/mbgl/style/layers/hillshade_layer_impl.cpp - src/mbgl/style/layers/hillshade_layer_impl.hpp - src/mbgl/style/layers/hillshade_layer_properties.cpp - src/mbgl/style/layers/hillshade_layer_properties.hpp - src/mbgl/style/layers/line_layer.cpp - src/mbgl/style/layers/line_layer_impl.cpp - src/mbgl/style/layers/line_layer_impl.hpp - src/mbgl/style/layers/line_layer_properties.cpp - src/mbgl/style/layers/line_layer_properties.hpp - src/mbgl/style/layers/raster_layer.cpp - src/mbgl/style/layers/raster_layer_impl.cpp - src/mbgl/style/layers/raster_layer_impl.hpp - src/mbgl/style/layers/raster_layer_properties.cpp - src/mbgl/style/layers/raster_layer_properties.hpp - src/mbgl/style/layers/symbol_layer.cpp - src/mbgl/style/layers/symbol_layer_impl.cpp - src/mbgl/style/layers/symbol_layer_impl.hpp - src/mbgl/style/layers/symbol_layer_properties.cpp - src/mbgl/style/layers/symbol_layer_properties.hpp - - # style/sources - include/mbgl/style/sources/custom_geometry_source.hpp - include/mbgl/style/sources/geojson_source.hpp - include/mbgl/style/sources/image_source.hpp - include/mbgl/style/sources/raster_dem_source.hpp - include/mbgl/style/sources/raster_source.hpp - include/mbgl/style/sources/vector_source.hpp - src/mbgl/style/sources/custom_geometry_source.cpp - src/mbgl/style/sources/custom_geometry_source_impl.cpp - src/mbgl/style/sources/custom_geometry_source_impl.hpp - src/mbgl/style/sources/geojson_source.cpp - src/mbgl/style/sources/geojson_source_impl.cpp - src/mbgl/style/sources/geojson_source_impl.hpp - src/mbgl/style/sources/image_source.cpp - src/mbgl/style/sources/image_source_impl.cpp - src/mbgl/style/sources/image_source_impl.hpp - src/mbgl/style/sources/raster_dem_source.cpp - src/mbgl/style/sources/raster_source.cpp - src/mbgl/style/sources/raster_source_impl.cpp - src/mbgl/style/sources/raster_source_impl.hpp - src/mbgl/style/sources/vector_source.cpp - src/mbgl/style/sources/vector_source_impl.cpp - src/mbgl/style/sources/vector_source_impl.hpp - - # text - src/mbgl/text/bidi.hpp - src/mbgl/text/check_max_angle.cpp - src/mbgl/text/check_max_angle.hpp - src/mbgl/text/collision_feature.cpp - src/mbgl/text/collision_feature.hpp - src/mbgl/text/collision_index.cpp - src/mbgl/text/collision_index.hpp - src/mbgl/text/cross_tile_symbol_index.cpp - src/mbgl/text/cross_tile_symbol_index.hpp - src/mbgl/text/get_anchors.cpp - src/mbgl/text/get_anchors.hpp - src/mbgl/text/glyph.cpp - src/mbgl/text/glyph.hpp - src/mbgl/text/glyph_atlas.cpp - src/mbgl/text/glyph_atlas.hpp - src/mbgl/text/glyph_manager.cpp - src/mbgl/text/glyph_manager.hpp - src/mbgl/text/glyph_manager_observer.hpp - src/mbgl/text/glyph_pbf.cpp - src/mbgl/text/glyph_pbf.hpp - src/mbgl/text/glyph_range.hpp - src/mbgl/text/language_tag.cpp - src/mbgl/text/language_tag.hpp - src/mbgl/text/local_glyph_rasterizer.hpp - src/mbgl/text/placement.cpp - src/mbgl/text/placement.hpp - src/mbgl/text/quads.cpp - src/mbgl/text/quads.hpp - src/mbgl/text/shaping.cpp - src/mbgl/text/shaping.hpp - - # tile - include/mbgl/tile/tile_id.hpp - include/mbgl/tile/tile_necessity.hpp - src/mbgl/tile/custom_geometry_tile.cpp - src/mbgl/tile/custom_geometry_tile.hpp - src/mbgl/tile/geojson_tile.cpp - src/mbgl/tile/geojson_tile.hpp - src/mbgl/tile/geojson_tile_data.hpp - src/mbgl/tile/geometry_tile.cpp - src/mbgl/tile/geometry_tile.hpp - src/mbgl/tile/geometry_tile_data.cpp - src/mbgl/tile/geometry_tile_data.hpp - src/mbgl/tile/geometry_tile_worker.cpp - src/mbgl/tile/geometry_tile_worker.hpp - src/mbgl/tile/raster_dem_tile.cpp - src/mbgl/tile/raster_dem_tile.hpp - src/mbgl/tile/raster_dem_tile_worker.cpp - src/mbgl/tile/raster_dem_tile_worker.hpp - src/mbgl/tile/raster_tile.cpp - src/mbgl/tile/raster_tile.hpp - src/mbgl/tile/raster_tile_worker.cpp - src/mbgl/tile/raster_tile_worker.hpp - src/mbgl/tile/tile.cpp - src/mbgl/tile/tile.hpp - src/mbgl/tile/tile_cache.cpp - src/mbgl/tile/tile_cache.hpp - src/mbgl/tile/tile_id_hash.cpp - src/mbgl/tile/tile_id_io.cpp - src/mbgl/tile/tile_loader.hpp - src/mbgl/tile/tile_loader_impl.hpp - src/mbgl/tile/tile_observer.hpp - src/mbgl/tile/vector_tile.cpp - src/mbgl/tile/vector_tile.hpp - src/mbgl/tile/vector_tile_data.cpp - src/mbgl/tile/vector_tile_data.hpp - - # util - include/mbgl/util/async_request.hpp - include/mbgl/util/async_task.hpp - include/mbgl/util/char_array_buffer.hpp - include/mbgl/util/chrono.hpp - include/mbgl/util/color.hpp - include/mbgl/util/compression.hpp - include/mbgl/util/constants.hpp - include/mbgl/util/convert.hpp - include/mbgl/util/enum.hpp - include/mbgl/util/event.hpp - include/mbgl/util/exception.hpp - include/mbgl/util/expected.hpp - include/mbgl/util/feature.hpp - include/mbgl/util/font_stack.hpp - include/mbgl/util/geo.hpp - include/mbgl/util/geojson.hpp - include/mbgl/util/geometry.hpp - include/mbgl/util/ignore.hpp - include/mbgl/util/image.hpp - include/mbgl/util/immutable.hpp - include/mbgl/util/indexed_tuple.hpp - include/mbgl/util/interpolate.hpp - include/mbgl/util/logging.hpp - include/mbgl/util/noncopyable.hpp - include/mbgl/util/optional.hpp - include/mbgl/util/peer.hpp - include/mbgl/util/platform.hpp - include/mbgl/util/premultiply.hpp - include/mbgl/util/projection.hpp - include/mbgl/util/range.hpp - include/mbgl/util/run_loop.hpp - include/mbgl/util/size.hpp - include/mbgl/util/string.hpp - include/mbgl/util/thread.hpp - include/mbgl/util/tileset.hpp - include/mbgl/util/timer.hpp - include/mbgl/util/traits.hpp - include/mbgl/util/tuple.hpp - include/mbgl/util/type_list.hpp - include/mbgl/util/unitbezier.hpp - include/mbgl/util/util.hpp - include/mbgl/util/variant.hpp - include/mbgl/util/work_request.hpp - include/mbgl/util/work_task.hpp - include/mbgl/util/work_task_impl.hpp - src/mbgl/util/chrono.cpp - src/mbgl/util/clip_id.cpp - src/mbgl/util/clip_id.hpp - src/mbgl/util/color.cpp - src/mbgl/util/compression.cpp - src/mbgl/util/constants.cpp - src/mbgl/util/convert.cpp - src/mbgl/util/dtoa.cpp - src/mbgl/util/dtoa.hpp - src/mbgl/util/event.cpp - src/mbgl/util/fnv_hash.hpp - src/mbgl/util/font_stack.cpp - src/mbgl/util/geo.cpp - src/mbgl/util/geojson_impl.cpp - src/mbgl/util/grid_index.cpp - src/mbgl/util/grid_index.hpp - src/mbgl/util/http_header.cpp - src/mbgl/util/http_header.hpp - src/mbgl/util/http_timeout.cpp - src/mbgl/util/http_timeout.hpp - src/mbgl/util/i18n.cpp - src/mbgl/util/i18n.hpp - src/mbgl/util/interpolate.cpp - src/mbgl/util/intersection_tests.cpp - src/mbgl/util/intersection_tests.hpp - src/mbgl/util/io.cpp - src/mbgl/util/io.hpp - src/mbgl/util/logging.cpp - src/mbgl/util/longest_common_subsequence.hpp - src/mbgl/util/mapbox.cpp - src/mbgl/util/mapbox.hpp - src/mbgl/util/mat2.cpp - src/mbgl/util/mat2.hpp - src/mbgl/util/mat3.cpp - src/mbgl/util/mat3.hpp - src/mbgl/util/mat4.cpp - src/mbgl/util/mat4.hpp - src/mbgl/util/math.hpp - src/mbgl/util/offscreen_texture.cpp - src/mbgl/util/offscreen_texture.hpp - src/mbgl/util/premultiply.cpp - src/mbgl/util/rapidjson.hpp - src/mbgl/util/rect.hpp - src/mbgl/util/std.hpp - src/mbgl/util/stopwatch.cpp - src/mbgl/util/stopwatch.hpp - src/mbgl/util/string.cpp - src/mbgl/util/thread_local.hpp - src/mbgl/util/tile_coordinate.hpp - src/mbgl/util/tile_cover.cpp - src/mbgl/util/tile_cover.hpp - src/mbgl/util/tile_cover_impl.cpp - src/mbgl/util/tile_cover_impl.hpp - src/mbgl/util/tile_range.hpp - src/mbgl/util/tiny_sdf.cpp - src/mbgl/util/tiny_sdf.hpp - src/mbgl/util/token.hpp - src/mbgl/util/url.cpp - src/mbgl/util/url.hpp - src/mbgl/util/utf.hpp - src/mbgl/util/version.cpp - src/mbgl/util/version.hpp - src/mbgl/util/work_request.cpp - -) diff --git a/cmake/core-files.txt b/cmake/core-files.txt new file mode 100644 index 0000000000..be80bf677a --- /dev/null +++ b/cmake/core-files.txt @@ -0,0 +1,765 @@ +# This file is generated. Do not edit. Regenerate this with scripts/generate-cmake-files.js + +# actor +include/mbgl/actor/actor.hpp +include/mbgl/actor/actor_ref.hpp +include/mbgl/actor/aspiring_actor.hpp +include/mbgl/actor/established_actor.hpp +include/mbgl/actor/mailbox.hpp +include/mbgl/actor/message.hpp +include/mbgl/actor/scheduler.hpp +src/mbgl/actor/mailbox.cpp +src/mbgl/actor/scheduler.cpp + +# algorithm +src/mbgl/algorithm/covered_by_children.hpp +src/mbgl/algorithm/generate_clip_ids.cpp +src/mbgl/algorithm/generate_clip_ids.hpp +src/mbgl/algorithm/generate_clip_ids_impl.hpp +src/mbgl/algorithm/update_renderables.hpp +src/mbgl/algorithm/update_tile_masks.hpp + +# annotation +include/mbgl/annotation/annotation.hpp +src/mbgl/annotation/annotation_manager.cpp +src/mbgl/annotation/annotation_manager.hpp +src/mbgl/annotation/annotation_source.cpp +src/mbgl/annotation/annotation_source.hpp +src/mbgl/annotation/annotation_tile.cpp +src/mbgl/annotation/annotation_tile.hpp +src/mbgl/annotation/fill_annotation_impl.cpp +src/mbgl/annotation/fill_annotation_impl.hpp +src/mbgl/annotation/line_annotation_impl.cpp +src/mbgl/annotation/line_annotation_impl.hpp +src/mbgl/annotation/render_annotation_source.cpp +src/mbgl/annotation/render_annotation_source.hpp +src/mbgl/annotation/shape_annotation_impl.cpp +src/mbgl/annotation/shape_annotation_impl.hpp +src/mbgl/annotation/symbol_annotation_impl.cpp +src/mbgl/annotation/symbol_annotation_impl.hpp + +# csscolorparser +src/csscolorparser/csscolorparser.cpp +src/csscolorparser/csscolorparser.hpp + +# geometry +src/mbgl/geometry/anchor.hpp +src/mbgl/geometry/debug_font_data.hpp +src/mbgl/geometry/dem_data.cpp +src/mbgl/geometry/dem_data.hpp +src/mbgl/geometry/feature_index.cpp +src/mbgl/geometry/feature_index.hpp +src/mbgl/geometry/line_atlas.cpp +src/mbgl/geometry/line_atlas.hpp + +# gl +src/mbgl/gl/attribute.cpp +src/mbgl/gl/attribute.hpp +src/mbgl/gl/color_mode.cpp +src/mbgl/gl/color_mode.hpp +src/mbgl/gl/context.cpp +src/mbgl/gl/context.hpp +src/mbgl/gl/debugging.cpp +src/mbgl/gl/debugging.hpp +src/mbgl/gl/debugging_extension.cpp +src/mbgl/gl/debugging_extension.hpp +src/mbgl/gl/depth_mode.cpp +src/mbgl/gl/depth_mode.hpp +src/mbgl/gl/draw_mode.hpp +src/mbgl/gl/extension.hpp +src/mbgl/gl/features.hpp +src/mbgl/gl/framebuffer.hpp +src/mbgl/gl/gl.cpp +src/mbgl/gl/gl.hpp +src/mbgl/gl/index_buffer.hpp +src/mbgl/gl/object.cpp +src/mbgl/gl/object.hpp +src/mbgl/gl/primitives.hpp +src/mbgl/gl/program.hpp +src/mbgl/gl/program_binary_extension.hpp +src/mbgl/gl/renderbuffer.hpp +src/mbgl/gl/state.hpp +src/mbgl/gl/stencil_mode.cpp +src/mbgl/gl/stencil_mode.hpp +src/mbgl/gl/texture.hpp +src/mbgl/gl/types.hpp +src/mbgl/gl/uniform.cpp +src/mbgl/gl/uniform.hpp +src/mbgl/gl/value.cpp +src/mbgl/gl/value.hpp +src/mbgl/gl/vertex_array.cpp +src/mbgl/gl/vertex_array.hpp +src/mbgl/gl/vertex_array_extension.hpp +src/mbgl/gl/vertex_buffer.hpp + +# layout +src/mbgl/layout/clip_lines.cpp +src/mbgl/layout/clip_lines.hpp +src/mbgl/layout/merge_lines.cpp +src/mbgl/layout/merge_lines.hpp +src/mbgl/layout/symbol_feature.hpp +src/mbgl/layout/symbol_instance.cpp +src/mbgl/layout/symbol_instance.hpp +src/mbgl/layout/symbol_layout.cpp +src/mbgl/layout/symbol_layout.hpp +src/mbgl/layout/symbol_projection.cpp +src/mbgl/layout/symbol_projection.hpp + +# map +include/mbgl/map/camera.hpp +include/mbgl/map/change.hpp +include/mbgl/map/map.hpp +include/mbgl/map/map_observer.hpp +include/mbgl/map/mode.hpp +src/mbgl/map/map.cpp +src/mbgl/map/transform.cpp +src/mbgl/map/transform.hpp +src/mbgl/map/transform_state.cpp +src/mbgl/map/transform_state.hpp +src/mbgl/map/zoom_history.hpp + +# math +include/mbgl/math/clamp.hpp +include/mbgl/math/log2.hpp +include/mbgl/math/minmax.hpp +include/mbgl/math/wrap.hpp +src/mbgl/math/log2.cpp + +# parsedate +src/parsedate/parsedate.cpp +src/parsedate/parsedate.hpp + +# programs +src/mbgl/programs/attributes.hpp +src/mbgl/programs/background_program.cpp +src/mbgl/programs/background_program.hpp +src/mbgl/programs/binary_program.cpp +src/mbgl/programs/binary_program.hpp +src/mbgl/programs/circle_program.cpp +src/mbgl/programs/circle_program.hpp +src/mbgl/programs/clipping_mask_program.hpp +src/mbgl/programs/collision_box_program.cpp +src/mbgl/programs/collision_box_program.hpp +src/mbgl/programs/debug_program.hpp +src/mbgl/programs/extrusion_texture_program.cpp +src/mbgl/programs/extrusion_texture_program.hpp +src/mbgl/programs/fill_extrusion_program.cpp +src/mbgl/programs/fill_extrusion_program.hpp +src/mbgl/programs/fill_program.cpp +src/mbgl/programs/fill_program.hpp +src/mbgl/programs/heatmap_program.cpp +src/mbgl/programs/heatmap_program.hpp +src/mbgl/programs/heatmap_texture_program.cpp +src/mbgl/programs/heatmap_texture_program.hpp +src/mbgl/programs/hillshade_prepare_program.cpp +src/mbgl/programs/hillshade_prepare_program.hpp +src/mbgl/programs/hillshade_program.cpp +src/mbgl/programs/hillshade_program.hpp +src/mbgl/programs/line_program.cpp +src/mbgl/programs/line_program.hpp +src/mbgl/programs/program.hpp +src/mbgl/programs/program_parameters.cpp +src/mbgl/programs/program_parameters.hpp +src/mbgl/programs/programs.hpp +src/mbgl/programs/raster_program.cpp +src/mbgl/programs/raster_program.hpp +src/mbgl/programs/segment.hpp +src/mbgl/programs/symbol_program.cpp +src/mbgl/programs/symbol_program.hpp +src/mbgl/programs/uniforms.hpp + +# renderer +include/mbgl/renderer/backend_scope.hpp +include/mbgl/renderer/mode.hpp +include/mbgl/renderer/query.hpp +include/mbgl/renderer/renderer.hpp +include/mbgl/renderer/renderer_backend.hpp +include/mbgl/renderer/renderer_frontend.hpp +include/mbgl/renderer/renderer_observer.hpp +src/mbgl/renderer/backend_scope.cpp +src/mbgl/renderer/bucket.hpp +src/mbgl/renderer/bucket_parameters.cpp +src/mbgl/renderer/bucket_parameters.hpp +src/mbgl/renderer/cross_faded_property_evaluator.cpp +src/mbgl/renderer/cross_faded_property_evaluator.hpp +src/mbgl/renderer/data_driven_property_evaluator.hpp +src/mbgl/renderer/group_by_layout.cpp +src/mbgl/renderer/group_by_layout.hpp +src/mbgl/renderer/image_atlas.cpp +src/mbgl/renderer/image_atlas.hpp +src/mbgl/renderer/image_manager.cpp +src/mbgl/renderer/image_manager.hpp +src/mbgl/renderer/paint_parameters.cpp +src/mbgl/renderer/paint_parameters.hpp +src/mbgl/renderer/paint_property_binder.hpp +src/mbgl/renderer/paint_property_statistics.hpp +src/mbgl/renderer/possibly_evaluated_property_value.hpp +src/mbgl/renderer/property_evaluation_parameters.hpp +src/mbgl/renderer/property_evaluator.hpp +src/mbgl/renderer/render_layer.cpp +src/mbgl/renderer/render_layer.hpp +src/mbgl/renderer/render_light.cpp +src/mbgl/renderer/render_light.hpp +src/mbgl/renderer/render_pass.hpp +src/mbgl/renderer/render_source.cpp +src/mbgl/renderer/render_source.hpp +src/mbgl/renderer/render_source_observer.hpp +src/mbgl/renderer/render_static_data.cpp +src/mbgl/renderer/render_static_data.hpp +src/mbgl/renderer/render_tile.cpp +src/mbgl/renderer/render_tile.hpp +src/mbgl/renderer/renderer.cpp +src/mbgl/renderer/renderer_backend.cpp +src/mbgl/renderer/renderer_impl.cpp +src/mbgl/renderer/renderer_impl.hpp +src/mbgl/renderer/style_diff.cpp +src/mbgl/renderer/style_diff.hpp +src/mbgl/renderer/tile_mask.hpp +src/mbgl/renderer/tile_parameters.hpp +src/mbgl/renderer/tile_pyramid.cpp +src/mbgl/renderer/tile_pyramid.hpp +src/mbgl/renderer/transition_parameters.hpp +src/mbgl/renderer/update_parameters.hpp + +# renderer/buckets +src/mbgl/renderer/buckets/circle_bucket.cpp +src/mbgl/renderer/buckets/circle_bucket.hpp +src/mbgl/renderer/buckets/debug_bucket.cpp +src/mbgl/renderer/buckets/debug_bucket.hpp +src/mbgl/renderer/buckets/fill_bucket.cpp +src/mbgl/renderer/buckets/fill_bucket.hpp +src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp +src/mbgl/renderer/buckets/fill_extrusion_bucket.hpp +src/mbgl/renderer/buckets/heatmap_bucket.cpp +src/mbgl/renderer/buckets/heatmap_bucket.hpp +src/mbgl/renderer/buckets/hillshade_bucket.cpp +src/mbgl/renderer/buckets/hillshade_bucket.hpp +src/mbgl/renderer/buckets/line_bucket.cpp +src/mbgl/renderer/buckets/line_bucket.hpp +src/mbgl/renderer/buckets/raster_bucket.cpp +src/mbgl/renderer/buckets/raster_bucket.hpp +src/mbgl/renderer/buckets/symbol_bucket.cpp +src/mbgl/renderer/buckets/symbol_bucket.hpp + +# renderer/layers +src/mbgl/renderer/layers/render_background_layer.cpp +src/mbgl/renderer/layers/render_background_layer.hpp +src/mbgl/renderer/layers/render_circle_layer.cpp +src/mbgl/renderer/layers/render_circle_layer.hpp +src/mbgl/renderer/layers/render_custom_layer.cpp +src/mbgl/renderer/layers/render_custom_layer.hpp +src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp +src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp +src/mbgl/renderer/layers/render_fill_layer.cpp +src/mbgl/renderer/layers/render_fill_layer.hpp +src/mbgl/renderer/layers/render_heatmap_layer.cpp +src/mbgl/renderer/layers/render_heatmap_layer.hpp +src/mbgl/renderer/layers/render_hillshade_layer.cpp +src/mbgl/renderer/layers/render_hillshade_layer.hpp +src/mbgl/renderer/layers/render_line_layer.cpp +src/mbgl/renderer/layers/render_line_layer.hpp +src/mbgl/renderer/layers/render_raster_layer.cpp +src/mbgl/renderer/layers/render_raster_layer.hpp +src/mbgl/renderer/layers/render_symbol_layer.cpp +src/mbgl/renderer/layers/render_symbol_layer.hpp + +# renderer/sources +src/mbgl/renderer/sources/render_custom_geometry_source.cpp +src/mbgl/renderer/sources/render_custom_geometry_source.hpp +src/mbgl/renderer/sources/render_geojson_source.cpp +src/mbgl/renderer/sources/render_geojson_source.hpp +src/mbgl/renderer/sources/render_image_source.cpp +src/mbgl/renderer/sources/render_image_source.hpp +src/mbgl/renderer/sources/render_raster_dem_source.cpp +src/mbgl/renderer/sources/render_raster_dem_source.hpp +src/mbgl/renderer/sources/render_raster_source.cpp +src/mbgl/renderer/sources/render_raster_source.hpp +src/mbgl/renderer/sources/render_vector_source.cpp +src/mbgl/renderer/sources/render_vector_source.hpp + +# shaders +src/mbgl/shaders/background.cpp +src/mbgl/shaders/background.hpp +src/mbgl/shaders/background_pattern.cpp +src/mbgl/shaders/background_pattern.hpp +src/mbgl/shaders/circle.cpp +src/mbgl/shaders/circle.hpp +src/mbgl/shaders/clipping_mask.cpp +src/mbgl/shaders/clipping_mask.hpp +src/mbgl/shaders/collision_box.cpp +src/mbgl/shaders/collision_box.hpp +src/mbgl/shaders/collision_circle.cpp +src/mbgl/shaders/collision_circle.hpp +src/mbgl/shaders/debug.cpp +src/mbgl/shaders/debug.hpp +src/mbgl/shaders/extrusion_texture.cpp +src/mbgl/shaders/extrusion_texture.hpp +src/mbgl/shaders/fill.cpp +src/mbgl/shaders/fill.hpp +src/mbgl/shaders/fill_extrusion.cpp +src/mbgl/shaders/fill_extrusion.hpp +src/mbgl/shaders/fill_extrusion_pattern.cpp +src/mbgl/shaders/fill_extrusion_pattern.hpp +src/mbgl/shaders/fill_outline.cpp +src/mbgl/shaders/fill_outline.hpp +src/mbgl/shaders/fill_outline_pattern.cpp +src/mbgl/shaders/fill_outline_pattern.hpp +src/mbgl/shaders/fill_pattern.cpp +src/mbgl/shaders/fill_pattern.hpp +src/mbgl/shaders/heatmap.cpp +src/mbgl/shaders/heatmap.hpp +src/mbgl/shaders/heatmap_texture.cpp +src/mbgl/shaders/heatmap_texture.hpp +src/mbgl/shaders/hillshade.cpp +src/mbgl/shaders/hillshade.hpp +src/mbgl/shaders/hillshade_prepare.cpp +src/mbgl/shaders/hillshade_prepare.hpp +src/mbgl/shaders/line.cpp +src/mbgl/shaders/line.hpp +src/mbgl/shaders/line_pattern.cpp +src/mbgl/shaders/line_pattern.hpp +src/mbgl/shaders/line_sdf.cpp +src/mbgl/shaders/line_sdf.hpp +src/mbgl/shaders/preludes.cpp +src/mbgl/shaders/preludes.hpp +src/mbgl/shaders/raster.cpp +src/mbgl/shaders/raster.hpp +src/mbgl/shaders/shaders.cpp +src/mbgl/shaders/shaders.hpp +src/mbgl/shaders/source.cpp +src/mbgl/shaders/source.hpp +src/mbgl/shaders/symbol_icon.cpp +src/mbgl/shaders/symbol_icon.hpp +src/mbgl/shaders/symbol_sdf.cpp +src/mbgl/shaders/symbol_sdf.hpp + +# sprite +src/mbgl/sprite/sprite_loader.cpp +src/mbgl/sprite/sprite_loader.hpp +src/mbgl/sprite/sprite_loader_observer.hpp +src/mbgl/sprite/sprite_loader_worker.cpp +src/mbgl/sprite/sprite_loader_worker.hpp +src/mbgl/sprite/sprite_parser.cpp +src/mbgl/sprite/sprite_parser.hpp + +# storage +include/mbgl/storage/default_file_source.hpp +include/mbgl/storage/file_source.hpp +include/mbgl/storage/network_status.hpp +include/mbgl/storage/offline.hpp +include/mbgl/storage/online_file_source.hpp +include/mbgl/storage/resource.hpp +include/mbgl/storage/resource_transform.hpp +include/mbgl/storage/response.hpp +src/mbgl/storage/asset_file_source.hpp +src/mbgl/storage/http_file_source.hpp +src/mbgl/storage/local_file_source.hpp +src/mbgl/storage/network_status.cpp +src/mbgl/storage/resource.cpp +src/mbgl/storage/resource_transform.cpp +src/mbgl/storage/response.cpp + +# style +include/mbgl/style/color_ramp_property_value.hpp +include/mbgl/style/conversion.hpp +include/mbgl/style/conversion_impl.hpp +include/mbgl/style/filter.hpp +include/mbgl/style/image.hpp +include/mbgl/style/layer.hpp +include/mbgl/style/layer_type.hpp +include/mbgl/style/light.hpp +include/mbgl/style/position.hpp +include/mbgl/style/property_expression.hpp +include/mbgl/style/property_value.hpp +include/mbgl/style/source.hpp +include/mbgl/style/style.hpp +include/mbgl/style/transition_options.hpp +include/mbgl/style/types.hpp +include/mbgl/style/undefined.hpp +src/mbgl/style/collection.hpp +src/mbgl/style/custom_tile_loader.cpp +src/mbgl/style/custom_tile_loader.hpp +src/mbgl/style/filter.cpp +src/mbgl/style/image.cpp +src/mbgl/style/image_impl.cpp +src/mbgl/style/image_impl.hpp +src/mbgl/style/layer.cpp +src/mbgl/style/layer_impl.cpp +src/mbgl/style/layer_impl.hpp +src/mbgl/style/layer_observer.hpp +src/mbgl/style/layout_property.hpp +src/mbgl/style/light.cpp +src/mbgl/style/light_impl.cpp +src/mbgl/style/light_impl.hpp +src/mbgl/style/light_observer.hpp +src/mbgl/style/observer.hpp +src/mbgl/style/paint_property.hpp +src/mbgl/style/parser.cpp +src/mbgl/style/parser.hpp +src/mbgl/style/properties.hpp +src/mbgl/style/rapidjson_conversion.hpp +src/mbgl/style/source.cpp +src/mbgl/style/source_impl.cpp +src/mbgl/style/source_impl.hpp +src/mbgl/style/source_observer.hpp +src/mbgl/style/style.cpp +src/mbgl/style/style_impl.cpp +src/mbgl/style/style_impl.hpp +src/mbgl/style/types.cpp + +# style/conversion +include/mbgl/style/conversion/color_ramp_property_value.hpp +include/mbgl/style/conversion/constant.hpp +include/mbgl/style/conversion/coordinate.hpp +include/mbgl/style/conversion/custom_geometry_source_options.hpp +include/mbgl/style/conversion/filter.hpp +include/mbgl/style/conversion/function.hpp +include/mbgl/style/conversion/geojson.hpp +include/mbgl/style/conversion/geojson_options.hpp +include/mbgl/style/conversion/get_json_type.hpp +include/mbgl/style/conversion/layer.hpp +include/mbgl/style/conversion/light.hpp +include/mbgl/style/conversion/position.hpp +include/mbgl/style/conversion/property_value.hpp +include/mbgl/style/conversion/source.hpp +include/mbgl/style/conversion/tileset.hpp +include/mbgl/style/conversion/transition_options.hpp +src/mbgl/style/conversion/color_ramp_property_value.cpp +src/mbgl/style/conversion/constant.cpp +src/mbgl/style/conversion/coordinate.cpp +src/mbgl/style/conversion/custom_geometry_source_options.cpp +src/mbgl/style/conversion/filter.cpp +src/mbgl/style/conversion/function.cpp +src/mbgl/style/conversion/geojson.cpp +src/mbgl/style/conversion/geojson_options.cpp +src/mbgl/style/conversion/get_json_type.cpp +src/mbgl/style/conversion/json.hpp +src/mbgl/style/conversion/layer.cpp +src/mbgl/style/conversion/light.cpp +src/mbgl/style/conversion/position.cpp +src/mbgl/style/conversion/property_value.cpp +src/mbgl/style/conversion/source.cpp +src/mbgl/style/conversion/stringify.hpp +src/mbgl/style/conversion/tileset.cpp +src/mbgl/style/conversion/transition_options.cpp + +# style/expression +include/mbgl/style/expression/array_assertion.hpp +include/mbgl/style/expression/assertion.hpp +include/mbgl/style/expression/at.hpp +include/mbgl/style/expression/boolean_operator.hpp +include/mbgl/style/expression/case.hpp +include/mbgl/style/expression/check_subtype.hpp +include/mbgl/style/expression/coalesce.hpp +include/mbgl/style/expression/coercion.hpp +include/mbgl/style/expression/collator.hpp +include/mbgl/style/expression/collator_expression.hpp +include/mbgl/style/expression/comparison.hpp +include/mbgl/style/expression/compound_expression.hpp +include/mbgl/style/expression/dsl.hpp +include/mbgl/style/expression/error.hpp +include/mbgl/style/expression/expression.hpp +include/mbgl/style/expression/find_zoom_curve.hpp +include/mbgl/style/expression/get_covering_stops.hpp +include/mbgl/style/expression/interpolate.hpp +include/mbgl/style/expression/interpolator.hpp +include/mbgl/style/expression/is_constant.hpp +include/mbgl/style/expression/is_expression.hpp +include/mbgl/style/expression/length.hpp +include/mbgl/style/expression/let.hpp +include/mbgl/style/expression/literal.hpp +include/mbgl/style/expression/match.hpp +include/mbgl/style/expression/parsing_context.hpp +include/mbgl/style/expression/step.hpp +include/mbgl/style/expression/type.hpp +include/mbgl/style/expression/value.hpp +src/mbgl/style/expression/array_assertion.cpp +src/mbgl/style/expression/assertion.cpp +src/mbgl/style/expression/at.cpp +src/mbgl/style/expression/boolean_operator.cpp +src/mbgl/style/expression/case.cpp +src/mbgl/style/expression/check_subtype.cpp +src/mbgl/style/expression/coalesce.cpp +src/mbgl/style/expression/coercion.cpp +src/mbgl/style/expression/collator_expression.cpp +src/mbgl/style/expression/comparison.cpp +src/mbgl/style/expression/compound_expression.cpp +src/mbgl/style/expression/dsl.cpp +src/mbgl/style/expression/expression.cpp +src/mbgl/style/expression/find_zoom_curve.cpp +src/mbgl/style/expression/get_covering_stops.cpp +src/mbgl/style/expression/interpolate.cpp +src/mbgl/style/expression/is_constant.cpp +src/mbgl/style/expression/is_expression.cpp +src/mbgl/style/expression/length.cpp +src/mbgl/style/expression/let.cpp +src/mbgl/style/expression/literal.cpp +src/mbgl/style/expression/match.cpp +src/mbgl/style/expression/parsing_context.cpp +src/mbgl/style/expression/step.cpp +src/mbgl/style/expression/util.cpp +src/mbgl/style/expression/util.hpp +src/mbgl/style/expression/value.cpp + +# style/layers +include/mbgl/style/layers/background_layer.hpp +include/mbgl/style/layers/circle_layer.hpp +include/mbgl/style/layers/custom_layer.hpp +include/mbgl/style/layers/fill_extrusion_layer.hpp +include/mbgl/style/layers/fill_layer.hpp +include/mbgl/style/layers/heatmap_layer.hpp +include/mbgl/style/layers/hillshade_layer.hpp +include/mbgl/style/layers/line_layer.hpp +include/mbgl/style/layers/raster_layer.hpp +include/mbgl/style/layers/symbol_layer.hpp +src/mbgl/style/layers/background_layer.cpp +src/mbgl/style/layers/background_layer_impl.cpp +src/mbgl/style/layers/background_layer_impl.hpp +src/mbgl/style/layers/background_layer_properties.cpp +src/mbgl/style/layers/background_layer_properties.hpp +src/mbgl/style/layers/circle_layer.cpp +src/mbgl/style/layers/circle_layer_impl.cpp +src/mbgl/style/layers/circle_layer_impl.hpp +src/mbgl/style/layers/circle_layer_properties.cpp +src/mbgl/style/layers/circle_layer_properties.hpp +src/mbgl/style/layers/custom_layer.cpp +src/mbgl/style/layers/custom_layer_impl.cpp +src/mbgl/style/layers/custom_layer_impl.hpp +src/mbgl/style/layers/fill_extrusion_layer.cpp +src/mbgl/style/layers/fill_extrusion_layer_impl.cpp +src/mbgl/style/layers/fill_extrusion_layer_impl.hpp +src/mbgl/style/layers/fill_extrusion_layer_properties.cpp +src/mbgl/style/layers/fill_extrusion_layer_properties.hpp +src/mbgl/style/layers/fill_layer.cpp +src/mbgl/style/layers/fill_layer_impl.cpp +src/mbgl/style/layers/fill_layer_impl.hpp +src/mbgl/style/layers/fill_layer_properties.cpp +src/mbgl/style/layers/fill_layer_properties.hpp +src/mbgl/style/layers/heatmap_layer.cpp +src/mbgl/style/layers/heatmap_layer_impl.cpp +src/mbgl/style/layers/heatmap_layer_impl.hpp +src/mbgl/style/layers/heatmap_layer_properties.cpp +src/mbgl/style/layers/heatmap_layer_properties.hpp +src/mbgl/style/layers/hillshade_layer.cpp +src/mbgl/style/layers/hillshade_layer_impl.cpp +src/mbgl/style/layers/hillshade_layer_impl.hpp +src/mbgl/style/layers/hillshade_layer_properties.cpp +src/mbgl/style/layers/hillshade_layer_properties.hpp +src/mbgl/style/layers/line_layer.cpp +src/mbgl/style/layers/line_layer_impl.cpp +src/mbgl/style/layers/line_layer_impl.hpp +src/mbgl/style/layers/line_layer_properties.cpp +src/mbgl/style/layers/line_layer_properties.hpp +src/mbgl/style/layers/raster_layer.cpp +src/mbgl/style/layers/raster_layer_impl.cpp +src/mbgl/style/layers/raster_layer_impl.hpp +src/mbgl/style/layers/raster_layer_properties.cpp +src/mbgl/style/layers/raster_layer_properties.hpp +src/mbgl/style/layers/symbol_layer.cpp +src/mbgl/style/layers/symbol_layer_impl.cpp +src/mbgl/style/layers/symbol_layer_impl.hpp +src/mbgl/style/layers/symbol_layer_properties.cpp +src/mbgl/style/layers/symbol_layer_properties.hpp + +# style/sources +include/mbgl/style/sources/custom_geometry_source.hpp +include/mbgl/style/sources/geojson_source.hpp +include/mbgl/style/sources/image_source.hpp +include/mbgl/style/sources/raster_dem_source.hpp +include/mbgl/style/sources/raster_source.hpp +include/mbgl/style/sources/vector_source.hpp +src/mbgl/style/sources/custom_geometry_source.cpp +src/mbgl/style/sources/custom_geometry_source_impl.cpp +src/mbgl/style/sources/custom_geometry_source_impl.hpp +src/mbgl/style/sources/geojson_source.cpp +src/mbgl/style/sources/geojson_source_impl.cpp +src/mbgl/style/sources/geojson_source_impl.hpp +src/mbgl/style/sources/image_source.cpp +src/mbgl/style/sources/image_source_impl.cpp +src/mbgl/style/sources/image_source_impl.hpp +src/mbgl/style/sources/raster_dem_source.cpp +src/mbgl/style/sources/raster_source.cpp +src/mbgl/style/sources/raster_source_impl.cpp +src/mbgl/style/sources/raster_source_impl.hpp +src/mbgl/style/sources/vector_source.cpp +src/mbgl/style/sources/vector_source_impl.cpp +src/mbgl/style/sources/vector_source_impl.hpp + +# text +src/mbgl/text/bidi.hpp +src/mbgl/text/check_max_angle.cpp +src/mbgl/text/check_max_angle.hpp +src/mbgl/text/collision_feature.cpp +src/mbgl/text/collision_feature.hpp +src/mbgl/text/collision_index.cpp +src/mbgl/text/collision_index.hpp +src/mbgl/text/cross_tile_symbol_index.cpp +src/mbgl/text/cross_tile_symbol_index.hpp +src/mbgl/text/get_anchors.cpp +src/mbgl/text/get_anchors.hpp +src/mbgl/text/glyph.cpp +src/mbgl/text/glyph.hpp +src/mbgl/text/glyph_atlas.cpp +src/mbgl/text/glyph_atlas.hpp +src/mbgl/text/glyph_manager.cpp +src/mbgl/text/glyph_manager.hpp +src/mbgl/text/glyph_manager_observer.hpp +src/mbgl/text/glyph_pbf.cpp +src/mbgl/text/glyph_pbf.hpp +src/mbgl/text/glyph_range.hpp +src/mbgl/text/language_tag.cpp +src/mbgl/text/language_tag.hpp +src/mbgl/text/local_glyph_rasterizer.hpp +src/mbgl/text/placement.cpp +src/mbgl/text/placement.hpp +src/mbgl/text/quads.cpp +src/mbgl/text/quads.hpp +src/mbgl/text/shaping.cpp +src/mbgl/text/shaping.hpp + +# tile +include/mbgl/tile/tile_id.hpp +include/mbgl/tile/tile_necessity.hpp +src/mbgl/tile/custom_geometry_tile.cpp +src/mbgl/tile/custom_geometry_tile.hpp +src/mbgl/tile/geojson_tile.cpp +src/mbgl/tile/geojson_tile.hpp +src/mbgl/tile/geojson_tile_data.hpp +src/mbgl/tile/geometry_tile.cpp +src/mbgl/tile/geometry_tile.hpp +src/mbgl/tile/geometry_tile_data.cpp +src/mbgl/tile/geometry_tile_data.hpp +src/mbgl/tile/geometry_tile_worker.cpp +src/mbgl/tile/geometry_tile_worker.hpp +src/mbgl/tile/raster_dem_tile.cpp +src/mbgl/tile/raster_dem_tile.hpp +src/mbgl/tile/raster_dem_tile_worker.cpp +src/mbgl/tile/raster_dem_tile_worker.hpp +src/mbgl/tile/raster_tile.cpp +src/mbgl/tile/raster_tile.hpp +src/mbgl/tile/raster_tile_worker.cpp +src/mbgl/tile/raster_tile_worker.hpp +src/mbgl/tile/tile.cpp +src/mbgl/tile/tile.hpp +src/mbgl/tile/tile_cache.cpp +src/mbgl/tile/tile_cache.hpp +src/mbgl/tile/tile_id_hash.cpp +src/mbgl/tile/tile_id_io.cpp +src/mbgl/tile/tile_loader.hpp +src/mbgl/tile/tile_loader_impl.hpp +src/mbgl/tile/tile_observer.hpp +src/mbgl/tile/vector_tile.cpp +src/mbgl/tile/vector_tile.hpp +src/mbgl/tile/vector_tile_data.cpp +src/mbgl/tile/vector_tile_data.hpp + +# util +include/mbgl/util/async_request.hpp +include/mbgl/util/async_task.hpp +include/mbgl/util/char_array_buffer.hpp +include/mbgl/util/chrono.hpp +include/mbgl/util/color.hpp +include/mbgl/util/compression.hpp +include/mbgl/util/constants.hpp +include/mbgl/util/convert.hpp +include/mbgl/util/enum.hpp +include/mbgl/util/event.hpp +include/mbgl/util/exception.hpp +include/mbgl/util/expected.hpp +include/mbgl/util/feature.hpp +include/mbgl/util/font_stack.hpp +include/mbgl/util/geo.hpp +include/mbgl/util/geojson.hpp +include/mbgl/util/geometry.hpp +include/mbgl/util/ignore.hpp +include/mbgl/util/image.hpp +include/mbgl/util/immutable.hpp +include/mbgl/util/indexed_tuple.hpp +include/mbgl/util/interpolate.hpp +include/mbgl/util/logging.hpp +include/mbgl/util/noncopyable.hpp +include/mbgl/util/optional.hpp +include/mbgl/util/peer.hpp +include/mbgl/util/platform.hpp +include/mbgl/util/premultiply.hpp +include/mbgl/util/projection.hpp +include/mbgl/util/range.hpp +include/mbgl/util/run_loop.hpp +include/mbgl/util/size.hpp +include/mbgl/util/string.hpp +include/mbgl/util/thread.hpp +include/mbgl/util/tileset.hpp +include/mbgl/util/timer.hpp +include/mbgl/util/traits.hpp +include/mbgl/util/tuple.hpp +include/mbgl/util/type_list.hpp +include/mbgl/util/unitbezier.hpp +include/mbgl/util/util.hpp +include/mbgl/util/variant.hpp +include/mbgl/util/work_request.hpp +include/mbgl/util/work_task.hpp +include/mbgl/util/work_task_impl.hpp +src/mbgl/util/chrono.cpp +src/mbgl/util/clip_id.cpp +src/mbgl/util/clip_id.hpp +src/mbgl/util/color.cpp +src/mbgl/util/compression.cpp +src/mbgl/util/constants.cpp +src/mbgl/util/convert.cpp +src/mbgl/util/dtoa.cpp +src/mbgl/util/dtoa.hpp +src/mbgl/util/event.cpp +src/mbgl/util/fnv_hash.hpp +src/mbgl/util/font_stack.cpp +src/mbgl/util/geo.cpp +src/mbgl/util/geojson_impl.cpp +src/mbgl/util/grid_index.cpp +src/mbgl/util/grid_index.hpp +src/mbgl/util/http_header.cpp +src/mbgl/util/http_header.hpp +src/mbgl/util/http_timeout.cpp +src/mbgl/util/http_timeout.hpp +src/mbgl/util/i18n.cpp +src/mbgl/util/i18n.hpp +src/mbgl/util/interpolate.cpp +src/mbgl/util/intersection_tests.cpp +src/mbgl/util/intersection_tests.hpp +src/mbgl/util/io.cpp +src/mbgl/util/io.hpp +src/mbgl/util/logging.cpp +src/mbgl/util/longest_common_subsequence.hpp +src/mbgl/util/mapbox.cpp +src/mbgl/util/mapbox.hpp +src/mbgl/util/mat2.cpp +src/mbgl/util/mat2.hpp +src/mbgl/util/mat3.cpp +src/mbgl/util/mat3.hpp +src/mbgl/util/mat4.cpp +src/mbgl/util/mat4.hpp +src/mbgl/util/math.hpp +src/mbgl/util/offscreen_texture.cpp +src/mbgl/util/offscreen_texture.hpp +src/mbgl/util/premultiply.cpp +src/mbgl/util/rapidjson.hpp +src/mbgl/util/rect.hpp +src/mbgl/util/std.hpp +src/mbgl/util/stopwatch.cpp +src/mbgl/util/stopwatch.hpp +src/mbgl/util/string.cpp +src/mbgl/util/thread_local.hpp +src/mbgl/util/tile_coordinate.hpp +src/mbgl/util/tile_cover.cpp +src/mbgl/util/tile_cover.hpp +src/mbgl/util/tile_cover_impl.cpp +src/mbgl/util/tile_cover_impl.hpp +src/mbgl/util/tile_range.hpp +src/mbgl/util/tiny_sdf.cpp +src/mbgl/util/tiny_sdf.hpp +src/mbgl/util/token.hpp +src/mbgl/util/url.cpp +src/mbgl/util/url.hpp +src/mbgl/util/utf.hpp +src/mbgl/util/version.cpp +src/mbgl/util/version.hpp +src/mbgl/util/work_request.cpp + diff --git a/cmake/core.cmake b/cmake/core.cmake index 436c767182..d52f7ba32f 100644 --- a/cmake/core.cmake +++ b/cmake/core.cmake @@ -1,6 +1,5 @@ -add_library(mbgl-core STATIC - ${MBGL_CORE_FILES} -) +load_sources_list(MBGL_CORE_FILES cmake/core-files.txt) +add_library(mbgl-core STATIC ${MBGL_CORE_FILES}) target_include_directories(mbgl-core PUBLIC include diff --git a/cmake/files.cmake.ejs b/cmake/files.cmake.ejs deleted file mode 100644 index 57126509ed..0000000000 --- a/cmake/files.cmake.ejs +++ /dev/null @@ -1,13 +0,0 @@ -<% - const name = locals.name; - const groups = locals.groups; --%> -# This file is generated. Do not edit. Regenerate this with scripts/generate-cmake-files.js - -set(MBGL_<%- snakeCaseUpper(name) %>_FILES -<% for (const key of Object.keys(groups).sort()) { -%> - # <%- key %> - <%- groups[key].sort().join('\n ') %> - -<% } -%> -) diff --git a/cmake/files.txt.ejs b/cmake/files.txt.ejs new file mode 100644 index 0000000000..6c210347f6 --- /dev/null +++ b/cmake/files.txt.ejs @@ -0,0 +1,10 @@ +<% + const groups = locals.groups; +-%> +# This file is generated. Do not edit. Regenerate this with scripts/generate-cmake-files.js + +<% for (const key of Object.keys(groups).sort()) { -%> +# <%- key %> +<%- groups[key].sort().join('\n') %> + +<% } -%> diff --git a/cmake/filesource-files.txt b/cmake/filesource-files.txt new file mode 100644 index 0000000000..9e806d9e54 --- /dev/null +++ b/cmake/filesource-files.txt @@ -0,0 +1,24 @@ +# File source +include/mbgl/storage/default_file_source.hpp +platform/default/default_file_source.cpp +platform/default/mbgl/storage/file_source_request.hpp +platform/default/file_source_request.cpp +include/mbgl/storage/online_file_source.hpp +platform/default/online_file_source.cpp +src/mbgl/storage/http_file_source.hpp +src/mbgl/storage/asset_file_source.hpp +platform/default/asset_file_source.cpp +src/mbgl/storage/local_file_source.hpp +platform/default/local_file_source.cpp + +# Offline +include/mbgl/storage/offline.hpp +platform/default/mbgl/storage/offline.cpp +platform/default/mbgl/storage/offline_database.hpp +platform/default/mbgl/storage/offline_database.cpp +platform/default/mbgl/storage/offline_download.hpp +platform/default/mbgl/storage/offline_download.cpp +platform/default/mbgl/storage/offline_schema.hpp + +# Database +platform/default/sqlite3.hpp diff --git a/cmake/filesource.cmake b/cmake/filesource.cmake index 9b7a4a1138..6486a4af32 100644 --- a/cmake/filesource.cmake +++ b/cmake/filesource.cmake @@ -1,31 +1,7 @@ add_vendor_target(expected INTERFACE) -add_library(mbgl-filesource STATIC - # File source - include/mbgl/storage/default_file_source.hpp - platform/default/default_file_source.cpp - platform/default/mbgl/storage/file_source_request.hpp - platform/default/file_source_request.cpp - include/mbgl/storage/online_file_source.hpp - platform/default/online_file_source.cpp - src/mbgl/storage/http_file_source.hpp - src/mbgl/storage/asset_file_source.hpp - platform/default/asset_file_source.cpp - src/mbgl/storage/local_file_source.hpp - platform/default/local_file_source.cpp - - # Offline - include/mbgl/storage/offline.hpp - platform/default/mbgl/storage/offline.cpp - platform/default/mbgl/storage/offline_database.hpp - platform/default/mbgl/storage/offline_database.cpp - platform/default/mbgl/storage/offline_download.hpp - platform/default/mbgl/storage/offline_download.cpp - platform/default/mbgl/storage/offline_schema.hpp - - # Database - platform/default/sqlite3.hpp -) +load_sources_list(MBGL_FILESOURCE_FILES cmake/filesource-files.txt) +add_library(mbgl-filesource STATIC ${MBGL_FILESOURCE_FILES}) target_add_mason_package(mbgl-filesource PUBLIC geometry) target_add_mason_package(mbgl-filesource PUBLIC variant) diff --git a/cmake/mbgl.cmake b/cmake/mbgl.cmake index 2381c01205..fdb435ccca 100644 --- a/cmake/mbgl.cmake +++ b/cmake/mbgl.cmake @@ -119,6 +119,24 @@ function(create_source_groups target) endforeach() endfunction() +function(load_sources_list VAR FILELIST) + set(_FILES) + file(STRINGS "${FILELIST}" _LINES) + foreach(_LINE IN LISTS _LINES) + string(STRIP "${_LINE}" _LINE) + string(REGEX MATCH "^([^;#]+)" _FILE "${_LINE}") + if (_FILE) + list(APPEND _FILES "${_FILE}") + endif() + endforeach() + set(${VAR} "${_FILES}" PARENT_SCOPE) +endfunction() + +function(target_sources_from_file TARGET TYPE FILELIST) + load_sources_list(_FILELIST "${FILELIST}") + target_sources(${TARGET} ${TYPE} "${_FILELIST}") +endfunction() + # Creates a library target for a vendored dependency function(add_vendor_target NAME TYPE) set(INCLUDE_TYPE "INTERFACE") diff --git a/cmake/test-files.cmake b/cmake/test-files.cmake deleted file mode 100644 index ff659b1cd1..0000000000 --- a/cmake/test-files.cmake +++ /dev/null @@ -1,155 +0,0 @@ -# This file is generated. Do not edit. Regenerate this with scripts/generate-cmake-files.js - -set(MBGL_TEST_FILES - # actor - test/actor/actor.test.cpp - test/actor/actor_ref.test.cpp - - # algorithm - test/algorithm/covered_by_children.test.cpp - test/algorithm/generate_clip_ids.test.cpp - test/algorithm/mock.hpp - test/algorithm/update_renderables.test.cpp - test/algorithm/update_tile_masks.test.cpp - - # api - test/api/annotations.test.cpp - test/api/api_misuse.test.cpp - test/api/custom_geometry_source.test.cpp - test/api/custom_layer.test.cpp - test/api/query.test.cpp - test/api/recycle_map.cpp - - # geometry - test/geometry/dem_data.test.cpp - test/geometry/line_atlas.test.cpp - - # gl - test/gl/bucket.test.cpp - test/gl/context.test.cpp - test/gl/object.test.cpp - - # map - test/map/map.test.cpp - test/map/prefetch.test.cpp - test/map/transform.test.cpp - - # math - test/math/clamp.test.cpp - test/math/minmax.test.cpp - test/math/wrap.test.cpp - - # programs - test/programs/binary_program.test.cpp - test/programs/symbol_program.test.cpp - - # renderer - test/renderer/backend_scope.test.cpp - test/renderer/group_by_layout.test.cpp - test/renderer/image_manager.test.cpp - - # sprite - test/sprite/sprite_loader.test.cpp - test/sprite/sprite_parser.test.cpp - - # storage - test/storage/asset_file_source.test.cpp - test/storage/default_file_source.test.cpp - test/storage/headers.test.cpp - test/storage/http_file_source.test.cpp - test/storage/local_file_source.test.cpp - test/storage/offline.test.cpp - test/storage/offline_database.test.cpp - test/storage/offline_download.test.cpp - test/storage/online_file_source.test.cpp - test/storage/resource.test.cpp - test/storage/sqlite.test.cpp - - # style - test/style/filter.test.cpp - test/style/properties.test.cpp - test/style/property_expression.test.cpp - test/style/source.test.cpp - test/style/style.test.cpp - test/style/style_image.test.cpp - test/style/style_layer.test.cpp - test/style/style_parser.test.cpp - - # style/conversion - test/style/conversion/function.test.cpp - test/style/conversion/geojson_options.test.cpp - test/style/conversion/layer.test.cpp - test/style/conversion/light.test.cpp - test/style/conversion/property_value.test.cpp - test/style/conversion/stringify.test.cpp - test/style/conversion/tileset.test.cpp - - # style/expression - test/style/expression/expression.test.cpp - test/style/expression/util.test.cpp - - # test - test/include/mbgl/test.hpp - test/src/mbgl/test/fake_file_source.hpp - test/src/mbgl/test/fixture_log_observer.cpp - test/src/mbgl/test/fixture_log_observer.hpp - test/src/mbgl/test/getrss.cpp - test/src/mbgl/test/getrss.hpp - test/src/mbgl/test/sqlite3_test_fs.cpp - test/src/mbgl/test/sqlite3_test_fs.hpp - test/src/mbgl/test/stub_file_source.cpp - test/src/mbgl/test/stub_file_source.hpp - test/src/mbgl/test/stub_geometry_tile_feature.hpp - test/src/mbgl/test/stub_layer_observer.hpp - test/src/mbgl/test/stub_map_observer.hpp - test/src/mbgl/test/stub_render_source_observer.hpp - test/src/mbgl/test/stub_style_observer.hpp - test/src/mbgl/test/stub_tile_observer.hpp - test/src/mbgl/test/test.cpp - test/src/mbgl/test/util.cpp - test/src/mbgl/test/util.hpp - - # text - test/text/cross_tile_symbol_index.test.cpp - test/text/glyph_manager.test.cpp - test/text/glyph_pbf.test.cpp - test/text/language_tag.test.cpp - test/text/local_glyph_rasterizer.test.cpp - test/text/quads.test.cpp - - # tile - test/tile/custom_geometry_tile.test.cpp - test/tile/geojson_tile.test.cpp - test/tile/geometry_tile_data.test.cpp - test/tile/raster_dem_tile.test.cpp - test/tile/raster_tile.test.cpp - test/tile/tile_coordinate.test.cpp - test/tile/tile_id.test.cpp - test/tile/vector_tile.test.cpp - - # util - test/util/async_task.test.cpp - test/util/dtoa.test.cpp - test/util/geo.test.cpp - test/util/grid_index.test.cpp - test/util/http_timeout.test.cpp - test/util/image.test.cpp - test/util/mapbox.test.cpp - test/util/memory.test.cpp - test/util/merge_lines.test.cpp - test/util/number_conversions.test.cpp - test/util/offscreen_texture.test.cpp - test/util/peer.test.cpp - test/util/position.test.cpp - test/util/projection.test.cpp - test/util/run_loop.test.cpp - test/util/text_conversions.test.cpp - test/util/thread.test.cpp - test/util/thread_local.test.cpp - test/util/tile_cover.test.cpp - test/util/tile_range.test.cpp - test/util/timer.test.cpp - test/util/token.test.cpp - test/util/url.test.cpp - -) diff --git a/cmake/test-files.txt b/cmake/test-files.txt new file mode 100644 index 0000000000..77a69bb450 --- /dev/null +++ b/cmake/test-files.txt @@ -0,0 +1,153 @@ +# This file is generated. Do not edit. Regenerate this with scripts/generate-cmake-files.js + +# actor +test/actor/actor.test.cpp +test/actor/actor_ref.test.cpp + +# algorithm +test/algorithm/covered_by_children.test.cpp +test/algorithm/generate_clip_ids.test.cpp +test/algorithm/mock.hpp +test/algorithm/update_renderables.test.cpp +test/algorithm/update_tile_masks.test.cpp + +# api +test/api/annotations.test.cpp +test/api/api_misuse.test.cpp +test/api/custom_geometry_source.test.cpp +test/api/custom_layer.test.cpp +test/api/query.test.cpp +test/api/recycle_map.cpp + +# geometry +test/geometry/dem_data.test.cpp +test/geometry/line_atlas.test.cpp + +# gl +test/gl/bucket.test.cpp +test/gl/context.test.cpp +test/gl/object.test.cpp + +# map +test/map/map.test.cpp +test/map/prefetch.test.cpp +test/map/transform.test.cpp + +# math +test/math/clamp.test.cpp +test/math/minmax.test.cpp +test/math/wrap.test.cpp + +# programs +test/programs/binary_program.test.cpp +test/programs/symbol_program.test.cpp + +# renderer +test/renderer/backend_scope.test.cpp +test/renderer/group_by_layout.test.cpp +test/renderer/image_manager.test.cpp + +# sprite +test/sprite/sprite_loader.test.cpp +test/sprite/sprite_parser.test.cpp + +# storage +test/storage/asset_file_source.test.cpp +test/storage/default_file_source.test.cpp +test/storage/headers.test.cpp +test/storage/http_file_source.test.cpp +test/storage/local_file_source.test.cpp +test/storage/offline.test.cpp +test/storage/offline_database.test.cpp +test/storage/offline_download.test.cpp +test/storage/online_file_source.test.cpp +test/storage/resource.test.cpp +test/storage/sqlite.test.cpp + +# style +test/style/filter.test.cpp +test/style/properties.test.cpp +test/style/property_expression.test.cpp +test/style/source.test.cpp +test/style/style.test.cpp +test/style/style_image.test.cpp +test/style/style_layer.test.cpp +test/style/style_parser.test.cpp + +# style/conversion +test/style/conversion/function.test.cpp +test/style/conversion/geojson_options.test.cpp +test/style/conversion/layer.test.cpp +test/style/conversion/light.test.cpp +test/style/conversion/property_value.test.cpp +test/style/conversion/stringify.test.cpp +test/style/conversion/tileset.test.cpp + +# style/expression +test/style/expression/expression.test.cpp +test/style/expression/util.test.cpp + +# test +test/include/mbgl/test.hpp +test/src/mbgl/test/fake_file_source.hpp +test/src/mbgl/test/fixture_log_observer.cpp +test/src/mbgl/test/fixture_log_observer.hpp +test/src/mbgl/test/getrss.cpp +test/src/mbgl/test/getrss.hpp +test/src/mbgl/test/sqlite3_test_fs.cpp +test/src/mbgl/test/sqlite3_test_fs.hpp +test/src/mbgl/test/stub_file_source.cpp +test/src/mbgl/test/stub_file_source.hpp +test/src/mbgl/test/stub_geometry_tile_feature.hpp +test/src/mbgl/test/stub_layer_observer.hpp +test/src/mbgl/test/stub_map_observer.hpp +test/src/mbgl/test/stub_render_source_observer.hpp +test/src/mbgl/test/stub_style_observer.hpp +test/src/mbgl/test/stub_tile_observer.hpp +test/src/mbgl/test/test.cpp +test/src/mbgl/test/util.cpp +test/src/mbgl/test/util.hpp + +# text +test/text/cross_tile_symbol_index.test.cpp +test/text/glyph_manager.test.cpp +test/text/glyph_pbf.test.cpp +test/text/language_tag.test.cpp +test/text/local_glyph_rasterizer.test.cpp +test/text/quads.test.cpp + +# tile +test/tile/custom_geometry_tile.test.cpp +test/tile/geojson_tile.test.cpp +test/tile/geometry_tile_data.test.cpp +test/tile/raster_dem_tile.test.cpp +test/tile/raster_tile.test.cpp +test/tile/tile_coordinate.test.cpp +test/tile/tile_id.test.cpp +test/tile/vector_tile.test.cpp + +# util +test/util/async_task.test.cpp +test/util/dtoa.test.cpp +test/util/geo.test.cpp +test/util/grid_index.test.cpp +test/util/http_timeout.test.cpp +test/util/image.test.cpp +test/util/mapbox.test.cpp +test/util/memory.test.cpp +test/util/merge_lines.test.cpp +test/util/number_conversions.test.cpp +test/util/offscreen_texture.test.cpp +test/util/peer.test.cpp +test/util/position.test.cpp +test/util/projection.test.cpp +test/util/run_loop.test.cpp +test/util/text_conversions.test.cpp +test/util/thread.test.cpp +test/util/thread_local.test.cpp +test/util/tile_cover.test.cpp +test/util/tile_range.test.cpp +test/util/timer.test.cpp +test/util/token.test.cpp +test/util/url.test.cpp + diff --git a/cmake/test.cmake b/cmake/test.cmake index f4309896b8..755edad892 100644 --- a/cmake/test.cmake +++ b/cmake/test.cmake @@ -1,13 +1,10 @@ add_vendor_target(gtest STATIC) +load_sources_list(MBGL_TEST_FILES cmake/test-files.txt) if (MBGL_TEST_TARGET_TYPE STREQUAL "library") - add_library(mbgl-test SHARED - ${MBGL_TEST_FILES} - ) + add_library(mbgl-test SHARED ${MBGL_TEST_FILES}) else() - add_executable(mbgl-test - ${MBGL_TEST_FILES} - ) + add_executable(mbgl-test ${MBGL_TEST_FILES}) endif() diff --git a/platform/android/config.cmake b/platform/android/config.cmake index be9d95ef0a..84c508dd73 100644 --- a/platform/android/config.cmake +++ b/platform/android/config.cmake @@ -1,5 +1,4 @@ add_definitions(-DMBGL_USE_GLES2=1) -include(cmake/test-files.cmake) include(cmake/nunicode.cmake) # Build thin archives. @@ -34,210 +33,7 @@ set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWIT ## mbgl core ## macro(mbgl_platform_core) - target_sources(mbgl-core - # Loop - PRIVATE platform/android/src/async_task.cpp - PRIVATE platform/android/src/run_loop.cpp - PRIVATE platform/android/src/run_loop_impl.hpp - PRIVATE platform/android/src/timer.cpp - - # Misc - PRIVATE platform/android/src/text/collator.cpp - PRIVATE platform/android/src/text/collator_jni.hpp - PRIVATE platform/android/src/text/local_glyph_rasterizer.cpp - PRIVATE platform/android/src/text/local_glyph_rasterizer_jni.hpp - PRIVATE platform/android/src/logging_android.cpp - PRIVATE platform/android/src/thread.cpp - PRIVATE platform/default/string_stdlib.cpp - PRIVATE platform/default/bidi.cpp - PRIVATE platform/default/thread_local.cpp - PRIVATE platform/default/unaccent.cpp - PRIVATE platform/default/unaccent.hpp - PRIVATE platform/default/utf.cpp - - # Image handling - PRIVATE platform/default/png_writer.cpp - PRIVATE platform/android/src/bitmap.cpp - PRIVATE platform/android/src/bitmap.hpp - PRIVATE platform/android/src/bitmap_factory.cpp - PRIVATE platform/android/src/bitmap_factory.hpp - PRIVATE platform/android/src/image.cpp - - # Thread pool - PRIVATE platform/default/mbgl/util/shared_thread_pool.cpp - PRIVATE platform/default/mbgl/util/shared_thread_pool.hpp - PRIVATE platform/default/mbgl/util/default_thread_pool.cpp - PRIVATE platform/default/mbgl/util/default_thread_pool.hpp - - # Rendering - PRIVATE platform/android/src/android_renderer_backend.cpp - PRIVATE platform/android/src/android_renderer_backend.hpp - PRIVATE platform/android/src/android_renderer_frontend.cpp - PRIVATE platform/android/src/android_renderer_frontend.hpp - - # Snapshots (core) - PRIVATE platform/default/mbgl/gl/headless_backend.cpp - PRIVATE platform/default/mbgl/gl/headless_backend.hpp - PRIVATE platform/default/mbgl/gl/headless_frontend.cpp - PRIVATE platform/default/mbgl/gl/headless_frontend.hpp - PRIVATE platform/default/mbgl/map/map_snapshotter.cpp - PRIVATE platform/default/mbgl/map/map_snapshotter.hpp - PRIVATE platform/linux/src/headless_backend_egl.cpp - - # Conversion C++ -> Java - PRIVATE platform/android/src/conversion/constant.hpp - PRIVATE platform/android/src/conversion/conversion.hpp - PRIVATE platform/android/src/style/conversion/property_expression.hpp - PRIVATE platform/android/src/style/conversion/property_value.hpp - PRIVATE platform/android/src/style/conversion/types.hpp - PRIVATE platform/android/src/style/conversion/types_string_values.hpp - PRIVATE platform/android/src/map/camera_position.cpp - PRIVATE platform/android/src/map/camera_position.hpp - PRIVATE platform/android/src/map/image.cpp - PRIVATE platform/android/src/map/image.hpp - - # Style conversion Java -> C++ - PRIVATE platform/android/src/style/android_conversion.hpp - PRIVATE platform/android/src/style/value.cpp - PRIVATE platform/android/src/style/value.hpp - PRIVATE platform/android/src/style/conversion/url_or_tileset.hpp - - # Style - PRIVATE platform/android/src/style/transition_options.cpp - PRIVATE platform/android/src/style/transition_options.hpp - PRIVATE platform/android/src/style/layers/background_layer.cpp - PRIVATE platform/android/src/style/layers/background_layer.hpp - PRIVATE platform/android/src/style/layers/circle_layer.cpp - PRIVATE platform/android/src/style/layers/circle_layer.hpp - PRIVATE platform/android/src/style/layers/custom_layer.cpp - PRIVATE platform/android/src/style/layers/custom_layer.hpp - PRIVATE platform/android/src/style/layers/fill_extrusion_layer.cpp - PRIVATE platform/android/src/style/layers/fill_extrusion_layer.hpp - PRIVATE platform/android/src/style/layers/fill_layer.cpp - PRIVATE platform/android/src/style/layers/fill_layer.hpp - PRIVATE platform/android/src/style/layers/heatmap_layer.cpp - PRIVATE platform/android/src/style/layers/heatmap_layer.hpp - PRIVATE platform/android/src/style/layers/hillshade_layer.cpp - PRIVATE platform/android/src/style/layers/hillshade_layer.hpp - PRIVATE platform/android/src/style/layers/layer.cpp - PRIVATE platform/android/src/style/layers/layer.hpp - PRIVATE platform/android/src/style/layers/layers.cpp - PRIVATE platform/android/src/style/layers/layers.hpp - PRIVATE platform/android/src/style/layers/line_layer.cpp - PRIVATE platform/android/src/style/layers/line_layer.hpp - PRIVATE platform/android/src/style/layers/raster_layer.cpp - PRIVATE platform/android/src/style/layers/raster_layer.hpp - PRIVATE platform/android/src/style/layers/symbol_layer.cpp - PRIVATE platform/android/src/style/layers/symbol_layer.hpp - PRIVATE platform/android/src/style/layers/unknown_layer.cpp - PRIVATE platform/android/src/style/layers/unknown_layer.hpp - PRIVATE platform/android/src/style/sources/geojson_source.cpp - PRIVATE platform/android/src/style/sources/geojson_source.hpp - PRIVATE platform/android/src/style/sources/custom_geometry_source.cpp - PRIVATE platform/android/src/style/sources/custom_geometry_source.hpp - PRIVATE platform/android/src/style/sources/source.cpp - PRIVATE platform/android/src/style/sources/source.hpp - PRIVATE platform/android/src/style/sources/raster_source.cpp - PRIVATE platform/android/src/style/sources/raster_source.hpp - PRIVATE platform/android/src/style/sources/unknown_source.cpp - PRIVATE platform/android/src/style/sources/unknown_source.hpp - PRIVATE platform/android/src/style/sources/vector_source.cpp - PRIVATE platform/android/src/style/sources/vector_source.hpp - PRIVATE platform/android/src/style/sources/image_source.hpp - PRIVATE platform/android/src/style/sources/image_source.cpp - PRIVATE platform/android/src/style/sources/raster_dem_source.cpp - PRIVATE platform/android/src/style/sources/raster_dem_source.hpp - PRIVATE platform/android/src/style/position.cpp - PRIVATE platform/android/src/style/position.hpp - PRIVATE platform/android/src/style/light.cpp - PRIVATE platform/android/src/style/light.hpp - - # Native map - PRIVATE platform/android/src/native_map_view.cpp - PRIVATE platform/android/src/native_map_view.hpp - PRIVATE platform/android/src/map_renderer.cpp - PRIVATE platform/android/src/map_renderer.hpp - PRIVATE platform/android/src/map_renderer_runnable.cpp - PRIVATE platform/android/src/map_renderer_runnable.hpp - - # Java core classes - PRIVATE platform/android/src/java/lang.cpp - PRIVATE platform/android/src/java/lang.hpp - PRIVATE platform/android/src/java/util.cpp - PRIVATE platform/android/src/java/util.hpp - - # Graphics - PRIVATE platform/android/src/graphics/pointf.cpp - PRIVATE platform/android/src/graphics/pointf.hpp - PRIVATE platform/android/src/graphics/rectf.cpp - PRIVATE platform/android/src/graphics/rectf.hpp - - # GeoJSON - PRIVATE platform/android/src/geojson/feature.cpp - PRIVATE platform/android/src/geojson/feature.hpp - PRIVATE platform/android/src/geojson/feature_collection.cpp - PRIVATE platform/android/src/geojson/feature_collection.hpp - PRIVATE platform/android/src/geojson/geometry.cpp - PRIVATE platform/android/src/geojson/geometry.hpp - PRIVATE platform/android/src/geojson/geometry_collection.cpp - PRIVATE platform/android/src/geojson/geometry_collection.hpp - PRIVATE platform/android/src/geojson/line_string.cpp - PRIVATE platform/android/src/geojson/line_string.hpp - PRIVATE platform/android/src/geojson/multi_line_string.cpp - PRIVATE platform/android/src/geojson/multi_line_string.hpp - PRIVATE platform/android/src/geojson/multi_point.cpp - PRIVATE platform/android/src/geojson/multi_point.hpp - PRIVATE platform/android/src/geojson/multi_polygon.cpp - PRIVATE platform/android/src/geojson/multi_polygon.hpp - PRIVATE platform/android/src/geojson/point.cpp - PRIVATE platform/android/src/geojson/point.hpp - PRIVATE platform/android/src/geojson/polygon.cpp - PRIVATE platform/android/src/geojson/polygon.hpp - - # Geometry - PRIVATE platform/android/src/geometry/lat_lng.cpp - PRIVATE platform/android/src/geometry/lat_lng.hpp - PRIVATE platform/android/src/geometry/lat_lng_bounds.cpp - PRIVATE platform/android/src/geometry/lat_lng_bounds.hpp - PRIVATE platform/android/src/geometry/lat_lng_quad.cpp - PRIVATE platform/android/src/geometry/lat_lng_quad.hpp - PRIVATE platform/android/src/geometry/projected_meters.cpp - PRIVATE platform/android/src/geometry/projected_meters.hpp - - # GSon - PRIVATE platform/android/src/gson/json_array.cpp - PRIVATE platform/android/src/gson/json_array.hpp - PRIVATE platform/android/src/gson/json_element.cpp - PRIVATE platform/android/src/gson/json_element.hpp - PRIVATE platform/android/src/gson/json_object.cpp - PRIVATE platform/android/src/gson/json_object.hpp - PRIVATE platform/android/src/gson/json_primitive.cpp - PRIVATE platform/android/src/gson/json_primitive.hpp - - # Annotation - PRIVATE platform/android/src/annotation/marker.cpp - PRIVATE platform/android/src/annotation/marker.hpp - PRIVATE platform/android/src/annotation/polygon.cpp - PRIVATE platform/android/src/annotation/polygon.hpp - PRIVATE platform/android/src/annotation/polyline.cpp - PRIVATE platform/android/src/annotation/polyline.hpp - - # Snapshots (SDK) - PRIVATE platform/android/src/snapshotter/map_snapshotter.cpp - PRIVATE platform/android/src/snapshotter/map_snapshotter.hpp - PRIVATE platform/android/src/snapshotter/map_snapshot.cpp - PRIVATE platform/android/src/snapshotter/map_snapshot.hpp - - # Main jni bindings - PRIVATE platform/android/src/attach_env.cpp - PRIVATE platform/android/src/attach_env.hpp - PRIVATE platform/android/src/java_types.cpp - PRIVATE platform/android/src/java_types.hpp - - # Main entry point - PRIVATE platform/android/src/jni.hpp - PRIVATE platform/android/src/jni.cpp - ) + target_sources_from_file(mbgl-core PRIVATE platform/android/core-files.txt) target_include_directories(mbgl-core PUBLIC platform/default @@ -265,36 +61,7 @@ endmacro() macro(mbgl_filesource) - target_sources(mbgl-filesource - # File source - PRIVATE platform/android/src/http_file_source.cpp - PRIVATE platform/android/src/asset_manager.hpp - PRIVATE platform/android/src/asset_manager_file_source.cpp - PRIVATE platform/android/src/asset_manager_file_source.hpp - - # FileSource holder - PRIVATE platform/android/src/file_source.cpp - PRIVATE platform/android/src/file_source.hpp - - # Connectivity - PRIVATE platform/android/src/connectivity_listener.cpp - PRIVATE platform/android/src/connectivity_listener.hpp - - # Offline - PRIVATE platform/android/src/offline/offline_manager.cpp - PRIVATE platform/android/src/offline/offline_manager.hpp - PRIVATE platform/android/src/offline/offline_region.cpp - PRIVATE platform/android/src/offline/offline_region.hpp - PRIVATE platform/android/src/offline/offline_region_definition.cpp - PRIVATE platform/android/src/offline/offline_region_definition.hpp - PRIVATE platform/android/src/offline/offline_region_error.cpp - PRIVATE platform/android/src/offline/offline_region_error.hpp - PRIVATE platform/android/src/offline/offline_region_status.cpp - PRIVATE platform/android/src/offline/offline_region_status.hpp - - # Database - PRIVATE platform/default/sqlite3.cpp - ) + target_sources_from_file(mbgl-filesource PRIVATE platform/android/filesource-files.txt) target_add_mason_package(mbgl-filesource PUBLIC sqlite) target_add_mason_package(mbgl-filesource PUBLIC jni.hpp) diff --git a/platform/android/core-files.txt b/platform/android/core-files.txt new file mode 100644 index 0000000000..7d86cb5615 --- /dev/null +++ b/platform/android/core-files.txt @@ -0,0 +1,202 @@ +# Loop +platform/android/src/async_task.cpp +platform/android/src/run_loop.cpp +platform/android/src/run_loop_impl.hpp +platform/android/src/timer.cpp + +# Misc +platform/android/src/text/collator.cpp +platform/android/src/text/collator_jni.hpp +platform/android/src/text/local_glyph_rasterizer.cpp +platform/android/src/text/local_glyph_rasterizer_jni.hpp +platform/android/src/logging_android.cpp +platform/android/src/thread.cpp +platform/default/string_stdlib.cpp +platform/default/bidi.cpp +platform/default/thread_local.cpp +platform/default/unaccent.cpp +platform/default/unaccent.hpp +platform/default/utf.cpp + +# Image handling +platform/default/png_writer.cpp +platform/android/src/bitmap.cpp +platform/android/src/bitmap.hpp +platform/android/src/bitmap_factory.cpp +platform/android/src/bitmap_factory.hpp +platform/android/src/image.cpp + +# Thread pool +platform/default/mbgl/util/shared_thread_pool.cpp +platform/default/mbgl/util/shared_thread_pool.hpp +platform/default/mbgl/util/default_thread_pool.cpp +platform/default/mbgl/util/default_thread_pool.hpp + +# Rendering +platform/android/src/android_renderer_backend.cpp +platform/android/src/android_renderer_backend.hpp +platform/android/src/android_renderer_frontend.cpp +platform/android/src/android_renderer_frontend.hpp + +# Snapshots (core) +platform/default/mbgl/gl/headless_backend.cpp +platform/default/mbgl/gl/headless_backend.hpp +platform/default/mbgl/gl/headless_frontend.cpp +platform/default/mbgl/gl/headless_frontend.hpp +platform/default/mbgl/map/map_snapshotter.cpp +platform/default/mbgl/map/map_snapshotter.hpp +platform/linux/src/headless_backend_egl.cpp + +# Conversion C++ -> Java +platform/android/src/conversion/constant.hpp +platform/android/src/conversion/conversion.hpp +platform/android/src/style/conversion/property_expression.hpp +platform/android/src/style/conversion/property_value.hpp +platform/android/src/style/conversion/types.hpp +platform/android/src/style/conversion/types_string_values.hpp +platform/android/src/map/camera_position.cpp +platform/android/src/map/camera_position.hpp +platform/android/src/map/image.cpp +platform/android/src/map/image.hpp + +# Style conversion Java -> C++ +platform/android/src/style/android_conversion.hpp +platform/android/src/style/value.cpp +platform/android/src/style/value.hpp +platform/android/src/style/conversion/url_or_tileset.hpp + +# Style +platform/android/src/style/transition_options.cpp +platform/android/src/style/transition_options.hpp +platform/android/src/style/layers/background_layer.cpp +platform/android/src/style/layers/background_layer.hpp +platform/android/src/style/layers/circle_layer.cpp +platform/android/src/style/layers/circle_layer.hpp +platform/android/src/style/layers/custom_layer.cpp +platform/android/src/style/layers/custom_layer.hpp +platform/android/src/style/layers/fill_extrusion_layer.cpp +platform/android/src/style/layers/fill_extrusion_layer.hpp +platform/android/src/style/layers/fill_layer.cpp +platform/android/src/style/layers/fill_layer.hpp +platform/android/src/style/layers/heatmap_layer.cpp +platform/android/src/style/layers/heatmap_layer.hpp +platform/android/src/style/layers/hillshade_layer.cpp +platform/android/src/style/layers/hillshade_layer.hpp +platform/android/src/style/layers/layer.cpp +platform/android/src/style/layers/layer.hpp +platform/android/src/style/layers/layers.cpp +platform/android/src/style/layers/layers.hpp +platform/android/src/style/layers/line_layer.cpp +platform/android/src/style/layers/line_layer.hpp +platform/android/src/style/layers/raster_layer.cpp +platform/android/src/style/layers/raster_layer.hpp +platform/android/src/style/layers/symbol_layer.cpp +platform/android/src/style/layers/symbol_layer.hpp +platform/android/src/style/layers/unknown_layer.cpp +platform/android/src/style/layers/unknown_layer.hpp +platform/android/src/style/sources/geojson_source.cpp +platform/android/src/style/sources/geojson_source.hpp +platform/android/src/style/sources/custom_geometry_source.cpp +platform/android/src/style/sources/custom_geometry_source.hpp +platform/android/src/style/sources/source.cpp +platform/android/src/style/sources/source.hpp +platform/android/src/style/sources/raster_source.cpp +platform/android/src/style/sources/raster_source.hpp +platform/android/src/style/sources/unknown_source.cpp +platform/android/src/style/sources/unknown_source.hpp +platform/android/src/style/sources/vector_source.cpp +platform/android/src/style/sources/vector_source.hpp +platform/android/src/style/sources/image_source.hpp +platform/android/src/style/sources/image_source.cpp +platform/android/src/style/sources/raster_dem_source.cpp +platform/android/src/style/sources/raster_dem_source.hpp +platform/android/src/style/position.cpp +platform/android/src/style/position.hpp +platform/android/src/style/light.cpp +platform/android/src/style/light.hpp + +# Native map +platform/android/src/native_map_view.cpp +platform/android/src/native_map_view.hpp +platform/android/src/map_renderer.cpp +platform/android/src/map_renderer.hpp +platform/android/src/map_renderer_runnable.cpp +platform/android/src/map_renderer_runnable.hpp + +# Java core classes +platform/android/src/java/lang.cpp +platform/android/src/java/lang.hpp +platform/android/src/java/util.cpp +platform/android/src/java/util.hpp + +# Graphics +platform/android/src/graphics/pointf.cpp +platform/android/src/graphics/pointf.hpp +platform/android/src/graphics/rectf.cpp +platform/android/src/graphics/rectf.hpp + +# GeoJSON +platform/android/src/geojson/feature.cpp +platform/android/src/geojson/feature.hpp +platform/android/src/geojson/feature_collection.cpp +platform/android/src/geojson/feature_collection.hpp +platform/android/src/geojson/geometry.cpp +platform/android/src/geojson/geometry.hpp +platform/android/src/geojson/geometry_collection.cpp +platform/android/src/geojson/geometry_collection.hpp +platform/android/src/geojson/line_string.cpp +platform/android/src/geojson/line_string.hpp +platform/android/src/geojson/multi_line_string.cpp +platform/android/src/geojson/multi_line_string.hpp +platform/android/src/geojson/multi_point.cpp +platform/android/src/geojson/multi_point.hpp +platform/android/src/geojson/multi_polygon.cpp +platform/android/src/geojson/multi_polygon.hpp +platform/android/src/geojson/point.cpp +platform/android/src/geojson/point.hpp +platform/android/src/geojson/polygon.cpp +platform/android/src/geojson/polygon.hpp + +# Geometry +platform/android/src/geometry/lat_lng.cpp +platform/android/src/geometry/lat_lng.hpp +platform/android/src/geometry/lat_lng_bounds.cpp +platform/android/src/geometry/lat_lng_bounds.hpp +platform/android/src/geometry/lat_lng_quad.cpp +platform/android/src/geometry/lat_lng_quad.hpp +platform/android/src/geometry/projected_meters.cpp +platform/android/src/geometry/projected_meters.hpp + +# GSon +platform/android/src/gson/json_array.cpp +platform/android/src/gson/json_array.hpp +platform/android/src/gson/json_element.cpp +platform/android/src/gson/json_element.hpp +platform/android/src/gson/json_object.cpp +platform/android/src/gson/json_object.hpp +platform/android/src/gson/json_primitive.cpp +platform/android/src/gson/json_primitive.hpp + +# Annotation +platform/android/src/annotation/marker.cpp +platform/android/src/annotation/marker.hpp +platform/android/src/annotation/polygon.cpp +platform/android/src/annotation/polygon.hpp +platform/android/src/annotation/polyline.cpp +platform/android/src/annotation/polyline.hpp + +# Snapshots (SDK) +platform/android/src/snapshotter/map_snapshotter.cpp +platform/android/src/snapshotter/map_snapshotter.hpp +platform/android/src/snapshotter/map_snapshot.cpp +platform/android/src/snapshotter/map_snapshot.hpp + +# Main jni bindings +platform/android/src/attach_env.cpp +platform/android/src/attach_env.hpp +platform/android/src/java_types.cpp +platform/android/src/java_types.hpp + +# Main entry point +platform/android/src/jni.hpp +platform/android/src/jni.cpp diff --git a/platform/android/filesource-files.txt b/platform/android/filesource-files.txt new file mode 100644 index 0000000000..c88db6c725 --- /dev/null +++ b/platform/android/filesource-files.txt @@ -0,0 +1,28 @@ +# File source +platform/android/src/http_file_source.cpp +platform/android/src/asset_manager.hpp +platform/android/src/asset_manager_file_source.cpp +platform/android/src/asset_manager_file_source.hpp + +# FileSource holder +platform/android/src/file_source.cpp +platform/android/src/file_source.hpp + +# Connectivity +platform/android/src/connectivity_listener.cpp +platform/android/src/connectivity_listener.hpp + +# Offline +platform/android/src/offline/offline_manager.cpp +platform/android/src/offline/offline_manager.hpp +platform/android/src/offline/offline_region.cpp +platform/android/src/offline/offline_region.hpp +platform/android/src/offline/offline_region_definition.cpp +platform/android/src/offline/offline_region_definition.hpp +platform/android/src/offline/offline_region_error.cpp +platform/android/src/offline/offline_region_error.hpp +platform/android/src/offline/offline_region_status.cpp +platform/android/src/offline/offline_region_status.hpp + +# Database +platform/default/sqlite3.cpp diff --git a/scripts/generate-cmake-files.js b/scripts/generate-cmake-files.js index 4b6a8b8672..bbbb9accec 100755 --- a/scripts/generate-cmake-files.js +++ b/scripts/generate-cmake-files.js @@ -6,7 +6,7 @@ const ejs = require('ejs'); require('./style-code'); -function generateCMakeListFile(name, regex, patterns) { +function generateFileList(name, regex, patterns) { const files = child_process.execSync(`git ls-files ${patterns.map((p) => '"' + p + '"').join(' ')}`).toString().trim().split('\n'); var groups = {}; for (const file of files) { @@ -18,15 +18,15 @@ function generateCMakeListFile(name, regex, patterns) { groups[group].push(file); } - const fileListCmake = ejs.compile(fs.readFileSync('cmake/files.cmake.ejs', 'utf8'), {strict: true}); - writeIfModified(`cmake/${name}-files.cmake`, fileListCmake({ name: name, groups: groups })); + const fileListCmake = ejs.compile(fs.readFileSync('cmake/files.txt.ejs', 'utf8'), {strict: true}); + writeIfModified(`cmake/${name}-files.txt`, fileListCmake({ groups: groups })); } -generateCMakeListFile('core', /^(?:src|include)\/(?:mbgl\/)?(.+)\/[^\/]+$/, +generateFileList('core', /^(?:src|include)\/(?:mbgl\/)?(.+)\/[^\/]+$/, [ 'include/*.hpp', 'include/*.h', 'src/*.hpp', 'src/*.cpp', 'src/*.h', 'src/*.c' ]); -generateCMakeListFile('benchmark', /^benchmark\/(?:(?:src|include)\/)?(?:mbgl\/)?(?:(.+)\/)?[^\/]+$/, +generateFileList('benchmark', /^benchmark\/(?:(?:src|include)\/)?(?:mbgl\/)?(?:(.+)\/)?[^\/]+$/, [ 'benchmark/*.hpp', 'benchmark/*.cpp', 'benchmark/*.h', 'benchmark/*.c' ]); -generateCMakeListFile('test', /^test\/(?:(?:src|include)\/)?(?:mbgl\/)?(?:(.+)\/)?[^\/]+$/, +generateFileList('test', /^test\/(?:(?:src|include)\/)?(?:mbgl\/)?(?:(.+)\/)?[^\/]+$/, [ 'test/*.hpp', 'test/*.cpp', 'test/*.h', 'test/*.c' ]); -- cgit v1.2.1 From b0fcca5879f1e8ffb0dfd43510e656cd84ca742a Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Mon, 30 Jul 2018 15:22:28 -0700 Subject: [core, node] Re-implement "avoid edges" behavior for MapMode::Tile - Fixes issue #12461. - Only implement "avoid edges" in MapMode::Tile since it's no longer relevant in Static or Continuous mode. - New: Force "avoid edges" to "true" for line labels, since in tile mode they'll always clip poorly at tile boundaries. - Remove unused "withinPlus0/inside" logic. --- src/mbgl/layout/symbol_layout.cpp | 32 +++++++--------------------- src/mbgl/text/collision_index.cpp | 44 +++++++++++++++++++++++++++------------ src/mbgl/text/collision_index.hpp | 14 +++++++++++-- src/mbgl/text/placement.cpp | 11 ++++++++-- 4 files changed, 60 insertions(+), 41 deletions(-) diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp index 41469f293d..ab718351ab 100644 --- a/src/mbgl/layout/symbol_layout.cpp +++ b/src/mbgl/layout/symbol_layout.cpp @@ -258,11 +258,6 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, const float textMaxBoxScale = tilePixelRatio * textMaxSize / glyphSize; const float iconBoxScale = tilePixelRatio * layoutIconSize; const float symbolSpacing = tilePixelRatio * layout.get(); - // CJL: I'm not sure why SymbolPlacementType::Line -> avoidEdges = false. It seems redundant since - // getAnchors will already avoid generating anchors outside the tile bounds. - // However, SymbolPlacementType::LineCenter allows anchors outside tile boundaries, so its behavior - // here should match SymbolPlacement::Point - const bool avoidEdges = layout.get() && layout.get() != SymbolPlacementType::Line; const float textPadding = layout.get() * tilePixelRatio; const float iconPadding = layout.get() * tilePixelRatio; const float textMaxAngle = layout.get() * util::DEG2RAD; @@ -274,25 +269,14 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex, IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketLeaderID, symbolInstances.size()); auto addSymbolInstance = [&] (const GeometryCoordinates& line, Anchor& anchor) { - // https://github.com/mapbox/vector-tile-spec/tree/master/2.1#41-layers - // +-------------------+ Symbols with anchors located on tile edges - // |(0,0) || are duplicated on neighbor tiles. - // | || - // | || In continuous mode, to avoid overdraw we - // | || skip symbols located on the extent edges. - // | Tile || In still mode, we include the features in - // | || the buffers for both tiles and clip them - // | || at draw time. - // | || - // +-------------------| In this scenario, the inner bounding box - // +-------------------+ is called 'withinPlus0', and the outer - // (extent,extent) is called 'inside'. - const bool withinPlus0 = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && anchor.point.y >= 0 && anchor.point.y < util::EXTENT; - const bool inside = withinPlus0 || anchor.point.x == util::EXTENT || anchor.point.y == util::EXTENT; - - if (avoidEdges && !inside) return; - - if (mode == MapMode::Tile || withinPlus0) { + const bool anchorInsideTile = anchor.point.x >= 0 && anchor.point.x < util::EXTENT && anchor.point.y >= 0 && anchor.point.y < util::EXTENT; + + if (mode == MapMode::Tile || anchorInsideTile) { + // For static/continuous rendering, only add symbols anchored within this tile: + // neighboring symbols will be added as part of the neighboring tiles. + // In tiled rendering mode, add all symbols in the buffers so that we can: + // (1) render symbols that overlap into this tile + // (2) approximate collision detection effects from neighboring symbols symbolInstances.emplace_back(anchor, line, shapedTextOrientations, shapedIcon, layout.evaluate(zoom, feature), layoutTextSize, textBoxScale, textPadding, textPlacement, textOffset, diff --git a/src/mbgl/text/collision_index.cpp b/src/mbgl/text/collision_index.cpp index 091840a371..dae789a196 100644 --- a/src/mbgl/text/collision_index.cpp +++ b/src/mbgl/text/collision_index.cpp @@ -62,6 +62,21 @@ bool CollisionIndex::isOffscreen(const CollisionBox& box) const { bool CollisionIndex::isInsideGrid(const CollisionBox& box) const { return box.px2 >= 0 && box.px1 < gridRightBoundary && box.py2 >= 0 && box.py1 < gridBottomBoundary; } + +CollisionTileBoundaries CollisionIndex::projectTileBoundaries(const mat4& posMatrix) const { + Point topLeft = projectPoint(posMatrix, { 0, 0 }); + Point bottomRight = projectPoint(posMatrix, { util::EXTENT, util::EXTENT }); + + return {{ topLeft.x, topLeft.y, bottomRight.x, bottomRight.y }}; + +} + +bool CollisionIndex::isInsideTile(const CollisionBox& box, const CollisionTileBoundaries& tileBoundaries) const { + // This check is only well defined when the tile boundaries are axis-aligned + // We are relying on it only being used in MapMode::Tile, where that is always the case + + return box.px1 >= tileBoundaries[0] && box.py1 >= tileBoundaries[1] && box.px2 < tileBoundaries[2] && box.py2 < tileBoundaries[3]; +} std::pair CollisionIndex::placeFeature(CollisionFeature& feature, @@ -73,7 +88,8 @@ std::pair CollisionIndex::placeFeature(CollisionFeature& feature, const float fontSize, const bool allowOverlap, const bool pitchWithMap, - const bool collisionDebug) { + const bool collisionDebug, + const optional& avoidEdges) { if (!feature.alongLine) { CollisionBox& box = feature.boxes.front(); const auto projectedPoint = projectAndGetPerspectiveRatio(posMatrix, box.anchor); @@ -82,15 +98,17 @@ std::pair CollisionIndex::placeFeature(CollisionFeature& feature, box.py1 = box.y1 * tileToViewport + projectedPoint.first.y; box.px2 = box.x2 * tileToViewport + projectedPoint.first.x; box.py2 = box.y2 * tileToViewport + projectedPoint.first.y; + - if (!isInsideGrid(box) || + if ((avoidEdges && !isInsideTile(box, *avoidEdges)) || + !isInsideGrid(box) || (!allowOverlap && collisionGrid.hitTest({{ box.px1, box.py1 }, { box.px2, box.py2 }}))) { return { false, false }; } return {true, isOffscreen(box)}; } else { - return placeLineFeature(feature, posMatrix, labelPlaneMatrix, textPixelRatio, symbol, scale, fontSize, allowOverlap, pitchWithMap, collisionDebug); + return placeLineFeature(feature, posMatrix, labelPlaneMatrix, textPixelRatio, symbol, scale, fontSize, allowOverlap, pitchWithMap, collisionDebug, avoidEdges); } } @@ -103,7 +121,8 @@ std::pair CollisionIndex::placeLineFeature(CollisionFeature& feature, const float fontSize, const bool allowOverlap, const bool pitchWithMap, - const bool collisionDebug) { + const bool collisionDebug, + const optional& avoidEdges) { const auto tileUnitAnchorPoint = symbol.anchorPoint; const auto projectedAnchor = projectAnchor(posMatrix, tileUnitAnchorPoint); @@ -202,15 +221,14 @@ std::pair CollisionIndex::placeLineFeature(CollisionFeature& feature, entirelyOffscreen &= isOffscreen(circle); inGrid |= isInsideGrid(circle); - if (!allowOverlap) { - if (collisionGrid.hitTest({{circle.px, circle.py}, circle.radius})) { - if (!collisionDebug) { - return {false, false}; - } else { - // Don't early exit if we're showing the debug circles because we still want to calculate - // which circles are in use - collisionDetected = true; - } + if ((avoidEdges && !isInsideTile(circle, *avoidEdges)) || + (!allowOverlap && collisionGrid.hitTest({{circle.px, circle.py}, circle.radius}))) { + if (!collisionDebug) { + return {false, false}; + } else { + // Don't early exit if we're showing the debug circles because we still want to calculate + // which circles are in use + collisionDetected = true; } } } diff --git a/src/mbgl/text/collision_index.hpp b/src/mbgl/text/collision_index.hpp index b2be4c6ade..78782fe61c 100644 --- a/src/mbgl/text/collision_index.hpp +++ b/src/mbgl/text/collision_index.hpp @@ -3,13 +3,18 @@ #include #include #include +#include #include +#include + namespace mbgl { class PlacedSymbol; struct TileDistance; + +using CollisionTileBoundaries = std::array; class CollisionIndex { public: @@ -26,15 +31,19 @@ public: const float fontSize, const bool allowOverlap, const bool pitchWithMap, - const bool collisionDebug); + const bool collisionDebug, + const optional& avoidEdges); void insertFeature(CollisionFeature& feature, bool ignorePlacement, uint32_t bucketInstanceId); std::unordered_map> queryRenderedSymbols(const ScreenLineString&) const; + + CollisionTileBoundaries projectTileBoundaries(const mat4& posMatrix) const; private: bool isOffscreen(const CollisionBox&) const; bool isInsideGrid(const CollisionBox&) const; + bool isInsideTile(const CollisionBox&, const CollisionTileBoundaries& tileBoundaries) const; std::pair placeLineFeature(CollisionFeature& feature, const mat4& posMatrix, @@ -45,7 +54,8 @@ private: const float fontSize, const bool allowOverlap, const bool pitchWithMap, - const bool collisionDebug); + const bool collisionDebug, + const optional& avoidEdges); float approximateTileDistance(const TileDistance& tileDistance, const float lastSegmentAngle, const float pixelsToTileUnits, const float cameraToAnchorDistance, const bool pitchWithMap); diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp index a050be4648..0747133bd2 100644 --- a/src/mbgl/text/placement.cpp +++ b/src/mbgl/text/placement.cpp @@ -110,6 +110,13 @@ void Placement::placeLayerBucket( auto partiallyEvaluatedTextSize = bucket.textSizeBinder->evaluateForZoom(state.getZoom()); auto partiallyEvaluatedIconSize = bucket.iconSizeBinder->evaluateForZoom(state.getZoom()); + optional avoidEdges; + if (mapMode == MapMode::Tile && + (bucket.layout.get() || + bucket.layout.get() == style::SymbolPlacementType::Line)) { + avoidEdges = collisionIndex.projectTileBoundaries(posMatrix); + } + for (auto& symbolInstance : bucket.symbolInstances) { if (seenCrossTileIDs.count(symbolInstance.crossTileID) == 0) { @@ -133,7 +140,7 @@ void Placement::placeLayerBucket( placedSymbol, scale, fontSize, bucket.layout.get(), bucket.layout.get() == style::AlignmentType::Map, - showCollisionBoxes); + showCollisionBoxes, avoidEdges); placeText = placed.first; offscreen &= placed.second; } @@ -147,7 +154,7 @@ void Placement::placeLayerBucket( placedSymbol, scale, fontSize, bucket.layout.get(), bucket.layout.get() == style::AlignmentType::Map, - showCollisionBoxes); + showCollisionBoxes, avoidEdges); placeIcon = placed.first; offscreen &= placed.second; } -- cgit v1.2.1 From 31bdb74f48e8cc796ef28ab9c840c8c04ef54ebf Mon Sep 17 00:00:00 2001 From: Bryan Haber Date: Mon, 26 Feb 2018 12:13:19 -0800 Subject: [build] fixed typo in list of configuration types; RelWithDebugInfo should be RelWithDebInfo - added missing linker flags for Sanitize configuration type - changed mason's download to use cmake's built-in support instead of directly calling curl --- CMakeLists.txt | 6 ++++-- cmake/mason.cmake | 16 +++++++--------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d524f2e754..b007b541b7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -54,7 +54,7 @@ if(WITH_COVERAGE) set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --coverage") endif(WITH_COVERAGE) -set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebugInfo Sanitize) +set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo Sanitize) # Compiler configuration set(CMAKE_CXX_EXTENSIONS OFF) @@ -92,7 +92,6 @@ set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os -DNDEBUG") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -O3 -DNDEBUG") set(CMAKE_CXX_FLAGS_SANITIZE "${CMAKE_CXX_FLAGS_SANITIZE} -O1 -g -fno-omit-frame-pointer -fno-optimize-sibling-calls") - if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-error=unknown-warning-option") elseif(CMAKE_COMPILER_IS_GNUCXX) @@ -100,6 +99,9 @@ elseif(CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fext-numeric-literals") endif() +set(CMAKE_SHARED_LINKER_FLAGS_SANITIZE "${CMAKE_SHARED_LINKER_FLAGS}") +set(CMAKE_EXE_LINKER_FLAGS_SANITIZE "${CMAKE_EXE_LINKER_FLAGS}") + # Technique from https://crascit.com/2016/04/09/using-ccache-with-cmake/ find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) diff --git a/cmake/mason.cmake b/cmake/mason.cmake index 00d268421a..76d02b95b5 100644 --- a/cmake/mason.cmake +++ b/cmake/mason.cmake @@ -84,17 +84,15 @@ function(mason_use _PACKAGE) set(_URL "${MASON_REPOSITORY}/${_SLUG}.tar.gz") message("[Mason] Downloading package ${_URL}...") - set(_FAILED) - set(_ERROR) - # Note: some CMake versions are compiled without SSL support + set(_STATUS) get_filename_component(_CACHE_DIR "${_CACHE_PATH}" DIRECTORY) file(MAKE_DIRECTORY "${_CACHE_DIR}") - execute_process( - COMMAND curl --retry 3 -s -f -S -L "${_URL}" -o "${_CACHE_PATH}.tmp" - RESULT_VARIABLE _FAILED - ERROR_VARIABLE _ERROR) - if(_FAILED) - message(FATAL_ERROR "[Mason] Failed to download ${_URL}: ${_ERROR}") + file(DOWNLOAD "${_URL}" "${_CACHE_PATH}.tmp" STATUS _STATUS TLS_VERIFY ON) + + list(GET _STATUS 0 _STATUS_CODE) + list(GET _STATUS 1 _STATUS_STRING) + if(NOT _STATUS_CODE EQUAL 0) + message(FATAL_ERROR "[Mason] Failed to download ${_URL}: ${_STATUS_STRING}") else() # We downloaded to a temporary file to prevent half-finished downloads file(RENAME "${_CACHE_PATH}.tmp" "${_CACHE_PATH}") -- cgit v1.2.1 From cf0313f21919b0df4840d3085d9db3fe4b6bbbec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Konstantin=20K=C3=A4fer?= Date: Mon, 20 Aug 2018 20:35:42 +0200 Subject: [core] fix static library build --- platform/ios/ios.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index eab0d85417..980fa0321c 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -3854,7 +3854,7 @@ BITCODE_GENERATION_MODE = bitcode; HEADER_SEARCH_PATHS = ( "$(mbgl_core_INCLUDE_DIRECTORIES)", - "$(mbgl_filesource_LINK_LIBRARIES)", + "$(mbgl_filesource_INCLUDE_DIRECTORIES)", ); OTHER_CFLAGS = "-fvisibility=hidden"; OTHER_CPLUSPLUSFLAGS = ( @@ -3885,7 +3885,7 @@ BITCODE_GENERATION_MODE = bitcode; HEADER_SEARCH_PATHS = ( "$(mbgl_core_INCLUDE_DIRECTORIES)", - "$(mbgl_filesource_LINK_LIBRARIES)", + "$(mbgl_filesource_INCLUDE_DIRECTORIES)", ); LLVM_LTO = YES; OTHER_CFLAGS = "-fvisibility=hidden"; -- cgit v1.2.1 From fae099933b23a36176dcc8c4a91c37816fa9b7fe Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Fri, 23 Mar 2018 15:44:21 +0200 Subject: [core] offline region definition - add support for arbitrary geometries --- include/mbgl/storage/offline.hpp | 34 ++++-- platform/default/mbgl/storage/offline.cpp | 133 ++++++++++++--------- platform/default/mbgl/storage/offline_download.cpp | 85 +++++++++++-- test/storage/offline.test.cpp | 74 ++++-------- test/storage/offline_database.test.cpp | 96 +++++++++------ test/storage/offline_download.test.cpp | 2 +- 6 files changed, 257 insertions(+), 167 deletions(-) diff --git a/include/mbgl/storage/offline.hpp b/include/mbgl/storage/offline.hpp index 62353446fa..b4e40cb5f3 100644 --- a/include/mbgl/storage/offline.hpp +++ b/include/mbgl/storage/offline.hpp @@ -1,8 +1,10 @@ #pragma once #include +#include #include #include +#include #include #include @@ -30,22 +32,40 @@ public: OfflineTilePyramidRegionDefinition(std::string, LatLngBounds, double, double, float); /* Private */ - std::vector tileCover(style::SourceType, uint16_t tileSize, const Range& zoomRange) const; - uint64_t tileCount(style::SourceType, uint16_t tileSize, const Range& zoomRange) const; const std::string styleURL; const LatLngBounds bounds; const double minZoom; const double maxZoom; const float pixelRatio; -private: - Range coveringZoomRange(style::SourceType, uint16_t tileSize, const Range& zoomRange) const; }; /* - * For the present, a tile pyramid is the only type of offline region. In the future, - * other definition types will be available and this will be a variant type. + * An offline region defined by a style URL, geometry, zoom range, and + * device pixel ratio. + * + * Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom. + * + * maxZoom may be ∞, in which case for each tile source, the region will include + * tiles from minZoom up to the maximum zoom level provided by that source. + * + * pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0. + */ +class OfflineGeometryRegionDefinition { +public: + OfflineGeometryRegionDefinition(std::string styleURL, Geometry, double minZoom, double maxZoom, float pixelRatio); + + /* Private */ + const std::string styleURL; + const Geometry geometry; + const double minZoom; + const double maxZoom; + const float pixelRatio; +}; + +/* + * The offline region definition types supported */ -using OfflineRegionDefinition = OfflineTilePyramidRegionDefinition; +using OfflineRegionDefinition = variant; /* * The encoded format is private. diff --git a/platform/default/mbgl/storage/offline.cpp b/platform/default/mbgl/storage/offline.cpp index 598a0b182b..e1ec0acb31 100644 --- a/platform/default/mbgl/storage/offline.cpp +++ b/platform/default/mbgl/storage/offline.cpp @@ -1,8 +1,10 @@ #include -#include #include #include +#include +#include + #include #include #include @@ -11,6 +13,8 @@ namespace mbgl { +// OfflineTilePyramidRegionDefinition + OfflineTilePyramidRegionDefinition::OfflineTilePyramidRegionDefinition( std::string styleURL_, LatLngBounds bounds_, double minZoom_, double maxZoom_, float pixelRatio_) : styleURL(std::move(styleURL_)), @@ -24,87 +28,100 @@ OfflineTilePyramidRegionDefinition::OfflineTilePyramidRegionDefinition( } } -std::vector OfflineTilePyramidRegionDefinition::tileCover(style::SourceType type, uint16_t tileSize, const Range& zoomRange) const { - const Range clampedZoomRange = coveringZoomRange(type, tileSize, zoomRange); - std::vector result; - - for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) { - for (const auto& tile : util::tileCover(bounds, z)) { - result.emplace_back(tile.canonical); - } - } - - return result; -} +// OfflineGeometryRegionDefinition -uint64_t OfflineTilePyramidRegionDefinition::tileCount(style::SourceType type, uint16_t tileSize, const Range& zoomRange) const { - - const Range clampedZoomRange = coveringZoomRange(type, tileSize, zoomRange); - unsigned long result = 0;; - for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) { - result += util::tileCount(bounds, z); +OfflineGeometryRegionDefinition::OfflineGeometryRegionDefinition(std::string styleURL_, Geometry geometry_, double minZoom_, double maxZoom_, float pixelRatio_) + : styleURL(styleURL_) + , geometry(std::move(geometry_)) + , minZoom(minZoom_) + , maxZoom(maxZoom_) + , pixelRatio(pixelRatio_) { + if (minZoom < 0 || maxZoom < 0 || maxZoom < minZoom || pixelRatio < 0 || + !std::isfinite(minZoom) || std::isnan(maxZoom) || !std::isfinite(pixelRatio)) { + throw std::invalid_argument("Invalid offline region definition"); } - - return result; -} - -Range OfflineTilePyramidRegionDefinition::coveringZoomRange(style::SourceType type, uint16_t tileSize, const Range& zoomRange) const { - double minZ = std::max(util::coveringZoomLevel(minZoom, type, tileSize), zoomRange.min); - double maxZ = std::min(util::coveringZoomLevel(maxZoom, type, tileSize), zoomRange.max); - - assert(minZ >= 0); - assert(maxZ >= 0); - assert(minZ < std::numeric_limits::max()); - assert(maxZ < std::numeric_limits::max()); - return { static_cast(minZ), static_cast(maxZ) }; } OfflineRegionDefinition decodeOfflineRegionDefinition(const std::string& region) { rapidjson::GenericDocument, rapidjson::CrtAllocator> doc; doc.Parse<0>(region.c_str()); - if (doc.HasParseError() || - !doc.HasMember("style_url") || !doc["style_url"].IsString() || - !doc.HasMember("bounds") || !doc["bounds"].IsArray() || doc["bounds"].Size() != 4 || - !doc["bounds"][0].IsDouble() || !doc["bounds"][1].IsDouble() || - !doc["bounds"][2].IsDouble() || !doc["bounds"][3].IsDouble() || - !doc.HasMember("min_zoom") || !doc["min_zoom"].IsDouble() || - (doc.HasMember("max_zoom") && !doc["max_zoom"].IsDouble()) || - !doc.HasMember("pixel_ratio") || !doc["pixel_ratio"].IsDouble()) { + // validation + + auto hasValidBounds = [&] { + return doc.HasMember("bounds") && doc["bounds"].IsArray() && doc["bounds"].Size() == 4 + && doc["bounds"][0].IsDouble() && doc["bounds"][1].IsDouble() + && doc["bounds"][2].IsDouble() && doc["bounds"][3].IsDouble(); + }; + + auto hasValidGeometry = [&] { + return doc.HasMember("geometry") && doc["geometry"].IsObject(); + }; + + if (doc.HasParseError() + || !doc.HasMember("style_url") || !doc["style_url"].IsString() + || !(hasValidBounds() || hasValidGeometry()) + || !doc.HasMember("min_zoom") || !doc["min_zoom"].IsDouble() + || (doc.HasMember("max_zoom") && !doc["max_zoom"].IsDouble()) + || !doc.HasMember("pixel_ratio") || !doc["pixel_ratio"].IsDouble()) { throw std::runtime_error("Malformed offline region definition"); } + // Common properties + std::string styleURL { doc["style_url"].GetString(), doc["style_url"].GetStringLength() }; - LatLngBounds bounds = LatLngBounds::hull( - LatLng(doc["bounds"][0].GetDouble(), doc["bounds"][1].GetDouble()), - LatLng(doc["bounds"][2].GetDouble(), doc["bounds"][3].GetDouble())); double minZoom = doc["min_zoom"].GetDouble(); double maxZoom = doc.HasMember("max_zoom") ? doc["max_zoom"].GetDouble() : INFINITY; float pixelRatio = doc["pixel_ratio"].GetDouble(); + + if (doc.HasMember("bounds")) { + return OfflineTilePyramidRegionDefinition{ + styleURL, + LatLngBounds::hull( + LatLng(doc["bounds"][0].GetDouble(), doc["bounds"][1].GetDouble()), + LatLng(doc["bounds"][2].GetDouble(), doc["bounds"][3].GetDouble())), + minZoom, maxZoom, pixelRatio }; + } else { + return OfflineGeometryRegionDefinition{ + styleURL, + mapbox::geojson::convert>(doc["geometry"].GetObject()), + minZoom, maxZoom, pixelRatio }; + }; - return { styleURL, bounds, minZoom, maxZoom, pixelRatio }; } std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition& region) { rapidjson::GenericDocument, rapidjson::CrtAllocator> doc; doc.SetObject(); - doc.AddMember("style_url", rapidjson::StringRef(region.styleURL.data(), region.styleURL.length()), doc.GetAllocator()); + // Encode common properties + region.match([&](auto& _region) { + doc.AddMember("style_url", rapidjson::StringRef(_region.styleURL.data(), _region.styleURL.length()), doc.GetAllocator()); + doc.AddMember("min_zoom", _region.minZoom, doc.GetAllocator()); + if (std::isfinite(_region.maxZoom)) { + doc.AddMember("max_zoom", _region.maxZoom, doc.GetAllocator()); + } - rapidjson::GenericValue, rapidjson::CrtAllocator> bounds(rapidjson::kArrayType); - bounds.PushBack(region.bounds.south(), doc.GetAllocator()); - bounds.PushBack(region.bounds.west(), doc.GetAllocator()); - bounds.PushBack(region.bounds.north(), doc.GetAllocator()); - bounds.PushBack(region.bounds.east(), doc.GetAllocator()); - doc.AddMember("bounds", bounds, doc.GetAllocator()); + doc.AddMember("pixel_ratio", _region.pixelRatio, doc.GetAllocator()); + }); - doc.AddMember("min_zoom", region.minZoom, doc.GetAllocator()); - if (std::isfinite(region.maxZoom)) { - doc.AddMember("max_zoom", region.maxZoom, doc.GetAllocator()); - } + // Encode specific properties + region.match( + [&] (const OfflineTilePyramidRegionDefinition& _region) { + rapidjson::GenericValue, rapidjson::CrtAllocator> bounds(rapidjson::kArrayType); + bounds.PushBack(_region.bounds.south(), doc.GetAllocator()); + bounds.PushBack(_region.bounds.west(), doc.GetAllocator()); + bounds.PushBack(_region.bounds.north(), doc.GetAllocator()); + bounds.PushBack(_region.bounds.east(), doc.GetAllocator()); + doc.AddMember("bounds", bounds, doc.GetAllocator()); + + }, + [&] (const OfflineGeometryRegionDefinition& _region) { + doc.AddMember("geometry", mapbox::geojson::convert(_region.geometry, doc.GetAllocator()), doc.GetAllocator()); - doc.AddMember("pixel_ratio", region.pixelRatio, doc.GetAllocator()); + } + ); rapidjson::StringBuffer buffer; rapidjson::Writer writer(buffer); @@ -113,6 +130,9 @@ std::string encodeOfflineRegionDefinition(const OfflineRegionDefinition& region) return buffer.GetString(); } + +// OfflineRegion + OfflineRegion::OfflineRegion(int64_t id_, OfflineRegionDefinition definition_, OfflineRegionMetadata metadata_) @@ -135,5 +155,4 @@ const OfflineRegionMetadata& OfflineRegion::getMetadata() const { int64_t OfflineRegion::getID() const { return id; } - } // namespace mbgl diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp index 179d2d5f57..118f3aad88 100644 --- a/platform/default/mbgl/storage/offline_download.cpp +++ b/platform/default/mbgl/storage/offline_download.cpp @@ -24,6 +24,63 @@ namespace mbgl { using namespace style; +// Generic functions + +template +Range coveringZoomRange(const RegionDefinition& definition, + style::SourceType type, uint16_t tileSize, const Range& zoomRange) { + double minZ = std::max(util::coveringZoomLevel(definition.minZoom, type, tileSize), zoomRange.min); + double maxZ = std::min(util::coveringZoomLevel(definition.maxZoom, type, tileSize), zoomRange.max); + + assert(minZ >= 0); + assert(maxZ >= 0); + assert(minZ < std::numeric_limits::max()); + assert(maxZ < std::numeric_limits::max()); + return { static_cast(minZ), static_cast(maxZ) }; +} + +template +void tileCover(const Geometry& geometry, uint8_t z, Fn&& fn) { + util::TileCover cover(geometry, z); + while (cover.hasNext()) { + fn(cover.next()->canonical); + } +} + + +template +void tileCover(const OfflineRegionDefinition& definition, style::SourceType type, + uint16_t tileSize, const Range& zoomRange, Fn&& fn) { + const Range clampedZoomRange = + definition.match([&](auto& reg) { return coveringZoomRange(reg, type, tileSize, zoomRange); }); + + for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) { + definition.match( + [&](const OfflineTilePyramidRegionDefinition& reg){ tileCover(reg.bounds, z, fn); }, + [&](const OfflineGeometryRegionDefinition& reg){ tileCover(reg.geometry, z, fn); } + ); + } +} + +uint64_t tileCount(const OfflineRegionDefinition& definition, style::SourceType type, + uint16_t tileSize, const Range& zoomRange) { + + const Range clampedZoomRange = + definition.match([&](auto& reg) { return coveringZoomRange(reg, type, tileSize, zoomRange); }); + + unsigned long result = 0;; + for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) { + result += definition.match( + [&](const OfflineTilePyramidRegionDefinition& reg){ return util::tileCount(reg.bounds, z); }, + [&](const OfflineGeometryRegionDefinition& reg){ return util::tileCount(reg.geometry, z); } + ); + } + + return result; +} + +// OfflineDownload + OfflineDownload::OfflineDownload(int64_t id_, OfflineRegionDefinition&& definition_, OfflineDatabase& offlineDatabase_, @@ -70,7 +127,8 @@ OfflineRegionStatus OfflineDownload::getStatus() const { } result->requiredResourceCount++; - optional styleResponse = offlineDatabase.get(Resource::style(definition.styleURL)); + optional styleResponse = + offlineDatabase.get(Resource::style(definition.match([](auto& reg){ return reg.styleURL; }))); if (!styleResponse) { return *result; } @@ -86,7 +144,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const { auto handleTiledSource = [&] (const variant& urlOrTileset, const uint16_t tileSize) { if (urlOrTileset.is()) { result->requiredResourceCount += - definition.tileCount(type, tileSize, urlOrTileset.get().zoomRange); + tileCount(definition, type, tileSize, urlOrTileset.get().zoomRange); } else { result->requiredResourceCount += 1; const auto& url = urlOrTileset.get(); @@ -96,7 +154,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const { optional tileset = style::conversion::convertJSON(*sourceResponse->data, error); if (tileset) { result->requiredResourceCount += - definition.tileCount(type, tileSize, (*tileset).zoomRange); + tileCount(definition, type, tileSize, (*tileset).zoomRange); } } else { result->requiredResourceCountIsPrecise = false; @@ -116,7 +174,7 @@ OfflineRegionStatus OfflineDownload::getStatus() const { handleTiledSource(rasterSource.getURLOrTileset(), rasterSource.getTileSize()); break; } - + case SourceType::RasterDEM: { const auto& rasterDEMSource = *source->as(); handleTiledSource(rasterDEMSource.getURLOrTileset(), rasterDEMSource.getTileSize()); @@ -161,7 +219,8 @@ void OfflineDownload::activateDownload() { status = OfflineRegionStatus(); status.downloadState = OfflineRegionDownloadState::Active; status.requiredResourceCount++; - ensureResource(Resource::style(definition.styleURL), [&](Response styleResponse) { + ensureResource(Resource::style(definition.match([](auto& reg){ return reg.styleURL; })), + [&](Response styleResponse) { status.requiredResourceCountIsPrecise = true; style::Parser parser; @@ -207,7 +266,7 @@ void OfflineDownload::activateDownload() { handleTiledSource(rasterSource.getURLOrTileset(), rasterSource.getTileSize()); break; } - + case SourceType::RasterDEM: { const auto& rasterDEMSource = *source->as(); handleTiledSource(rasterDEMSource.getURLOrTileset(), rasterDEMSource.getTileSize()); @@ -247,8 +306,9 @@ void OfflineDownload::activateDownload() { } if (!parser.spriteURL.empty()) { - queueResource(Resource::spriteImage(parser.spriteURL, definition.pixelRatio)); - queueResource(Resource::spriteJSON(parser.spriteURL, definition.pixelRatio)); + auto pixelRatio = definition.match([](auto& reg){ return reg.pixelRatio; }); + queueResource(Resource::spriteImage(parser.spriteURL, pixelRatio)); + queueResource(Resource::spriteJSON(parser.spriteURL, pixelRatio)); } continueDownload(); @@ -296,11 +356,12 @@ void OfflineDownload::queueResource(Resource resource) { } void OfflineDownload::queueTiles(SourceType type, uint16_t tileSize, const Tileset& tileset) { - for (const auto& tile : definition.tileCover(type, tileSize, tileset.zoomRange)) { + tileCover(definition, type, tileSize, tileset.zoomRange, [&](const auto& tile) { status.requiredResourceCount++; - resourcesRemaining.push_back( - Resource::tile(tileset.tiles[0], definition.pixelRatio, tile.x, tile.y, tile.z, tileset.scheme)); - } + resourcesRemaining.push_back(Resource::tile( + tileset.tiles[0], definition.match([](auto& def) { return def.pixelRatio; }), tile.x, + tile.y, tile.z, tileset.scheme)); + }); } void OfflineDownload::ensureResource(const Resource& resource, diff --git a/test/storage/offline.test.cpp b/test/storage/offline.test.cpp index 59aebebaba..90f9570320 100644 --- a/test/storage/offline.test.cpp +++ b/test/storage/offline.test.cpp @@ -6,58 +6,30 @@ using namespace mbgl; using SourceType = mbgl::style::SourceType; -static const LatLngBounds sanFrancisco = - LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 }); -static const LatLngBounds sanFranciscoWrapped = - LatLngBounds::hull({ 37.6609, 238.5744 }, { 37.8271, 238.3204 }); - -TEST(OfflineTilePyramidRegionDefinition, TileCoverEmpty) { - OfflineTilePyramidRegionDefinition region("", LatLngBounds::empty(), 0, 20, 1.0); - - EXPECT_EQ((std::vector{}), region.tileCover(SourceType::Vector, 512, { 0, 22 })); -} - -TEST(OfflineTilePyramidRegionDefinition, TileCoverZoomIntersection) { - OfflineTilePyramidRegionDefinition region("", sanFrancisco, 2, 2, 1.0); - - EXPECT_EQ((std::vector{ { 2, 0, 1 } }), - region.tileCover(SourceType::Vector, 512, { 0, 22 })); - - EXPECT_EQ((std::vector{}), region.tileCover(SourceType::Vector, 512, { 3, 22 })); -} - -TEST(OfflineTilePyramidRegionDefinition, TileCoverTileSize) { - OfflineTilePyramidRegionDefinition region("", LatLngBounds::world(), 0, 0, 1.0); - - EXPECT_EQ((std::vector{ { 0, 0, 0 } }), - region.tileCover(SourceType::Vector, 512, { 0, 22 })); - - EXPECT_EQ((std::vector{ { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 } }), - region.tileCover(SourceType::Vector, 256, { 0, 22 })); -} - -TEST(OfflineTilePyramidRegionDefinition, TileCoverZoomRounding) { - OfflineTilePyramidRegionDefinition region("", sanFrancisco, 0.6, 0.7, 1.0); - - EXPECT_EQ((std::vector{ { 0, 0, 0 } }), - region.tileCover(SourceType::Vector, 512, { 0, 22 })); - - EXPECT_EQ((std::vector{ { 1, 0, 0 } }), - region.tileCover(SourceType::Raster, 512, { 0, 22 })); +TEST(OfflineTilePyramidRegionDefinition, EncodeDecode) { + OfflineTilePyramidRegionDefinition region("mapbox://style", LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 }), 0, 20, 1.0); + + auto encoded = encodeOfflineRegionDefinition(region); + auto decoded = decodeOfflineRegionDefinition(encoded).get(); + + EXPECT_EQ(decoded.styleURL, region.styleURL); + EXPECT_EQ(decoded.minZoom, region.minZoom); + EXPECT_EQ(decoded.maxZoom, region.maxZoom); + EXPECT_EQ(decoded.pixelRatio, region.pixelRatio); + EXPECT_EQ(decoded.bounds.southwest(), region.bounds.southwest()); + EXPECT_EQ(decoded.bounds.northeast(), region.bounds.northeast()); } -TEST(OfflineTilePyramidRegionDefinition, TileCoverWrapped) { - OfflineTilePyramidRegionDefinition region("", sanFranciscoWrapped, 0, 0, 1.0); - - EXPECT_EQ((std::vector{ { 0, 0, 0 } }), - region.tileCover(SourceType::Vector, 512, { 0, 22 })); -} - -TEST(OfflineTilePyramidRegionDefinition, TileCount) { - OfflineTilePyramidRegionDefinition region("", sanFranciscoWrapped, 0, 22, 1.0); - - //These numbers match the count from tileCover().size(). - EXPECT_EQ(38424u, region.tileCount(SourceType::Vector, 512, { 10, 18 })); - EXPECT_EQ(9675240u, region.tileCount(SourceType::Vector, 512, { 3, 22 })); +TEST(OfflineGeometryRegionDefinition, EncodeDecode) { + OfflineGeometryRegionDefinition region("mapbox://style", Point(-122.5744, 37.6609), 0, 2, 1.0); + + auto encoded = encodeOfflineRegionDefinition(region); + auto decoded = decodeOfflineRegionDefinition(encoded).get(); + + EXPECT_EQ(decoded.styleURL, region.styleURL); + EXPECT_EQ(decoded.minZoom, region.minZoom); + EXPECT_EQ(decoded.maxZoom, region.maxZoom); + EXPECT_EQ(decoded.pixelRatio, region.pixelRatio); + EXPECT_EQ(decoded.geometry, region.geometry); } diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp index 346cd6da80..2ed72e0d8c 100644 --- a/test/storage/offline_database.test.cpp +++ b/test/storage/offline_database.test.cpp @@ -411,25 +411,31 @@ TEST(OfflineDatabase, PutTileNotFound) { TEST(OfflineDatabase, CreateRegion) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; auto region = db.createRegion(definition, metadata); ASSERT_TRUE(region); - EXPECT_EQ(definition.styleURL, region->getDefinition().styleURL); - EXPECT_EQ(definition.bounds, region->getDefinition().bounds); - EXPECT_EQ(definition.minZoom, region->getDefinition().minZoom); - EXPECT_EQ(definition.maxZoom, region->getDefinition().maxZoom); - EXPECT_EQ(definition.pixelRatio, region->getDefinition().pixelRatio); - EXPECT_EQ(metadata, region->getMetadata()); - EXPECT_EQ(0u, log.uncheckedCount()); + + region->getDefinition().match( + [&](OfflineTilePyramidRegionDefinition& def) { + EXPECT_EQ(definition.styleURL, def.styleURL); + EXPECT_EQ(definition.bounds, def.bounds); + EXPECT_EQ(definition.minZoom, def.minZoom); + EXPECT_EQ(definition.maxZoom, def.maxZoom); + EXPECT_EQ(definition.pixelRatio, def.pixelRatio); + }, [](auto&) { + EXPECT_FALSE(false); + } + ); + EXPECT_EQ(metadata, region->getMetadata()); } TEST(OfflineDatabase, UpdateMetadata) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; auto region = db.createRegion(definition, metadata); ASSERT_TRUE(region); @@ -445,7 +451,7 @@ TEST(OfflineDatabase, UpdateMetadata) { TEST(OfflineDatabase, ListRegions) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; auto region = db.createRegion(definition, metadata); @@ -453,12 +459,19 @@ TEST(OfflineDatabase, ListRegions) { auto regions = db.listRegions().value(); ASSERT_EQ(1u, regions.size()); + EXPECT_EQ(region->getID(), regions.at(0).getID()); - EXPECT_EQ(definition.styleURL, regions.at(0).getDefinition().styleURL); - EXPECT_EQ(definition.bounds, regions.at(0).getDefinition().bounds); - EXPECT_EQ(definition.minZoom, regions.at(0).getDefinition().minZoom); - EXPECT_EQ(definition.maxZoom, regions.at(0).getDefinition().maxZoom); - EXPECT_EQ(definition.pixelRatio, regions.at(0).getDefinition().pixelRatio); + regions.at(0).getDefinition().match( + [&](OfflineTilePyramidRegionDefinition& def) { + EXPECT_EQ(definition.styleURL, def.styleURL); + EXPECT_EQ(definition.bounds, def.bounds); + EXPECT_EQ(definition.minZoom, def.minZoom); + EXPECT_EQ(definition.maxZoom, def.maxZoom); + EXPECT_EQ(definition.pixelRatio, def.pixelRatio); + }, + [&](auto&) { + EXPECT_FALSE(false); + }); EXPECT_EQ(metadata, regions.at(0).getMetadata()); EXPECT_EQ(0u, log.uncheckedCount()); @@ -467,27 +480,30 @@ TEST(OfflineDatabase, ListRegions) { TEST(OfflineDatabase, GetRegionDefinition) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; - auto region = db.createRegion(definition, metadata); - ASSERT_TRUE(region); - auto result = db.getRegionDefinition(region->getID()); - ASSERT_TRUE(result); - - EXPECT_EQ(definition.styleURL, result->styleURL); - EXPECT_EQ(definition.bounds, result->bounds); - EXPECT_EQ(definition.minZoom, result->minZoom); - EXPECT_EQ(definition.maxZoom, result->maxZoom); - EXPECT_EQ(definition.pixelRatio, result->pixelRatio); - EXPECT_EQ(0u, log.uncheckedCount()); + + auto region = db.createRegion(definition, metadata); + db.getRegionDefinition(region->getID())->match( + [&](OfflineTilePyramidRegionDefinition& result) { + EXPECT_EQ(definition.styleURL, result.styleURL); + EXPECT_EQ(definition.bounds, result.bounds); + EXPECT_EQ(definition.minZoom, result.minZoom); + EXPECT_EQ(definition.maxZoom, result.maxZoom); + EXPECT_EQ(definition.pixelRatio, result.pixelRatio); + }, + [&](auto&) { + EXPECT_FALSE(false); + } + ); } TEST(OfflineDatabase, DeleteRegion) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata {{ 1, 2, 3 }}; auto region = db.createRegion(definition, metadata); ASSERT_TRUE(region); @@ -509,15 +525,17 @@ TEST(OfflineDatabase, DeleteRegion) { TEST(OfflineDatabase, CreateRegionInfiniteMaxZoom) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; OfflineRegionMetadata metadata; auto region = db.createRegion(definition, metadata); ASSERT_TRUE(region); - EXPECT_EQ(0, region->getDefinition().minZoom); - EXPECT_EQ(INFINITY, region->getDefinition().maxZoom); - EXPECT_EQ(0u, log.uncheckedCount()); + + region->getDefinition().match([&](auto& def) { + EXPECT_EQ(0, def.minZoom); + EXPECT_EQ(INFINITY, def.maxZoom); + }); } TEST(OfflineDatabase, TEST_REQUIRES_WRITE(ConcurrentUse)) { @@ -600,7 +618,7 @@ TEST(OfflineDatabase, PutEvictsLeastRecentlyUsedResources) { TEST(OfflineDatabase, PutRegionResourceDoesNotEvict) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; auto region = db.createRegion(definition, OfflineRegionMetadata()); ASSERT_TRUE(region); @@ -637,7 +655,7 @@ TEST(OfflineDatabase, PutFailsWhenEvictionInsuffices) { TEST(OfflineDatabase, GetRegionCompletedStatus) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata; auto region = db.createRegion(definition, metadata); ASSERT_TRUE(region); @@ -676,7 +694,7 @@ TEST(OfflineDatabase, GetRegionCompletedStatus) { TEST(OfflineDatabase, HasRegionResource) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; auto region = db.createRegion(definition, OfflineRegionMetadata()); ASSERT_TRUE(region); @@ -700,7 +718,7 @@ TEST(OfflineDatabase, HasRegionResource) { TEST(OfflineDatabase, HasRegionResourceTile) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; auto region = db.createRegion(definition, OfflineRegionMetadata()); ASSERT_TRUE(region); @@ -734,7 +752,7 @@ TEST(OfflineDatabase, HasRegionResourceTile) { TEST(OfflineDatabase, OfflineMapboxTileCount) { FixtureLog log; OfflineDatabase db(":memory:"); - OfflineRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; + OfflineTilePyramidRegionDefinition definition { "http://example.com/style", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 2.0 }; OfflineRegionMetadata metadata; auto region1 = db.createRegion(definition, metadata); @@ -795,7 +813,7 @@ TEST(OfflineDatabase, OfflineMapboxTileCount) { TEST(OfflineDatabase, BatchInsertion) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; auto region = db.createRegion(definition, OfflineRegionMetadata()); ASSERT_TRUE(region); @@ -821,7 +839,7 @@ TEST(OfflineDatabase, BatchInsertionMapboxTileCountExceeded) { FixtureLog log; OfflineDatabase db(":memory:", 1024 * 100); db.setOfflineMapboxTileCountLimit(1); - OfflineRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::world(), 0, INFINITY, 1.0 }; auto region = db.createRegion(definition, OfflineRegionMetadata()); ASSERT_TRUE(region); diff --git a/test/storage/offline_download.test.cpp b/test/storage/offline_download.test.cpp index 93b4dd623a..492e68e869 100644 --- a/test/storage/offline_download.test.cpp +++ b/test/storage/offline_download.test.cpp @@ -66,7 +66,7 @@ public: std::size_t size = 0; auto createRegion() { - OfflineRegionDefinition definition { "", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 1.0 }; + OfflineTilePyramidRegionDefinition definition { "", LatLngBounds::hull({1, 2}, {3, 4}), 5, 6, 1.0 }; OfflineRegionMetadata metadata; return db.createRegion(definition, metadata); } -- cgit v1.2.1 From 4fedcf8d061d835e71df80dbc20a32ee4ec8fd21 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Mon, 26 Mar 2018 21:33:52 +0300 Subject: [android] arbitrary offline region geometries --- platform/android/MapboxGLAndroidSDK/build.gradle | 1 + .../offline/OfflineGeometryRegionDefinition.java | 128 +++++++++++++++++++++ platform/android/src/jni.cpp | 1 + platform/android/src/offline/offline_manager.cpp | 6 +- platform/android/src/offline/offline_region.cpp | 9 +- .../src/offline/offline_region_definition.cpp | 68 ++++++++++- .../src/offline/offline_region_definition.hpp | 17 ++- 7 files changed, 223 insertions(+), 7 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index 0529489783..5a505af959 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -10,6 +10,7 @@ dependencies { api (dependenciesList.mapboxAndroidGestures) { exclude group: 'com.android.support', module: 'appcompat-v7' } + implementation dependenciesList.mapboxJavaTurf implementation dependenciesList.supportAnnotations implementation dependenciesList.supportFragmentV4 implementation dependenciesList.timber diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java new file mode 100644 index 0000000000..0db3ee3202 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition.java @@ -0,0 +1,128 @@ +package com.mapbox.mapboxsdk.offline; + +import android.os.Parcel; +import android.os.Parcelable; + +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.Geometry; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; +import com.mapbox.turf.TurfMeasurement; + +/** + * An offline region defined by a style URL, geometry, zoom range, and + * device pixel ratio. + *

+ * Both minZoom and maxZoom must be ≥ 0, and maxZoom must be ≥ minZoom. + *

+ * maxZoom may be ∞, in which case for each tile source, the region will include + * tiles from minZoom up to the maximum zoom level provided by that source. + *

+ * pixelRatio must be ≥ 0 and should typically be 1.0 or 2.0. + */ +public class OfflineGeometryRegionDefinition implements OfflineRegionDefinition, Parcelable { + + private String styleURL; + private Geometry geometry; + private double minZoom; + private double maxZoom; + private float pixelRatio; + + /** + * Constructor to create an OfflineGeometryRegionDefinition from parameters. + * + * @param styleURL the style + * @param geometry the geometry + * @param minZoom min zoom + * @param maxZoom max zoom + * @param pixelRatio pixel ratio of the device + */ + public OfflineGeometryRegionDefinition( + String styleURL, Geometry geometry, double minZoom, double maxZoom, float pixelRatio) { + // Note: Also used in JNI + this.styleURL = styleURL; + this.geometry = geometry; + this.minZoom = minZoom; + this.maxZoom = maxZoom; + this.pixelRatio = pixelRatio; + } + + /** + * Constructor to create an OfflineGeometryRegionDefinition from a Parcel. + * + * @param parcel the parcel to create the OfflineGeometryRegionDefinition from + */ + public OfflineGeometryRegionDefinition(Parcel parcel) { + this.styleURL = parcel.readString(); + this.geometry = Feature.fromJson(parcel.readString()).geometry(); + this.minZoom = parcel.readDouble(); + this.maxZoom = parcel.readDouble(); + this.pixelRatio = parcel.readFloat(); + } + + /* + * Getters + */ + + public String getStyleURL() { + return styleURL; + } + + public Geometry getGeometry() { + return geometry; + } + + /** + * Calculates the bounding box for the Geometry it contains + * to retain backwards compatibility + * @return the {@link LatLngBounds} or null + */ + @Override + public LatLngBounds getBounds() { + if (geometry == null) { + return null; + } + + double[] bbox = TurfMeasurement.bbox(geometry); + return LatLngBounds.from(bbox[3], bbox[2], bbox[1], bbox[0]); + } + + public double getMinZoom() { + return minZoom; + } + + public double getMaxZoom() { + return maxZoom; + } + + public float getPixelRatio() { + return pixelRatio; + } + + /* + * Parceable + */ + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(styleURL); + dest.writeString(Feature.fromGeometry(geometry).toJson()); + dest.writeDouble(minZoom); + dest.writeDouble(maxZoom); + dest.writeFloat(pixelRatio); + } + + public static final Creator CREATOR = new Creator() { + public OfflineGeometryRegionDefinition createFromParcel(Parcel in) { + return new OfflineGeometryRegionDefinition(in); + } + + public OfflineGeometryRegionDefinition[] newArray(int size) { + return new OfflineGeometryRegionDefinition[size]; + } + }; +} diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp index beb2c14eb3..18b966e261 100755 --- a/platform/android/src/jni.cpp +++ b/platform/android/src/jni.cpp @@ -180,6 +180,7 @@ void registerNatives(JavaVM *vm) { OfflineRegion::registerNative(env); OfflineRegionDefinition::registerNative(env); OfflineTilePyramidRegionDefinition::registerNative(env); + OfflineGeometryRegionDefinition::registerNative(env); OfflineRegionError::registerNative(env); OfflineRegionStatus::registerNative(env); diff --git a/platform/android/src/offline/offline_manager.cpp b/platform/android/src/offline/offline_manager.cpp index 4f94a1c3a5..e96ed7e4d2 100644 --- a/platform/android/src/offline/offline_manager.cpp +++ b/platform/android/src/offline/offline_manager.cpp @@ -48,9 +48,7 @@ void OfflineManager::createOfflineRegion(jni::JNIEnv& env_, jni::Array metadata_, jni::Object callback_) { // Convert - - // XXX hardcoded cast for now as we only support OfflineTilePyramidRegionDefinition - auto definition = OfflineTilePyramidRegionDefinition::getDefinition(env_, jni::Object(*definition_)); + auto definition = OfflineRegionDefinition::getDefinition(env_, definition_); mbgl::OfflineRegionMetadata metadata; if (metadata_) { @@ -152,7 +150,7 @@ void OfflineManager::CreateOfflineRegionCallback::onCreate(jni::JNIEnv& env, jni::Object jFileSource, jni::Object callback, mbgl::optional region) { - //Convert the region to java peer object + // Convert the region to java peer object auto jregion = OfflineRegion::New(env, jFileSource, std::move(*region)); // Trigger callback diff --git a/platform/android/src/offline/offline_region.cpp b/platform/android/src/offline/offline_region.cpp index fe4dbecf14..5ed37eda73 100644 --- a/platform/android/src/offline/offline_region.cpp +++ b/platform/android/src/offline/offline_region.cpp @@ -159,7 +159,14 @@ void OfflineRegion::updateOfflineRegionMetadata(jni::JNIEnv& env_, jni::Array OfflineRegion::New(jni::JNIEnv& env, jni::Object jFileSource, mbgl::OfflineRegion region) { // Definition - auto definition = jni::Object(*OfflineTilePyramidRegionDefinition::New(env, region.getDefinition())); + auto definition = region.getDefinition().match( + [&](const mbgl::OfflineTilePyramidRegionDefinition def) { + return jni::Object( + *OfflineTilePyramidRegionDefinition::New(env, def)); + }, [&](const mbgl::OfflineGeometryRegionDefinition def) { + return jni::Object( + *OfflineGeometryRegionDefinition::New(env, def)); + }); // Metadata auto metadata = OfflineRegion::metadata(env, region.getMetadata()); diff --git a/platform/android/src/offline/offline_region_definition.cpp b/platform/android/src/offline/offline_region_definition.cpp index 66a9bdf99d..a856672902 100644 --- a/platform/android/src/offline/offline_region_definition.cpp +++ b/platform/android/src/offline/offline_region_definition.cpp @@ -1,6 +1,9 @@ #include "offline_region_definition.hpp" #include "../geometry/lat_lng_bounds.hpp" +#include "../geojson/geometry.hpp" + +#include namespace mbgl { namespace android { @@ -13,9 +16,21 @@ void OfflineRegionDefinition::registerNative(jni::JNIEnv& env) { javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); } +mbgl::OfflineRegionDefinition OfflineRegionDefinition::getDefinition(JNIEnv& env, + jni::Object jDefinition) { + + if (jDefinition.IsInstanceOf(env, OfflineTilePyramidRegionDefinition::javaClass)) { + return OfflineTilePyramidRegionDefinition::getDefinition(env, jni::Object(*jDefinition)); + } else if (jDefinition.IsInstanceOf(env, OfflineGeometryRegionDefinition::javaClass)) { + return OfflineGeometryRegionDefinition::getDefinition(env, jni::Object(*jDefinition)); + } + + throw std::runtime_error("Unknown offline region definition java class"); +} + // OfflineTilePyramidRegionDefinition // -jni::Object OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, mbgl::OfflineTilePyramidRegionDefinition definition) { +jni::Object OfflineTilePyramidRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineTilePyramidRegionDefinition& definition) { //Convert objects auto styleURL = jni::Make(env, definition.styleURL); @@ -65,5 +80,56 @@ void OfflineTilePyramidRegionDefinition::registerNative(jni::JNIEnv& env) { javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); } +// OfflineGeometryRegionDefinition // + +jni::Object OfflineGeometryRegionDefinition::New(jni::JNIEnv& env, const mbgl::OfflineGeometryRegionDefinition& definition) { + //Convert objects + auto styleURL = jni::Make(env, definition.styleURL); + auto geometry = geojson::Geometry::New(env, definition.geometry); + + static auto constructor = javaClass.GetConstructor, jni::jdouble, jni::jdouble, jni::jfloat>(env); + auto jdefinition = javaClass.New(env, constructor, styleURL, geometry, definition.minZoom, definition.maxZoom, definition.pixelRatio); + + //Delete References + jni::DeleteLocalRef(env, styleURL); + jni::DeleteLocalRef(env, geometry); + + return jdefinition; +} + +mbgl::OfflineGeometryRegionDefinition OfflineGeometryRegionDefinition::getDefinition(jni::JNIEnv& env, jni::Object jDefinition) { + // Field references + static auto styleURLF = javaClass.GetField(env, "styleURL"); + static auto geometryF = javaClass.GetField>(env, "geometry"); + static auto minZoomF = javaClass.GetField(env, "minZoom"); + static auto maxZoomF = javaClass.GetField(env, "maxZoom"); + static auto pixelRatioF = javaClass.GetField(env, "pixelRatio"); + + // Get objects + auto jStyleURL = jDefinition.Get(env, styleURLF); + auto jGeometry = jDefinition.Get(env, geometryF); + + // Create definition + mbgl::OfflineGeometryRegionDefinition definition( + jni::Make(env, jStyleURL), + geojson::Geometry::convert(env, jGeometry), + jDefinition.Get(env, minZoomF), + jDefinition.Get(env, maxZoomF), + jDefinition.Get(env, pixelRatioF) + ); + + // Delete references + jni::DeleteLocalRef(env, jStyleURL); + jni::DeleteLocalRef(env, jGeometry); + + return definition; +} + +jni::Class OfflineGeometryRegionDefinition::javaClass; + +void OfflineGeometryRegionDefinition::registerNative(jni::JNIEnv& env) { + javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); +} + } // namespace android } // namespace mbgl diff --git a/platform/android/src/offline/offline_region_definition.hpp b/platform/android/src/offline/offline_region_definition.hpp index 2ca82a4d96..a9dfb54634 100644 --- a/platform/android/src/offline/offline_region_definition.hpp +++ b/platform/android/src/offline/offline_region_definition.hpp @@ -14,13 +14,14 @@ public: static void registerNative(jni::JNIEnv&); + static mbgl::OfflineRegionDefinition getDefinition(JNIEnv& env, jni::Object jDefinition); }; class OfflineTilePyramidRegionDefinition: public OfflineRegionDefinition { public: static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineTilePyramidRegionDefinition"; }; - static jni::Object New(jni::JNIEnv&, mbgl::OfflineTilePyramidRegionDefinition); + static jni::Object New(jni::JNIEnv&, const mbgl::OfflineTilePyramidRegionDefinition&); static mbgl::OfflineTilePyramidRegionDefinition getDefinition(jni::JNIEnv&, jni::Object); @@ -30,5 +31,19 @@ public: }; +class OfflineGeometryRegionDefinition: public OfflineRegionDefinition { +public: + static constexpr auto Name() { return "com/mapbox/mapboxsdk/offline/OfflineGeometryRegionDefinition"; }; + + static jni::Object New(jni::JNIEnv&, const mbgl::OfflineGeometryRegionDefinition&); + + static mbgl::OfflineGeometryRegionDefinition getDefinition(jni::JNIEnv&, jni::Object); + + static jni::Class javaClass; + + static void registerNative(jni::JNIEnv&); + +}; + } // namespace android } // namespace mbgl -- cgit v1.2.1 From ca0f2f925d38c190957241f7fa2375a90fa87f45 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Tue, 27 Mar 2018 00:39:59 +0300 Subject: [darwin] arbitrary offline region geometries --- platform/darwin/src/MGLOfflinePack.mm | 21 +++- platform/darwin/src/MGLOfflineRegion.h | 15 ++- platform/darwin/src/MGLOfflineRegion_Private.h | 9 -- platform/darwin/src/MGLOfflineStorage.mm | 2 +- platform/darwin/src/MGLShapeOfflineRegion.h | 72 +++++++++++++ platform/darwin/src/MGLShapeOfflineRegion.mm | 120 +++++++++++++++++++++ .../darwin/src/MGLShapeOfflineRegion_Private.h | 22 ++++ platform/darwin/src/MGLTilePyramidOfflineRegion.h | 14 +-- platform/darwin/src/MGLTilePyramidOfflineRegion.mm | 5 +- .../src/MGLTilePyramidOfflineRegion_Private.h | 22 ++++ platform/darwin/test/MGLOfflineRegionTests.m | 18 +++- platform/darwin/test/MGLOfflineStorageTests.mm | 74 ++++++++++++- platform/ios/CHANGELOG.md | 1 + platform/ios/ios.xcodeproj/project.pbxproj | 24 +++++ platform/ios/src/Mapbox.h | 1 + platform/macos/CHANGELOG.md | 1 + platform/macos/macos.xcodeproj/project.pbxproj | 16 +++ platform/macos/src/Mapbox.h | 1 + 18 files changed, 409 insertions(+), 29 deletions(-) create mode 100644 platform/darwin/src/MGLShapeOfflineRegion.h create mode 100644 platform/darwin/src/MGLShapeOfflineRegion.mm create mode 100644 platform/darwin/src/MGLShapeOfflineRegion_Private.h create mode 100644 platform/darwin/src/MGLTilePyramidOfflineRegion_Private.h diff --git a/platform/darwin/src/MGLOfflinePack.mm b/platform/darwin/src/MGLOfflinePack.mm index 7bbc681c88..bafb976585 100644 --- a/platform/darwin/src/MGLOfflinePack.mm +++ b/platform/darwin/src/MGLOfflinePack.mm @@ -3,6 +3,9 @@ #import "MGLOfflineStorage_Private.h" #import "MGLOfflineRegion_Private.h" #import "MGLTilePyramidOfflineRegion.h" +#import "MGLTilePyramidOfflineRegion_Private.h" +#import "MGLShapeOfflineRegion.h" +#import "MGLShapeOfflineRegion_Private.h" #import "NSValue+MGLAdditions.h" @@ -27,6 +30,12 @@ const MGLExceptionName MGLInvalidOfflinePackException = @"MGLInvalidOfflinePackE } \ } while (NO); +@interface MGLTilePyramidOfflineRegion () +@end + +@interface MGLShapeOfflineRegion () +@end + class MBGLOfflineRegionObserver : public mbgl::OfflineRegionObserver { public: MBGLOfflineRegionObserver(MGLOfflinePack *pack_) : pack(pack_) {} @@ -78,7 +87,17 @@ private: const mbgl::OfflineRegionDefinition ®ionDefinition = _mbglOfflineRegion->getDefinition(); NSAssert([MGLTilePyramidOfflineRegion conformsToProtocol:@protocol(MGLOfflineRegion_Private)], @"MGLTilePyramidOfflineRegion should conform to MGLOfflineRegion_Private."); - return [(id )[MGLTilePyramidOfflineRegion alloc] initWithOfflineRegionDefinition:regionDefinition]; + NSAssert([MGLShapeOfflineRegion conformsToProtocol:@protocol(MGLOfflineRegion_Private)], @"MGLShapeOfflineRegion should conform to MGLOfflineRegion_Private."); + + + + return regionDefinition.match( + [&] (const mbgl::OfflineTilePyramidRegionDefinition def){ + return (id )[[MGLTilePyramidOfflineRegion alloc] initWithOfflineRegionDefinition:def]; + }, + [&] (const mbgl::OfflineGeometryRegionDefinition& def){ + return (id )[[MGLShapeOfflineRegion alloc] initWithOfflineRegionDefinition:def]; + }); } - (NSData *)context { diff --git a/platform/darwin/src/MGLOfflineRegion.h b/platform/darwin/src/MGLOfflineRegion.h index fe0ab6cb7f..3e0f485e2c 100644 --- a/platform/darwin/src/MGLOfflineRegion.h +++ b/platform/darwin/src/MGLOfflineRegion.h @@ -4,12 +4,21 @@ NS_ASSUME_NONNULL_BEGIN /** An object conforming to the `MGLOfflineRegion` protocol determines which - resources are required by an `MGLOfflinePack` object. At present, only - instances of `MGLTilePyramidOfflineRegion` may be used as `MGLOfflinePack` - regions, but additional conforming implementations may be added in the future. + resources are required by an `MGLOfflinePack` object. */ @protocol MGLOfflineRegion +/** + URL of the style whose resources are required for offline viewing. + + In addition to the JSON stylesheet, different styles may require different font + glyphs, sprite sheets, and other resources. + + The URL may be a full HTTP or HTTPS URL or a Mapbox URL indicating the style’s + map ID (`mapbox://styles/{user}/{style}`). + */ +@property (nonatomic, readonly) NSURL *styleURL; + @end NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLOfflineRegion_Private.h b/platform/darwin/src/MGLOfflineRegion_Private.h index b1dec8dd64..c1f3fd5200 100644 --- a/platform/darwin/src/MGLOfflineRegion_Private.h +++ b/platform/darwin/src/MGLOfflineRegion_Private.h @@ -8,15 +8,6 @@ NS_ASSUME_NONNULL_BEGIN @protocol MGLOfflineRegion_Private -/** - Initializes and returns an offline region backed by the given C++ region - definition object. - - @param definition A reference to an offline region definition backing the - offline region. - */ -- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineRegionDefinition &)definition; - /** Creates and returns a C++ offline region definition corresponding to the receiver. diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm index 05e1b06338..93a6da36c4 100644 --- a/platform/darwin/src/MGLOfflineStorage.mm +++ b/platform/darwin/src/MGLOfflineStorage.mm @@ -285,7 +285,7 @@ const MGLExceptionName MGLUnsupportedRegionTypeException = @"MGLUnsupportedRegio return; } - const mbgl::OfflineTilePyramidRegionDefinition regionDefinition = [(id )region offlineRegionDefinition]; + const mbgl::OfflineRegionDefinition regionDefinition = [(id )region offlineRegionDefinition]; mbgl::OfflineRegionMetadata metadata(context.length); [context getBytes:&metadata[0] length:metadata.size()]; self.mbglFileSource->createOfflineRegion(regionDefinition, metadata, [&, completion](mbgl::expected mbglOfflineRegion) { diff --git a/platform/darwin/src/MGLShapeOfflineRegion.h b/platform/darwin/src/MGLShapeOfflineRegion.h new file mode 100644 index 0000000000..ac54dc137b --- /dev/null +++ b/platform/darwin/src/MGLShapeOfflineRegion.h @@ -0,0 +1,72 @@ +#import + +#import "MGLFoundation.h" +#import "MGLOfflineRegion.h" +#import "MGLShape.h" + +NS_ASSUME_NONNULL_BEGIN + +/** + An offline region defined by a style URL, geographic shape, and + range of zoom levels. + + This class requires fewer resources than MGLTilePyramidOfflineRegion + for irregularly shaped regions. + */ +MGL_EXPORT +@interface MGLShapeOfflineRegion : NSObject + +/** + The shape for the geographic region covered by the downloaded + tiles. + */ +@property (nonatomic, readonly) MGLShape *shape; + +/** + The minimum zoom level for which to download tiles and other resources. + + For more information about zoom levels, `-[MGLMapView zoomLevel]`. + */ +@property (nonatomic, readonly) double minimumZoomLevel; + +/** + The maximum zoom level for which to download tiles and other resources. + + For more information about zoom levels, `-[MGLMapView zoomLevel]`. + */ +@property (nonatomic, readonly) double maximumZoomLevel; + +- (instancetype)init NS_UNAVAILABLE; + +/** + Initializes a newly created offline region with the given style URL, geometry, + and range of zoom levels. + + This is the designated initializer for `MGLShapeOfflineRegion`. + + @param styleURL URL of the map style for which to download resources. The URL + may be a full HTTP or HTTPS URL or a Mapbox URL indicating the style’s map + ID (`mapbox://styles/{user}/{style}`). Specify `nil` for the default style. + Relative file URLs cannot be used as offline style URLs. To download the + online resources required by a local style, specify a URL to an online copy + of the style. + @param shape The shape of the geographic region to be covered by + the downloaded tiles. + @param minimumZoomLevel The minimum zoom level to be covered by the downloaded + tiles. This parameter should be set to at least 0 but no greater than the + value of the `maximumZoomLevel` parameter. For each required tile source, if + this parameter is set to a value less than the tile source’s minimum zoom + level, the download covers zoom levels down to the tile source’s minimum + zoom level. + @param maximumZoomLevel The maximum zoom level to be covered by the downloaded + tiles. This parameter should be set to at least the value of the + `minimumZoomLevel` parameter. For each required tile source, if this + parameter is set to a value greater than the tile source’s minimum zoom + level, the download covers zoom levels up to the tile source’s maximum zoom + level. + */ +- (instancetype)initWithStyleURL:(nullable NSURL *)styleURL shape:(MGLShape *)shape fromZoomLevel:(double)minimumZoomLevel toZoomLevel:(double)maximumZoomLevel NS_DESIGNATED_INITIALIZER; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLShapeOfflineRegion.mm b/platform/darwin/src/MGLShapeOfflineRegion.mm new file mode 100644 index 0000000000..e1393f1199 --- /dev/null +++ b/platform/darwin/src/MGLShapeOfflineRegion.mm @@ -0,0 +1,120 @@ +#import "MGLShapeOfflineRegion.h" + +#if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR + #import +#else + #import +#endif + +#import "MGLOfflineRegion_Private.h" +#import "MGLShapeOfflineRegion_Private.h" +#import "MGLFeature_Private.h" +#import "MGLShape_Private.h" +#import "MGLStyle.h" + +@interface MGLShapeOfflineRegion () + +@end + +@implementation MGLShapeOfflineRegion { + NSURL *_styleURL; +} + +@synthesize styleURL = _styleURL; + ++ (BOOL)supportsSecureCoding { + return YES; +} + +- (instancetype)init { + [NSException raise:@"Method unavailable" + format: + @"-[MGLShapeOfflineRegion init] is unavailable. " + @"Use -initWithStyleURL:shape:fromZoomLevel:toZoomLevel: instead."]; + return nil; +} + +- (instancetype)initWithStyleURL:(NSURL *)styleURL shape:(MGLShape *)shape fromZoomLevel:(double)minimumZoomLevel toZoomLevel:(double)maximumZoomLevel { + if (self = [super init]) { + if (!styleURL) { + styleURL = [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion]; + } + + if (!styleURL.scheme) { + [NSException raise:@"Invalid style URL" format: + @"%@ does not support setting a relative file URL as the style URL. " + @"To download the online resources required by this style, " + @"specify a URL to an online copy of this style. " + @"For Mapbox-hosted styles, use the mapbox: scheme.", + NSStringFromClass([self class])]; + } + + _styleURL = styleURL; + _shape = shape; + _minimumZoomLevel = minimumZoomLevel; + _maximumZoomLevel = maximumZoomLevel; + } + return self; +} + +- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineGeometryRegionDefinition &)definition { + NSURL *styleURL = [NSURL URLWithString:@(definition.styleURL.c_str())]; + MGLShape *shape = MGLShapeFromGeoJSON(definition.geometry); + return [self initWithStyleURL:styleURL shape:shape fromZoomLevel:definition.minZoom toZoomLevel:definition.maxZoom]; +} + +- (const mbgl::OfflineRegionDefinition)offlineRegionDefinition { +#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR + const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale]; +#elif TARGET_OS_MAC + const float scaleFactor = [NSScreen mainScreen].backingScaleFactor; +#endif + return mbgl::OfflineGeometryRegionDefinition(_styleURL.absoluteString.UTF8String, + _shape.geometryObject, + _minimumZoomLevel, _maximumZoomLevel, + scaleFactor); +} + +- (nullable instancetype)initWithCoder:(NSCoder *)coder { + NSURL *styleURL = [coder decodeObjectForKey:@"styleURL"]; + MGLShape * shape = [coder decodeObjectForKey:@"shape"]; + double minimumZoomLevel = [coder decodeDoubleForKey:@"minimumZoomLevel"]; + double maximumZoomLevel = [coder decodeDoubleForKey:@"maximumZoomLevel"]; + + return [self initWithStyleURL:styleURL shape:shape fromZoomLevel:minimumZoomLevel toZoomLevel:maximumZoomLevel]; +} + +- (void)encodeWithCoder:(NSCoder *)coder +{ + [coder encodeObject:_styleURL forKey:@"styleURL"]; + [coder encodeObject:_shape forKey:@"shape"]; + [coder encodeDouble:_maximumZoomLevel forKey:@"maximumZoomLevel"]; + [coder encodeDouble:_minimumZoomLevel forKey:@"minimumZoomLevel"]; +} + +- (id)copyWithZone:(nullable NSZone *)zone { + return [[[self class] allocWithZone:zone] initWithStyleURL:_styleURL shape:_shape fromZoomLevel:_minimumZoomLevel toZoomLevel:_maximumZoomLevel]; +} + +- (BOOL)isEqual:(id)other { + if (other == self) { + return YES; + } + if (![other isKindOfClass:[self class]]) { + return NO; + } + + MGLShapeOfflineRegion *otherRegion = other; + return (_minimumZoomLevel == otherRegion->_minimumZoomLevel + && _maximumZoomLevel == otherRegion->_maximumZoomLevel + && _shape.geometryObject == otherRegion->_shape.geometryObject + && [_styleURL isEqual:otherRegion->_styleURL]); +} + +- (NSUInteger)hash { + return (_styleURL.hash + + _shape.hash + + @(_minimumZoomLevel).hash + @(_maximumZoomLevel).hash); +} + +@end diff --git a/platform/darwin/src/MGLShapeOfflineRegion_Private.h b/platform/darwin/src/MGLShapeOfflineRegion_Private.h new file mode 100644 index 0000000000..2ab44ad405 --- /dev/null +++ b/platform/darwin/src/MGLShapeOfflineRegion_Private.h @@ -0,0 +1,22 @@ +#import + +#import "MGLOfflineRegion.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@protocol MGLShapeOfflineRegion_Private + +/** + Initializes and returns an offline region backed by the given C++ region + definition object. + + @param definition A reference to an offline region definition backing the + offline region. + */ +- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineGeometryRegionDefinition &)definition; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/src/MGLTilePyramidOfflineRegion.h b/platform/darwin/src/MGLTilePyramidOfflineRegion.h index 31e5a41920..4fbb68dbc6 100644 --- a/platform/darwin/src/MGLTilePyramidOfflineRegion.h +++ b/platform/darwin/src/MGLTilePyramidOfflineRegion.h @@ -9,21 +9,13 @@ NS_ASSUME_NONNULL_BEGIN /** An offline region defined by a style URL, geographic coordinate bounds, and range of zoom levels. + + To minimize the resources required by an irregularly shaped offline region, + use the MGLShapeOfflineRegion class instead. */ MGL_EXPORT @interface MGLTilePyramidOfflineRegion : NSObject -/** - URL of the style whose resources are required for offline viewing. - - In addition to the JSON stylesheet, different styles may require different font - glyphs, sprite sheets, and other resources. - - The URL may be a full HTTP or HTTPS URL or a Mapbox URL indicating the style’s - map ID (`mapbox://styles/{user}/{style}`). - */ -@property (nonatomic, readonly) NSURL *styleURL; - /** The coordinate bounds for the geographic region covered by the downloaded tiles. diff --git a/platform/darwin/src/MGLTilePyramidOfflineRegion.mm b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm index 7333703267..0766d224da 100644 --- a/platform/darwin/src/MGLTilePyramidOfflineRegion.mm +++ b/platform/darwin/src/MGLTilePyramidOfflineRegion.mm @@ -5,10 +5,11 @@ #endif #import "MGLOfflineRegion_Private.h" +#import "MGLTilePyramidOfflineRegion_Private.h" #import "MGLGeometry_Private.h" #import "MGLStyle.h" -@interface MGLTilePyramidOfflineRegion () +@interface MGLTilePyramidOfflineRegion () @end @@ -52,7 +53,7 @@ return self; } -- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineRegionDefinition &)definition { +- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineTilePyramidRegionDefinition &)definition { NSURL *styleURL = [NSURL URLWithString:@(definition.styleURL.c_str())]; MGLCoordinateBounds bounds = MGLCoordinateBoundsFromLatLngBounds(definition.bounds); return [self initWithStyleURL:styleURL bounds:bounds fromZoomLevel:definition.minZoom toZoomLevel:definition.maxZoom]; diff --git a/platform/darwin/src/MGLTilePyramidOfflineRegion_Private.h b/platform/darwin/src/MGLTilePyramidOfflineRegion_Private.h new file mode 100644 index 0000000000..90d8e05477 --- /dev/null +++ b/platform/darwin/src/MGLTilePyramidOfflineRegion_Private.h @@ -0,0 +1,22 @@ +#import + +#import "MGLOfflineRegion.h" + +#include + +NS_ASSUME_NONNULL_BEGIN + +@protocol MGLTilePyramidOfflineRegion_Private + +/** + Initializes and returns an offline region backed by the given C++ region + definition object. + + @param definition A reference to an offline region definition backing the + offline region. + */ +- (instancetype)initWithOfflineRegionDefinition:(const mbgl::OfflineTilePyramidRegionDefinition &)definition; + +@end + +NS_ASSUME_NONNULL_END diff --git a/platform/darwin/test/MGLOfflineRegionTests.m b/platform/darwin/test/MGLOfflineRegionTests.m index da9928741b..eac6da9b54 100644 --- a/platform/darwin/test/MGLOfflineRegionTests.m +++ b/platform/darwin/test/MGLOfflineRegionTests.m @@ -17,7 +17,7 @@ XCTAssertThrowsSpecificNamed([[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:localURL bounds:bounds fromZoomLevel:0 toZoomLevel:DBL_MAX], NSException, MGLInvalidStyleURLException, @"No exception raised when initializing region with a local file URL as the style URL."); } -- (void)testEquality { +- (void)testTilePyramidRegionEquality { MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(kCLLocationCoordinate2DInvalid, kCLLocationCoordinate2DInvalid); MGLTilePyramidOfflineRegion *original = [[MGLTilePyramidOfflineRegion alloc] initWithStyleURL:[MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion] bounds:bounds fromZoomLevel:5 toZoomLevel:10]; MGLTilePyramidOfflineRegion *copy = [original copy]; @@ -29,4 +29,20 @@ XCTAssertEqual(original.maximumZoomLevel, original.maximumZoomLevel, @"Maximum zoom level has changed."); } +- (void)testGeometryRegionEquality { + NSString *geojson = @"{\"type\": \"Point\", \"coordinates\": [-3.8671874999999996, 52.482780222078226] }"; + NSError *error; + MGLShape *shape = [MGLShape shapeWithData: [geojson dataUsingEncoding:NSUTF8StringEncoding] encoding: NSUTF8StringEncoding error:&error]; + XCTAssertNil(error); + + MGLShapeOfflineRegion *original = [[MGLShapeOfflineRegion alloc] initWithStyleURL:[MGLStyle lightStyleURLWithVersion:MGLStyleDefaultVersion] shape:shape fromZoomLevel:5 toZoomLevel:10]; + MGLShapeOfflineRegion *copy = [original copy]; + XCTAssertEqualObjects(original, copy, @"Shape region should be equal to its copy."); + + XCTAssertEqualObjects(original.styleURL, copy.styleURL, @"Style URL has changed."); + XCTAssertEqualObjects(original.shape, copy.shape, @"Geometry has changed."); + XCTAssertEqual(original.minimumZoomLevel, original.minimumZoomLevel, @"Minimum zoom level has changed."); + XCTAssertEqual(original.maximumZoomLevel, original.maximumZoomLevel, @"Maximum zoom level has changed."); +} + @end diff --git a/platform/darwin/test/MGLOfflineStorageTests.mm b/platform/darwin/test/MGLOfflineStorageTests.mm index 28c6633028..e9e2467f21 100644 --- a/platform/darwin/test/MGLOfflineStorageTests.mm +++ b/platform/darwin/test/MGLOfflineStorageTests.mm @@ -36,7 +36,7 @@ XCTAssertEqual([MGLOfflineStorage sharedOfflineStorage], [MGLOfflineStorage sharedOfflineStorage], @"There should only be one shared offline storage object."); } -- (void)testAddPack { +- (void)testAddPackForBounds { NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count; NSURL *styleURL = [MGLStyle lightStyleURLWithVersion:8]; @@ -109,6 +109,78 @@ [self waitForExpectationsWithTimeout:1 handler:nil]; } +- (void)testAddPackForGeometry { + NSUInteger countOfPacks = [MGLOfflineStorage sharedOfflineStorage].packs.count; + + NSURL *styleURL = [MGLStyle lightStyleURLWithVersion:8]; + double zoomLevel = 20; + NSString *geojson = @"{ \"type\": \"Polygon\", \"coordinates\": [ [ [ 5.1299285888671875, 52.10365839097971 ], [ 5.103063583374023, 52.110037078604236 ], [ 5.080232620239258, 52.09548601177304 ], [ 5.106925964355469, 52.07987524347506 ], [ 5.1299285888671875, 52.10365839097971 ] ] ]}"; + NSError *error; + MGLShape *shape = [MGLShape shapeWithData: [geojson dataUsingEncoding:NSUTF8StringEncoding] encoding: NSUTF8StringEncoding error:&error]; + XCTAssertNil(error); + MGLShapeOfflineRegion *region = [[MGLShapeOfflineRegion alloc] initWithStyleURL:styleURL shape:shape fromZoomLevel:zoomLevel toZoomLevel:zoomLevel]; + + + NSString *nameKey = @"Name"; + NSString *name = @"Utrecht centrum"; + + NSData *context = [NSKeyedArchiver archivedDataWithRootObject:@{nameKey: name}]; + + __block MGLOfflinePack *pack; + [self keyValueObservingExpectationForObject:[MGLOfflineStorage sharedOfflineStorage] keyPath:@"packs" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) { + const auto changeKind = static_cast([change[NSKeyValueChangeKindKey] unsignedLongValue]); + NSIndexSet *indices = change[NSKeyValueChangeIndexesKey]; + return changeKind == NSKeyValueChangeInsertion && indices.count == 1; + }]; + XCTestExpectation *additionCompletionHandlerExpectation = [self expectationWithDescription:@"add pack completion handler"]; + [[MGLOfflineStorage sharedOfflineStorage] addPackForRegion:region withContext:context completionHandler:^(MGLOfflinePack * _Nullable completionHandlerPack, NSError * _Nullable error) { + XCTAssertNotNil(completionHandlerPack, @"Added pack should exist."); + XCTAssertEqual(completionHandlerPack.state, MGLOfflinePackStateInactive, @"New pack should initially have inactive state."); + pack = completionHandlerPack; + [additionCompletionHandlerExpectation fulfill]; + }]; + [self waitForExpectationsWithTimeout:2 handler:nil]; + + XCTAssertEqual([MGLOfflineStorage sharedOfflineStorage].packs.count, countOfPacks + 1, @"Added pack should have been added to the canonical collection of packs owned by the shared offline storage object. This assertion can fail if this test is run before -testAAALoadPacks."); + + XCTAssertEqual(pack, [MGLOfflineStorage sharedOfflineStorage].packs.lastObject, @"Pack should be appended to end of packs array."); + + XCTAssertEqualObjects(pack.region, region, @"Added pack’s region has changed."); + + NSDictionary *userInfo = [NSKeyedUnarchiver unarchiveObjectWithData:pack.context]; + XCTAssert([userInfo isKindOfClass:[NSDictionary class]], @"Context of offline pack isn’t a dictionary."); + XCTAssert([userInfo[nameKey] isKindOfClass:[NSString class]], @"Name of offline pack isn’t a string."); + XCTAssertEqualObjects(userInfo[nameKey], name, @"Name of offline pack has changed."); + + XCTAssertEqual(pack.state, MGLOfflinePackStateInactive, @"New pack should initially have inactive state."); + + [self keyValueObservingExpectationForObject:pack keyPath:@"state" handler:^BOOL(id _Nonnull observedObject, NSDictionary * _Nonnull change) { + const auto changeKind = static_cast([change[NSKeyValueChangeKindKey] unsignedLongValue]); + const auto state = static_cast([change[NSKeyValueChangeNewKey] longValue]); + return changeKind == NSKeyValueChangeSetting && state == MGLOfflinePackStateInactive; + }]; + [self expectationForNotification:MGLOfflinePackProgressChangedNotification object:pack handler:^BOOL(NSNotification * _Nonnull notification) { + MGLOfflinePack *notificationPack = notification.object; + XCTAssert([notificationPack isKindOfClass:[MGLOfflinePack class]], @"Object of notification should be an MGLOfflinePack."); + + NSDictionary *userInfo = notification.userInfo; + XCTAssertNotNil(userInfo, @"Progress change notification should have a userInfo dictionary."); + + NSNumber *stateNumber = userInfo[MGLOfflinePackUserInfoKeyState]; + XCTAssert([stateNumber isKindOfClass:[NSNumber class]], @"Progress change notification’s state should be an NSNumber."); + XCTAssertEqual(stateNumber.integerValue, pack.state, @"State in a progress change notification should match the pack’s state."); + + NSValue *progressValue = userInfo[MGLOfflinePackUserInfoKeyProgress]; + XCTAssert([progressValue isKindOfClass:[NSValue class]], @"Progress change notification’s progress should be an NSValue."); + XCTAssertEqualObjects(progressValue, [NSValue valueWithMGLOfflinePackProgress:pack.progress], @"Progress change notification’s progress should match pack’s progress."); + + return notificationPack == pack && pack.state == MGLOfflinePackStateInactive; + }]; + [pack requestProgress]; + [self waitForExpectationsWithTimeout:1 handler:nil]; + pack = nil; +} + - (void)testBackupExclusion { NSURL *cacheDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory inDomain:NSUserDomainMask diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index 0bb97eaec3..edebf57dc6 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -8,6 +8,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * When a symbol in an `MGLSymbolStyleLayer` has both an icon and text, both are shown or hidden together based on available space. ([#12521](https://github.com/mapbox/mapbox-gl-native/pull/12521)) * The `-[MGLMapView visibleFeaturesAtPoint:]` method can now return features near tile boundaries at high zoom levels. ([#12570](https://github.com/mapbox/mapbox-gl-native/pull/12570)) * Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) +* Added `MGLShapeOfflineRegion` for defining arbitrarily shaped offline regions [#11447](https://github.com/mapbox/mapbox-gl-native/pull/11447) ## 4.3.0 - August 15, 2018 diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj index 980fa0321c..3875d46865 100644 --- a/platform/ios/ios.xcodeproj/project.pbxproj +++ b/platform/ios/ios.xcodeproj/project.pbxproj @@ -294,6 +294,8 @@ 8989B17E201A48EB0081CF59 /* MGLHeatmapStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8989B17B201A48EA0081CF59 /* MGLHeatmapStyleLayer.mm */; }; 8989B17F201A48EB0081CF59 /* MGLHeatmapStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 8989B17B201A48EA0081CF59 /* MGLHeatmapStyleLayer.mm */; }; 920A3E5D1E6F995200C16EFC /* MGLSourceQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */; }; + 9221BAAD2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9221BAAC2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */; }; + 9221BAB020699F8A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9221BAAC2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */; }; 927FBCFC1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 927FBCFB1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m */; }; 927FBCFF1F4DB05500F8BF1F /* MGLMapSnapshotter.h in Headers */ = {isa = PBXBuildFile; fileRef = 927FBCFD1F4DB05500F8BF1F /* MGLMapSnapshotter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 927FBD001F4DB05500F8BF1F /* MGLMapSnapshotter.h in Headers */ = {isa = PBXBuildFile; fileRef = 927FBCFD1F4DB05500F8BF1F /* MGLMapSnapshotter.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -301,6 +303,12 @@ 927FBD021F4DB05500F8BF1F /* MGLMapSnapshotter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 927FBCFE1F4DB05500F8BF1F /* MGLMapSnapshotter.mm */; }; 929EFFAB1F56DCD4003A77D5 /* MGLAnnotationView.mm in Sources */ = {isa = PBXBuildFile; fileRef = 4018B1C41CDC277F00F666AF /* MGLAnnotationView.mm */; }; 92F2C3ED1F0E3C3A00268EC0 /* MGLRendererFrontend.h in Headers */ = {isa = PBXBuildFile; fileRef = 92F2C3EC1F0E3C3A00268EC0 /* MGLRendererFrontend.h */; }; + 92FC0AEA207CEE16007B6B54 /* MGLShapeOfflineRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = 92FC0AE7207CEE16007B6B54 /* MGLShapeOfflineRegion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 92FC0AEB207CEE16007B6B54 /* MGLShapeOfflineRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = 92FC0AE7207CEE16007B6B54 /* MGLShapeOfflineRegion.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 92FC0AEC207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 92FC0AE8207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h */; }; + 92FC0AED207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 92FC0AE8207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h */; }; + 92FC0AEE207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92FC0AE9207CEE16007B6B54 /* MGLShapeOfflineRegion.mm */; }; + 92FC0AEF207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92FC0AE9207CEE16007B6B54 /* MGLShapeOfflineRegion.mm */; }; 96036A01200565C700510F3D /* NSOrthography+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 960369FF200565C700510F3D /* NSOrthography+MGLAdditions.h */; }; 96036A02200565C700510F3D /* NSOrthography+MGLAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 960369FF200565C700510F3D /* NSOrthography+MGLAdditions.h */; }; 96036A03200565C700510F3D /* NSOrthography+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 96036A00200565C700510F3D /* NSOrthography+MGLAdditions.m */; }; @@ -973,11 +981,15 @@ 8989B17A201A48EA0081CF59 /* MGLHeatmapStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLHeatmapStyleLayer.h; sourceTree = ""; }; 8989B17B201A48EA0081CF59 /* MGLHeatmapStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLHeatmapStyleLayer.mm; sourceTree = ""; }; 920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLSourceQueryTests.m; path = ../../darwin/test/MGLSourceQueryTests.m; sourceTree = ""; }; + 9221BAAC2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTilePyramidOfflineRegion_Private.h; sourceTree = ""; }; 927FBCFA1F4DAA8300F8BF1F /* MBXSnapshotsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBXSnapshotsViewController.h; sourceTree = ""; }; 927FBCFB1F4DAA8300F8BF1F /* MBXSnapshotsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBXSnapshotsViewController.m; sourceTree = ""; }; 927FBCFD1F4DB05500F8BF1F /* MGLMapSnapshotter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapSnapshotter.h; sourceTree = ""; }; 927FBCFE1F4DB05500F8BF1F /* MGLMapSnapshotter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapSnapshotter.mm; sourceTree = ""; }; 92F2C3EC1F0E3C3A00268EC0 /* MGLRendererFrontend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRendererFrontend.h; sourceTree = ""; }; + 92FC0AE7207CEE16007B6B54 /* MGLShapeOfflineRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeOfflineRegion.h; sourceTree = ""; }; + 92FC0AE8207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeOfflineRegion_Private.h; sourceTree = ""; }; + 92FC0AE9207CEE16007B6B54 /* MGLShapeOfflineRegion.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLShapeOfflineRegion.mm; sourceTree = ""; }; 960369FF200565C700510F3D /* NSOrthography+MGLAdditions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSOrthography+MGLAdditions.h"; sourceTree = ""; }; 96036A00200565C700510F3D /* NSOrthography+MGLAdditions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "NSOrthography+MGLAdditions.m"; sourceTree = ""; }; 96036A0520059BBA00510F3D /* MGLNSOrthographyAdditionsTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLNSOrthographyAdditionsTests.m; sourceTree = ""; }; @@ -2118,7 +2130,11 @@ DA8847E61CBAFA5100AB86E3 /* MGLOfflineStorage.h */, DA8848091CBAFA6200AB86E3 /* MGLOfflineStorage_Private.h */, DA88480A1CBAFA6200AB86E3 /* MGLOfflineStorage.mm */, + 92FC0AE8207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h */, + 92FC0AE7207CEE16007B6B54 /* MGLShapeOfflineRegion.h */, + 92FC0AE9207CEE16007B6B54 /* MGLShapeOfflineRegion.mm */, DA8847ED1CBAFA5100AB86E3 /* MGLTilePyramidOfflineRegion.h */, + 9221BAAC2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */, DA8848101CBAFA6200AB86E3 /* MGLTilePyramidOfflineRegion.mm */, ); name = "Offline Maps"; @@ -2211,6 +2227,7 @@ buildActionMask = 2147483647; files = ( 556660DB1E1D8E8D00E2C41B /* MGLFoundation.h in Headers */, + 92FC0AEA207CEE16007B6B54 /* MGLShapeOfflineRegion.h in Headers */, 35D13AC31D3D19DD00AFB4E0 /* MGLFillStyleLayer.h in Headers */, DA88483A1CBAFB8500AB86E3 /* MGLAnnotationImage.h in Headers */, DAF2571B201901E200367EF5 /* MGLHillshadeStyleLayer.h in Headers */, @@ -2277,6 +2294,7 @@ 071BBB031EE76146001FB02A /* MGLImageSource.h in Headers */, DA8847F41CBAFA5100AB86E3 /* MGLOfflinePack.h in Headers */, DA88482E1CBAFA6200AB86E3 /* NSException+MGLAdditions.h in Headers */, + 9221BAAD2069843A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */, 96F3F73C1F57124B003E2D2C /* MGLUserLocationHeadingIndicator.h in Headers */, 408AA8571DAEDA1700022900 /* NSDictionary+MGLAdditions.h in Headers */, DA88483F1CBAFB8500AB86E3 /* MGLUserLocation.h in Headers */, @@ -2321,6 +2339,7 @@ DA8847F51CBAFA5100AB86E3 /* MGLOfflineRegion.h in Headers */, DA737EE11D056A4E005BDA16 /* MGLMapViewDelegate.h in Headers */, ACF969F420CB04E600B23FB7 /* MMEEventsService.h in Headers */, + 92FC0AEC207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */, AC518DFF201BB55A00EBC820 /* MGLTelemetryConfig.h in Headers */, DA88481B1CBAFA6200AB86E3 /* MGLGeometry_Private.h in Headers */, 3510FFF91D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.h in Headers */, @@ -2351,6 +2370,7 @@ 556660CA1E1BF3A900E2C41B /* MGLFoundation.h in Headers */, 96E516ED200058A200A02306 /* MGLComputedShapeSource.h in Headers */, 35B82BF91D6C5F8400B1B721 /* NSPredicate+MGLAdditions.h in Headers */, + 92FC0AEB207CEE16007B6B54 /* MGLShapeOfflineRegion.h in Headers */, DA35A2CA1CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */, 350098BC1D480108004B2AF0 /* MGLVectorTileSource.h in Headers */, FA68F14B1E9D656600F9F6C2 /* MGLFillExtrusionStyleLayer.h in Headers */, @@ -2379,6 +2399,7 @@ CA55CD42202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */, DABFB86D1CBE9A0F00D62B32 /* MGLAnnotationImage.h in Headers */, DABFB8721CBE9A0F00D62B32 /* MGLUserLocation.h in Headers */, + 92FC0AED207CEE16007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */, 927FBD001F4DB05500F8BF1F /* MGLMapSnapshotter.h in Headers */, 3566C7721D4A9198008152BC /* MGLSource_Private.h in Headers */, 353933FF1D3FB7DD003F57D7 /* MGLSymbolStyleLayer.h in Headers */, @@ -2455,6 +2476,7 @@ 96E516E02000550C00A02306 /* MGLFeature_Private.h in Headers */, 353933F61D3FB785003F57D7 /* MGLBackgroundStyleLayer.h in Headers */, DABFB85D1CBE99E500D62B32 /* MGLAccountManager.h in Headers */, + 9221BAB020699F8A0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */, 96E516F5200059B100A02306 /* MGLNetworkConfiguration.h in Headers */, 96E516F42000597D00A02306 /* NSData+MGLAdditions.h in Headers */, 96E516DD200054F200A02306 /* MGLPolygon_Private.h in Headers */, @@ -3010,6 +3032,7 @@ 40834C441FE05F7500C1BD0D /* reporting_utils.m in Sources */, 408AA8581DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */, DA35A2A11CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */, + 92FC0AEE207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */, 35305D481D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */, 40834BF61FE05E1800C1BD0D /* MMEUIApplicationWrapper.m in Sources */, DA8848291CBAFA6200AB86E3 /* MGLStyle.mm in Sources */, @@ -3137,6 +3160,7 @@ 40834C511FE05F7600C1BD0D /* reporting_utils.m in Sources */, 35305D491D22AA680007D005 /* NSData+MGLAdditions.mm in Sources */, 357FE2E01E02D2B20068B753 /* NSCoder+MGLAdditions.mm in Sources */, + 92FC0AEF207CEE16007B6B54 /* MGLShapeOfflineRegion.mm in Sources */, DAA4E42D1CBB730400178DFB /* MGLAnnotationImage.m in Sources */, 40834C0A1FE05E1800C1BD0D /* MMEUIApplicationWrapper.m in Sources */, 558DE7A31E5615E400C7916D /* MGLFoundation.mm in Sources */, diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h index a0afe2d9cc..2af80b455d 100644 --- a/platform/ios/src/Mapbox.h +++ b/platform/ios/src/Mapbox.h @@ -57,6 +57,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[]; #import "MGLRasterTileSource.h" #import "MGLRasterDEMSource.h" #import "MGLImageSource.h" +#import "MGLShapeOfflineRegion.h" #import "MGLTilePyramidOfflineRegion.h" #import "MGLTypes.h" #import "MGLUserLocation.h" diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 41063670a8..1e6a54d8e9 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -5,6 +5,7 @@ * When a symbol in an `MGLSymbolStyleLayer` has both an icon and text, both are shown or hidden together based on available space. ([#12521](https://github.com/mapbox/mapbox-gl-native/pull/12521)) * The `-[MGLMapView annotationAtPoint:]` method can now return annotations near tile boundaries at high zoom levels. ([#12570](https://github.com/mapbox/mapbox-gl-native/pull/12570)) * Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) +* Added `MGLShapeOfflineRegion` for defining arbitrarily shaped offline regions [#11447](https://github.com/mapbox/mapbox-gl-native/pull/11447) # 0.10.0 - August 15, 2018 diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj index 3ee1b8eab4..1785caddb9 100644 --- a/platform/macos/macos.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -93,7 +93,11 @@ 92092EF01F5EB10E00AF5130 /* MGLMapSnapshotter.h in Headers */ = {isa = PBXBuildFile; fileRef = 92092EEE1F5EB10E00AF5130 /* MGLMapSnapshotter.h */; settings = {ATTRIBUTES = (Public, ); }; }; 92092EF11F5EB10E00AF5130 /* MGLMapSnapshotter.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92092EEF1F5EB10E00AF5130 /* MGLMapSnapshotter.mm */; }; 920A3E591E6F859D00C16EFC /* MGLSourceQueryTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 920A3E581E6F859D00C16EFC /* MGLSourceQueryTests.m */; }; + 9221BAAF20699CBB0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9221BAAE20699CBA0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */; }; + 9250B8C32073C69100EF338C /* MGLShapeOfflineRegion.h in Headers */ = {isa = PBXBuildFile; fileRef = 9250B8C22073C69000EF338C /* MGLShapeOfflineRegion.h */; settings = {ATTRIBUTES = (Public, ); }; }; 92F2C3EB1F0E3A1900268EC0 /* MGLRendererFrontend.h in Headers */ = {isa = PBXBuildFile; fileRef = 92F2C3EA1F0E3A1900268EC0 /* MGLRendererFrontend.h */; }; + 92FC0AE4207CC8DA007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 92FC0AE3207CC8DA007B6B54 /* MGLShapeOfflineRegion_Private.h */; }; + 92FC0AE6207CDD8D007B6B54 /* MGLShapeOfflineRegion.mm in Sources */ = {isa = PBXBuildFile; fileRef = 92FC0AE5207CDD8D007B6B54 /* MGLShapeOfflineRegion.mm */; }; 9654C12B1FFC38E000DB6A19 /* MGLPolyline_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C12A1FFC38E000DB6A19 /* MGLPolyline_Private.h */; }; 9654C12D1FFC394700DB6A19 /* MGLPolygon_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C12C1FFC394700DB6A19 /* MGLPolygon_Private.h */; }; 96E027311E57C9A7004B8E66 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96E027331E57C9A7004B8E66 /* Localizable.strings */; }; @@ -383,7 +387,11 @@ 92092EEE1F5EB10E00AF5130 /* MGLMapSnapshotter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapSnapshotter.h; sourceTree = ""; }; 92092EEF1F5EB10E00AF5130 /* MGLMapSnapshotter.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapSnapshotter.mm; sourceTree = ""; }; 920A3E581E6F859D00C16EFC /* MGLSourceQueryTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLSourceQueryTests.m; sourceTree = ""; }; + 9221BAAE20699CBA0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLTilePyramidOfflineRegion_Private.h; sourceTree = ""; }; + 9250B8C22073C69000EF338C /* MGLShapeOfflineRegion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeOfflineRegion.h; sourceTree = ""; }; 92F2C3EA1F0E3A1900268EC0 /* MGLRendererFrontend.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLRendererFrontend.h; sourceTree = ""; }; + 92FC0AE3207CC8DA007B6B54 /* MGLShapeOfflineRegion_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLShapeOfflineRegion_Private.h; sourceTree = ""; }; + 92FC0AE5207CDD8D007B6B54 /* MGLShapeOfflineRegion.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLShapeOfflineRegion.mm; sourceTree = ""; }; 9654C12A1FFC38E000DB6A19 /* MGLPolyline_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolyline_Private.h; sourceTree = ""; }; 9654C12C1FFC394700DB6A19 /* MGLPolygon_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLPolygon_Private.h; sourceTree = ""; }; 966091701E5BBFF700A9A03B /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = ""; }; @@ -1007,7 +1015,11 @@ DAE6C3511CC31E0400DB3429 /* MGLOfflineStorage.h */, DAE6C3741CC31E2A00DB3429 /* MGLOfflineStorage_Private.h */, DAE6C3751CC31E2A00DB3429 /* MGLOfflineStorage.mm */, + 9250B8C22073C69000EF338C /* MGLShapeOfflineRegion.h */, + 92FC0AE3207CC8DA007B6B54 /* MGLShapeOfflineRegion_Private.h */, + 92FC0AE5207CDD8D007B6B54 /* MGLShapeOfflineRegion.mm */, DAE6C3581CC31E0400DB3429 /* MGLTilePyramidOfflineRegion.h */, + 9221BAAE20699CBA0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h */, DAE6C37B1CC31E2A00DB3429 /* MGLTilePyramidOfflineRegion.mm */, ); name = "Offline Maps"; @@ -1214,6 +1226,7 @@ 352742781D4C220900A1ECE6 /* MGLStyleValue.h in Headers */, DAE6C35E1CC31E0400DB3429 /* MGLMultiPoint.h in Headers */, 35602BFF1D3EA9B40050646F /* MGLStyleLayer_Private.h in Headers */, + 92FC0AE4207CC8DA007B6B54 /* MGLShapeOfflineRegion_Private.h in Headers */, DAF0D8161DFE6B1800B28378 /* MGLAttributionInfo_Private.h in Headers */, DAE6C3971CC31E2A00DB3429 /* NSBundle+MGLAdditions.h in Headers */, DAED385F1D62CED700D7640F /* NSURL+MGLAdditions.h in Headers */, @@ -1246,6 +1259,7 @@ 35602BFA1D3EA99F0050646F /* MGLFillStyleLayer.h in Headers */, DA35A2A41CC9EB1A00E826B2 /* MGLCoordinateFormatter.h in Headers */, 35C5D8491D6DD66D00E95907 /* NSCompoundPredicate+MGLAdditions.h in Headers */, + 9250B8C32073C69100EF338C /* MGLShapeOfflineRegion.h in Headers */, DD0902B31DB1AC6400C5BDCE /* MGLNetworkConfiguration.h in Headers */, DAE6C3621CC31E0400DB3429 /* MGLOverlay.h in Headers */, DAE6C3651CC31E0400DB3429 /* MGLPolyline.h in Headers */, @@ -1287,6 +1301,7 @@ 352742851D4C244700A1ECE6 /* MGLRasterTileSource.h in Headers */, 9654C12D1FFC394700DB6A19 /* MGLPolygon_Private.h in Headers */, 408AA85B1DAEECFE00022900 /* MGLShape_Private.h in Headers */, + 9221BAAF20699CBB0054BDF4 /* MGLTilePyramidOfflineRegion_Private.h in Headers */, DACC22181CF3D4F700D220D9 /* MGLFeature_Private.h in Headers */, 9654C12B1FFC38E000DB6A19 /* MGLPolyline_Private.h in Headers */, DA6408D71DA4E5DA00908C90 /* MGLVectorStyleLayer.h in Headers */, @@ -1568,6 +1583,7 @@ DAE6C3B51CC31EF300DB3429 /* MGLCompassCell.m in Sources */, DA8F25901D51CA600010E6B5 /* MGLRasterStyleLayer.mm in Sources */, DAD165751CF4CD7A001FF4B9 /* MGLShapeCollection.mm in Sources */, + 92FC0AE6207CDD8D007B6B54 /* MGLShapeOfflineRegion.mm in Sources */, 35C5D8481D6DD66D00E95907 /* NSComparisonPredicate+MGLAdditions.mm in Sources */, DA35A2AE1CCA091800E826B2 /* MGLCompassDirectionFormatter.m in Sources */, DACA8623201920BE00E9693A /* MGLRasterDEMSource.mm in Sources */, diff --git a/platform/macos/src/Mapbox.h b/platform/macos/src/Mapbox.h index 198998a874..dcffd73dfc 100644 --- a/platform/macos/src/Mapbox.h +++ b/platform/macos/src/Mapbox.h @@ -56,6 +56,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[]; #import "MGLRasterDEMSource.h" #import "MGLImageSource.h" #import "MGLTilePyramidOfflineRegion.h" +#import "MGLShapeOfflineRegion.h" #import "MGLTypes.h" #import "NSValue+MGLAdditions.h" #import "MGLStyleValue.h" -- cgit v1.2.1 From fcb68041d51990a4cf67d88fa1eeb0f5d882305c Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Wed, 11 Apr 2018 10:59:32 +0300 Subject: [offline] Add option to pass geojson input file --- bin/offline.cpp | 90 ++++++++++++++++++++++++++++++++++++++------- platform/linux/config.cmake | 1 + 2 files changed, 77 insertions(+), 14 deletions(-) diff --git a/bin/offline.cpp b/bin/offline.cpp index 603f0b848a..2da47a4476 100644 --- a/bin/offline.cpp +++ b/bin/offline.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include @@ -11,9 +12,47 @@ #include #include #include +#include using namespace std::literals::chrono_literals; +std::string readFile(const std::string& fileName) { + std::ifstream stream(fileName.c_str()); + if (!stream.good()) { + throw std::runtime_error("Cannot read file: " + fileName); + } + + std::stringstream buffer; + buffer << stream.rdbuf(); + stream.close(); + + return buffer.str(); +} + +mapbox::geometry::geometry parseGeometry(const std::string& json) { + using namespace mapbox::geojson; + auto geojson = parse(json); + return geojson.match( + [](const geometry& geom) { + return geom; + }, + [](const feature& feature) { + return feature.geometry; + }, + [](const feature_collection& featureCollection) { + if (featureCollection.size() < 1) { + throw std::runtime_error("No features in feature collection"); + } + geometry_collection geometries; + + for (auto feature : featureCollection) { + geometries.push_back(feature.geometry); + } + + return geometries; + }); +} + int main(int argc, char *argv[]) { args::ArgumentParser argumentParser("Mapbox GL offline tool"); args::HelpFlag helpFlag(argumentParser, "help", "Display this help menu", {'h', "help"}); @@ -22,11 +61,19 @@ int main(int argc, char *argv[]) { args::ValueFlag styleValue(argumentParser, "URL", "Map stylesheet", {'s', "style"}); args::ValueFlag outputValue(argumentParser, "file", "Output database file name", {'o', "output"}); args::ValueFlag apiBaseValue(argumentParser, "URL", "API Base URL", {'a', "apiBaseURL"}); - - args::ValueFlag northValue(argumentParser, "degrees", "North latitude", {"north"}); - args::ValueFlag westValue(argumentParser, "degrees", "West longitude", {"west"}); - args::ValueFlag southValue(argumentParser, "degrees", "South latitude", {"south"}); - args::ValueFlag eastValue(argumentParser, "degrees", "East longitude", {"east"}); + + // LatLngBounds + args::Group latLngBoundsGroup(argumentParser, "LatLng bounds:", args::Group::Validators::AllOrNone); + args::ValueFlag northValue(latLngBoundsGroup, "degrees", "North latitude", {"north"}); + args::ValueFlag westValue(latLngBoundsGroup, "degrees", "West longitude", {"west"}); + args::ValueFlag southValue(latLngBoundsGroup, "degrees", "South latitude", {"south"}); + args::ValueFlag eastValue(latLngBoundsGroup, "degrees", "East longitude", {"east"}); + + // Geometry + args::Group geoJSONGroup(argumentParser, "GeoJson geometry:", args::Group::Validators::AllOrNone); + args::ValueFlag geometryValue(geoJSONGroup, "file", "GeoJSON file containing the region geometry", {"geojson"}); + + args::ValueFlag minZoomValue(argumentParser, "number", "Min zoom level", {"minZoom"}); args::ValueFlag maxZoomValue(argumentParser, "number", "Max zoom level", {"maxZoom"}); args::ValueFlag pixelRatioValue(argumentParser, "number", "Pixel ratio", {"pixelRatio"}); @@ -48,23 +95,39 @@ int main(int argc, char *argv[]) { std::string style = styleValue ? args::get(styleValue) : mbgl::util::default_styles::streets.url; - // Bay area - const double north = northValue ? args::get(northValue) : 37.2; - const double west = westValue ? args::get(westValue) : -122.8; - const double south = southValue ? args::get(southValue) : 38.1; - const double east = eastValue ? args::get(eastValue) : -121.7; - const double minZoom = minZoomValue ? args::get(minZoomValue) : 0.0; const double maxZoom = maxZoomValue ? args::get(maxZoomValue) : 15.0; const double pixelRatio = pixelRatioValue ? args::get(pixelRatioValue) : 1.0; const std::string output = outputValue ? args::get(outputValue) : "offline.db"; + + using namespace mbgl; + + OfflineRegionDefinition definition = [&]() { + if (geometryValue) { + try { + std::string json = readFile(geometryValue.Get()); + auto geometry = parseGeometry(json); + return OfflineRegionDefinition{ OfflineGeometryRegionDefinition(style, geometry, minZoom, maxZoom, pixelRatio) }; + } catch(std::runtime_error e) { + std::cerr << "Could not parse geojson file " << geometryValue.Get() << ": " << e.what() << std::endl; + exit(1); + } + } else { + // Bay area + const double north = northValue ? args::get(northValue) : 37.2; + const double west = westValue ? args::get(westValue) : -122.8; + const double south = southValue ? args::get(southValue) : 38.1; + const double east = eastValue ? args::get(eastValue) : -121.7; + LatLngBounds boundingBox = LatLngBounds::hull(LatLng(north, west), LatLng(south, east)); + return OfflineRegionDefinition{ OfflineTilePyramidRegionDefinition(style, boundingBox, minZoom, maxZoom, pixelRatio) }; + } + }(); const char* tokenEnv = getenv("MAPBOX_ACCESS_TOKEN"); const std::string token = tokenValue ? args::get(tokenValue) : (tokenEnv ? tokenEnv : std::string()); const std::string apiBaseURL = apiBaseValue ? args::get(apiBaseValue) : mbgl::util::API_BASE_URL; - using namespace mbgl; util::RunLoop loop; DefaultFileSource fileSource(output, "."); @@ -73,8 +136,7 @@ int main(int argc, char *argv[]) { fileSource.setAccessToken(token); fileSource.setAPIBaseURL(apiBaseURL); - LatLngBounds boundingBox = LatLngBounds::hull(LatLng(north, west), LatLng(south, east)); - OfflineTilePyramidRegionDefinition definition(style, boundingBox, minZoom, maxZoom, pixelRatio); + OfflineRegionMetadata metadata; class Observer : public OfflineRegionObserver { diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake index c1eb4bfe12..b55cedcacb 100644 --- a/platform/linux/config.cmake +++ b/platform/linux/config.cmake @@ -81,6 +81,7 @@ macro(mbgl_platform_core) target_add_mason_package(mbgl-core PUBLIC libjpeg-turbo) target_add_mason_package(mbgl-core PUBLIC webp) target_add_mason_package(mbgl-core PRIVATE icu) + target_add_mason_package(mbgl-core PUBLIC geojson) target_link_libraries(mbgl-core PRIVATE nunicode -- cgit v1.2.1 From 50059659d100759978c8bebb04ac7beb9e6d618f Mon Sep 17 00:00:00 2001 From: Nadia Barbosa Date: Mon, 13 Aug 2018 17:24:56 -0700 Subject: Warn if MGLShapeSource is initialized with MGLShapeCollection Move warning from ShapeCollection to ShapeSource Try checking MGLComputedShapeSources Include MGLShapeCollection header Add changelog entry --- platform/darwin/src/MGLComputedShapeSource.mm | 17 +++++++++++++++++ platform/darwin/src/MGLShapeCollection.mm | 1 + platform/darwin/src/MGLShapeSource.mm | 8 ++++++++ platform/ios/CHANGELOG.md | 1 + 4 files changed, 27 insertions(+) diff --git a/platform/darwin/src/MGLComputedShapeSource.mm b/platform/darwin/src/MGLComputedShapeSource.mm index 609db7f399..0493131922 100644 --- a/platform/darwin/src/MGLComputedShapeSource.mm +++ b/platform/darwin/src/MGLComputedShapeSource.mm @@ -4,6 +4,7 @@ #import "MGLSource_Private.h" #import "MGLShape_Private.h" #import "MGLGeometry_Private.h" +#import "MGLShapeCollection.h" #include #include @@ -131,6 +132,14 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi mbgl::FeatureCollection featureCollection; featureCollection.reserve(data.count); for (MGLShape * feature in data) { + if ([feature isMemberOfClass:[MGLShapeCollection class]]) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSLog(@"MGLShapeCollection initialized with MGLFeatures will not retain attributes." + @"Use MGLShapeCollectionFeature to retain attributes instead." + @"This will be logged only once."); + }); + } mbgl::Feature geoJsonObject = [feature geoJSONObject].get(); featureCollection.push_back(geoJsonObject); } @@ -196,6 +205,14 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi for (MGLShape * feature in features) { mbgl::Feature geoJsonObject = [feature geoJSONObject].get(); featureCollection.push_back(geoJsonObject); + if ([feature isMemberOfClass:[MGLShapeCollection class]]) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSLog(@"MGLShapeCollection initialized with MGLFeatures will not retain attributes." + @"Use MGLShapeCollectionFeature to retain attributes instead." + @"This will be logged only once."); + }); + } } const auto geojson = mbgl::GeoJSON{featureCollection}; static_cast(self.rawSource)->setTileData(tileID, geojson); diff --git a/platform/darwin/src/MGLShapeCollection.mm b/platform/darwin/src/MGLShapeCollection.mm index 74e78a764a..5db1ee335c 100644 --- a/platform/darwin/src/MGLShapeCollection.mm +++ b/platform/darwin/src/MGLShapeCollection.mm @@ -1,6 +1,7 @@ #import "MGLShapeCollection.h" #import "MGLShape_Private.h" +#import "MGLFeature.h" #import diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm index 1425269012..9457d2569a 100644 --- a/platform/darwin/src/MGLShapeSource.mm +++ b/platform/darwin/src/MGLShapeSource.mm @@ -105,6 +105,14 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary(identifier.UTF8String, geoJSONOptions); if (self = [super initWithPendingSource:std::move(source)]) { + if ([shape isMemberOfClass:[MGLShapeCollection class]]) { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSLog(@"MGLShapeCollection initialized with MGLFeatures will not retain attributes." + @"Use MGLShapeCollectionFeature to retain attributes instead." + @"This will be logged only once."); + }); + } self.shape = shape; } return self; diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index edebf57dc6..d4254554d1 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -9,6 +9,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * The `-[MGLMapView visibleFeaturesAtPoint:]` method can now return features near tile boundaries at high zoom levels. ([#12570](https://github.com/mapbox/mapbox-gl-native/pull/12570)) * Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) * Added `MGLShapeOfflineRegion` for defining arbitrarily shaped offline regions [#11447](https://github.com/mapbox/mapbox-gl-native/pull/11447) +* Added a one-time warning about possible attribute loss when initializing an `MGLShapeSource` with an `MGLShapeCollection` [#12625](https://github.com/mapbox/mapbox-gl-native/pull/12625) ## 4.3.0 - August 15, 2018 -- cgit v1.2.1 From 7fc872b797679ae033a32246206efb06c98a0fd5 Mon Sep 17 00:00:00 2001 From: Jordan Kiley Date: Mon, 20 Aug 2018 16:30:03 -0700 Subject: Add enabled property to MGLShape (#12352) * [ios, macos] Add -[MGLMapViewDelegate mapView:canSelectAnnotation:] method. * [ios, macos] Update changelogs. * [ios, macos] Add mapView:canSelect: integration tests. * [ios, macos] Change semantics to shape annotations. * [ios, macos] Update changelogs. * [ios, macos] Update shapeAnnotationIsEnabled documentation, improve code readability. --- platform/ios/CHANGELOG.md | 1 + platform/ios/src/MGLMapView.mm | 6 +++++- platform/ios/src/MGLMapViewDelegate.h | 12 ++++++++++++ platform/ios/test/MGLMapViewDelegateIntegrationTests.swift | 2 ++ platform/macos/CHANGELOG.md | 1 + platform/macos/src/MGLMapView.mm | 6 +++++- platform/macos/src/MGLMapViewDelegate.h | 12 ++++++++++++ platform/macos/test/MGLMapViewDelegateIntegrationTests.swift | 2 ++ 8 files changed, 40 insertions(+), 2 deletions(-) diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md index d4254554d1..2d52084be7 100644 --- a/platform/ios/CHANGELOG.md +++ b/platform/ios/CHANGELOG.md @@ -10,6 +10,7 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT * Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) * Added `MGLShapeOfflineRegion` for defining arbitrarily shaped offline regions [#11447](https://github.com/mapbox/mapbox-gl-native/pull/11447) * Added a one-time warning about possible attribute loss when initializing an `MGLShapeSource` with an `MGLShapeCollection` [#12625](https://github.com/mapbox/mapbox-gl-native/pull/12625) +* Added an `-[MGLMapViewDelegate mapView:shapeAnnotationIsEnabled:]` method to specify whether an annotation is selectable. ([#12352](https://github.com/mapbox/mapbox-gl-native/pull/12352)) ## 4.3.0 - August 15, 2018 diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm index 2a231838a4..8ca41b328c 100644 --- a/platform/ios/src/MGLMapView.mm +++ b/platform/ios/src/MGLMapView.mm @@ -4183,7 +4183,11 @@ public: { if ([annotation isKindOfClass:[MGLMultiPoint class]]) { - return false; + if ([self.delegate respondsToSelector:@selector(mapView:shapeAnnotationIsEnabled:)]) { + return !!(![self.delegate mapView:self shapeAnnotationIsEnabled:(MGLMultiPoint *)annotation]); + } else { + return false; + } } MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag]; diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h index 201e3db84b..4bd1a95c9b 100644 --- a/platform/ios/src/MGLMapViewDelegate.h +++ b/platform/ios/src/MGLMapViewDelegate.h @@ -432,6 +432,18 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark Selecting Annotations +/** + Returns a Boolean value indicating whether the shape annotation can be selected. + + If the return value is `YES`, the user can select the annotation by tapping + on it. If the delegate does not implement this method, the default value is `YES`. + + @param mapView The map view that has selected the annotation. + @param annotation The object representing the shape annotation. + @return A Boolean value indicating whether the annotation can be selected. + */ +- (BOOL)mapView:(MGLMapView *)mapView shapeAnnotationIsEnabled:(MGLShape *)annotation; + /** Tells the delegate that one of its annotations was selected. diff --git a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift index 4d11b000b9..48673b1d14 100644 --- a/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift +++ b/platform/ios/test/MGLMapViewDelegateIntegrationTests.swift @@ -58,6 +58,8 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate { func mapView(_ mapView: MGLMapView, tapOnCalloutFor annotation: MGLAnnotation) {} func mapViewDidFinishRenderingFrame(_ mapView: MGLMapView, fullyRendered: Bool) {} + + func mapView(_ mapView: MGLMapView, shapeAnnotationIsEnabled annotation: MGLShape) -> Bool { return false } func mapView(_ mapView: MGLMapView, didAdd annotationViews: [MGLAnnotationView]) {} diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md index 1e6a54d8e9..c0c751d370 100644 --- a/platform/macos/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -6,6 +6,7 @@ * The `-[MGLMapView annotationAtPoint:]` method can now return annotations near tile boundaries at high zoom levels. ([#12570](https://github.com/mapbox/mapbox-gl-native/pull/12570)) * Fixed inconsistencies in exception naming. ([#12583](https://github.com/mapbox/mapbox-gl-native/issues/12583)) * Added `MGLShapeOfflineRegion` for defining arbitrarily shaped offline regions [#11447](https://github.com/mapbox/mapbox-gl-native/pull/11447) +* Added an `-[MGLMapViewDelegate mapView:shapeAnnotationIsEnabled:]` method to specify whether an annotation is selectable. ([#12352](https://github.com/mapbox/mapbox-gl-native/pull/12352)) # 0.10.0 - August 15, 2018 diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm index 154b716377..3c1fe18499 100644 --- a/platform/macos/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -2108,7 +2108,11 @@ public: if ([annotation isKindOfClass:[MGLMultiPoint class]]) { - return false; + if ([self.delegate respondsToSelector:@selector(mapView:shapeAnnotationIsEnabled:)]) { + return !!(![self.delegate mapView:self shapeAnnotationIsEnabled:(MGLMultiPoint *)annotation]); + } else { + return false; + } } MGLAnnotationImage *annotationImage = [self imageOfAnnotationWithTag:annotationTag]; diff --git a/platform/macos/src/MGLMapViewDelegate.h b/platform/macos/src/MGLMapViewDelegate.h index dae5b40286..2a8b28c1b4 100644 --- a/platform/macos/src/MGLMapViewDelegate.h +++ b/platform/macos/src/MGLMapViewDelegate.h @@ -243,6 +243,18 @@ NS_ASSUME_NONNULL_BEGIN #pragma mark Selecting Annotations +/** + Returns a Boolean value indicating whether the shape annotation can be selected. + + If the return value is `YES`, the user can select the annotation by clicking + on it. If the delegate does not implement this method, the default value is `YES`. + + @param mapView The map view that has selected the annotation. + @param annotation The object representing the shape annotation. + @return A Boolean value indicating whether the annotation can be selected. + */ +- (BOOL)mapView:(MGLMapView *)mapView shapeAnnotationIsEnabled:(MGLShape *)annotation; + /** Tells the delegate that one of its annotations has been selected. diff --git a/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift b/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift index 3f82e7c61a..00635d97eb 100644 --- a/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift +++ b/platform/macos/test/MGLMapViewDelegateIntegrationTests.swift @@ -26,6 +26,8 @@ extension MGLMapViewDelegateIntegrationTests: MGLMapViewDelegate { func mapViewDidFinishRenderingMap(_ mapView: MGLMapView, fullyRendered: Bool) {} func mapViewDidFailLoadingMap(_ mapView: MGLMapView, withError error: Error) {} + + func mapView(_ mapView: MGLMapView, shapeAnnotationIsEnabled annotation: MGLShape) -> Bool { return false } func mapView(_ mapView: MGLMapView, didDeselect annotation: MGLAnnotation) {} -- cgit v1.2.1 From 5297f563a4dd6a9d25c7f45714d54d45897f3bb0 Mon Sep 17 00:00:00 2001 From: Kiyong Jung Date: Thu, 16 Aug 2018 19:32:20 +0900 Subject: [android] Make AndroidRendererFrontend to request render once per event loop (#12586) When AndroidRendererFrontend::update() called multiple times in a single loop, updateAsyncTask->send() will perform nothing, thus MapRenderer::update()/requestRender() will be coalesced. --- .../testapp/activity/style/RuntimeStyleActivity.java | 13 +++++++++++++ .../src/main/res/menu/menu_runtime_style.xml | 4 ++++ .../src/main/res/values/actions.xml | 1 + platform/android/src/android_renderer_frontend.cpp | 11 ++++++++--- platform/android/src/android_renderer_frontend.hpp | 8 ++++++++ 5 files changed, 34 insertions(+), 3 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java index f49d80d704..20fa2e7d52 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/RuntimeStyleActivity.java @@ -197,6 +197,9 @@ public class RuntimeStyleActivity extends AppCompatActivity { case R.id.action_numeric_filter: styleNumericFillLayer(); return true; + case R.id.action_bring_water_to_front: + bringWaterToFront(); + return true; default: return super.onOptionsItemSelected(item); } @@ -572,6 +575,16 @@ public class RuntimeStyleActivity extends AppCompatActivity { }, 2000); } + private void bringWaterToFront() { + Layer water = mapboxMap.getLayer("water"); + if (water != null) { + mapboxMap.removeLayer(water); + mapboxMap.addLayerAt(water, mapboxMap.getLayers().size() - 1); + } else { + Toast.makeText(this, "No water layer in this style", Toast.LENGTH_SHORT).show(); + } + } + private static class DefaultCallback implements MapboxMap.CancelableCallback { @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml index 5c77179272..e3d7c8cfa0 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_runtime_style.xml @@ -66,4 +66,8 @@ android:id="@+id/action_numeric_filter" android:title="@string/apply_numeric_fill_filter" mapbox:showAsAction="never" /> + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml index 6d94c03529..e3cdc06dc1 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/actions.xml @@ -79,6 +79,7 @@ Apply filtered fill Apply filtered line Apply numeric fill filter + Bring water to front Toggle text size Toggle text field contents Toggle text font diff --git a/platform/android/src/android_renderer_frontend.cpp b/platform/android/src/android_renderer_frontend.cpp index 2a03d9de9e..8b4a25a4d9 100644 --- a/platform/android/src/android_renderer_frontend.cpp +++ b/platform/android/src/android_renderer_frontend.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -56,7 +57,11 @@ private: AndroidRendererFrontend::AndroidRendererFrontend(MapRenderer& mapRenderer_) : mapRenderer(mapRenderer_) - , mapRunLoop(util::RunLoop::Get()) { + , mapRunLoop(util::RunLoop::Get()) + , updateAsyncTask(std::make_unique([this]() { + mapRenderer.update(std::move(updateParams)); + mapRenderer.requestRender(); + })) { } AndroidRendererFrontend::~AndroidRendererFrontend() = default; @@ -73,8 +78,8 @@ void AndroidRendererFrontend::setObserver(RendererObserver& observer) { } void AndroidRendererFrontend::update(std::shared_ptr params) { - mapRenderer.update(std::move(params)); - mapRenderer.requestRender(); + updateParams = std::move(params); + updateAsyncTask->send(); } void AndroidRendererFrontend::reduceMemoryUse() { diff --git a/platform/android/src/android_renderer_frontend.hpp b/platform/android/src/android_renderer_frontend.hpp index b61904e388..9bd64e4819 100644 --- a/platform/android/src/android_renderer_frontend.hpp +++ b/platform/android/src/android_renderer_frontend.hpp @@ -18,6 +18,12 @@ namespace mbgl { class RenderedQueryOptions; class SourceQueryOptions; +namespace util { + +class AsyncTask; + +} // namespace util + namespace android { class AndroidRendererFrontend : public RendererFrontend { @@ -44,6 +50,8 @@ public: private: MapRenderer& mapRenderer; util::RunLoop* mapRunLoop; + std::unique_ptr updateAsyncTask; + std::shared_ptr updateParams; }; } // namespace android -- cgit v1.2.1 From 2c093e7f0b79072d3107ffab09e70255552916db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Tue, 7 Aug 2018 19:47:23 +0200 Subject: [android] - converting GeoJsonSource Java features to core ones on a worker thread --- .../mapboxsdk/style/sources/GeoJsonSource.java | 12 +- .../activity/maplayout/SimpleMapActivity.java | 1 - .../android/src/style/sources/geojson_source.cpp | 128 +++++++++++++++------ .../android/src/style/sources/geojson_source.hpp | 30 ++++- 4 files changed, 130 insertions(+), 41 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java index 65cd908ae4..2d9b1c985a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonSource.java @@ -188,7 +188,8 @@ public class GeoJsonSource extends Source { } /** - * Updates the GeoJson with a single feature + * Updates the GeoJson with a single feature. The update is performed asynchronously, + * so the data won't be immediately visible or available to query when this method returns. * * @param feature the GeoJSON {@link Feature} to set */ @@ -198,7 +199,8 @@ public class GeoJsonSource extends Source { } /** - * Updates the GeoJson with a single geometry + * Updates the GeoJson with a single geometry. The update is performed asynchronously, + * so the data won't be immediately visible or available to query when this method returns. * * @param geometry the GeoJSON {@link Geometry} to set */ @@ -208,7 +210,8 @@ public class GeoJsonSource extends Source { } /** - * Updates the GeoJson + * Updates the GeoJson. The update is performed asynchronously, + * so the data won't be immediately visible or available to query when this method returns. * * @param features the GeoJSON FeatureCollection */ @@ -218,7 +221,8 @@ public class GeoJsonSource extends Source { } /** - * Updates the GeoJson + * Updates the GeoJson. The update is performed asynchronously, + * so the data won't be immediately visible or available to query when this method returns. * * @param json the raw GeoJson FeatureCollection string */ diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java index 8f8a5af3cc..a1f7b4af01 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/maplayout/SimpleMapActivity.java @@ -17,7 +17,6 @@ public class SimpleMapActivity extends AppCompatActivity { protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_map_simple); - mapView = (MapView) findViewById(R.id.mapView); mapView.onCreate(savedInstanceState); } diff --git a/platform/android/src/style/sources/geojson_source.cpp b/platform/android/src/style/sources/geojson_source.cpp index 14067503f1..e526231763 100644 --- a/platform/android/src/style/sources/geojson_source.cpp +++ b/platform/android/src/style/sources/geojson_source.cpp @@ -16,7 +16,13 @@ #include "../conversion/url_or_tileset.hpp" #include +#include +// GeoJSONSource uses a "coalescing" model for high frequency asynchronous data update calls, +// which in practice means, that any update that started processing is going to finish +// and the last scheduled update is going to finish as well. Any updates scheduled during processing can be canceled. +// Conversion from Java features to core ones is done on a worker thread and once finished, +// the ownership of the converted features is returned to the calling thread. namespace mbgl { namespace android { @@ -40,60 +46,39 @@ namespace android { : Source(env, std::make_unique( jni::Make(env, sourceId), convertGeoJSONOptions(env, options)) - ) { + ), converter(std::make_unique>(*sharedThreadPool())) { } GeoJSONSource::GeoJSONSource(jni::JNIEnv& env, mbgl::style::Source& coreSource, AndroidRendererFrontend& frontend) - : Source(env, coreSource, createJavaPeer(env), frontend) { + : Source(env, coreSource, createJavaPeer(env), frontend) + , converter(std::make_unique>(*sharedThreadPool())) { } GeoJSONSource::~GeoJSONSource() = default; - void GeoJSONSource::setGeoJSONString(jni::JNIEnv& env, jni::String json) { - using namespace mbgl::style::conversion; + void GeoJSONSource::setGeoJSONString(jni::JNIEnv& env, jni::String jString) { - // Convert the jni object - Error error; - optional converted = convert(mbgl::android::Value(env, json), error); - if(!converted) { - mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message); - return; - } + std::shared_ptr json = std::make_shared(jni::Make(env, jString)); - // Update the core source - source.as()->GeoJSONSource::setGeoJSON(*converted); + Update::Converter converterFn = [this, json](ActorRef _callback) { + converter->self().invoke(&FeatureConverter::convertJson, json, _callback); + }; + + setAsync(converterFn); } void GeoJSONSource::setFeatureCollection(jni::JNIEnv& env, jni::Object jFeatures) { - using namespace mbgl::android::geojson; - - // Convert the jni object - auto features = FeatureCollection::convert(env, jFeatures); - - // Update the core source - source.as()->GeoJSONSource::setGeoJSON(GeoJSON(features)); + setCollectionAsync(env, jFeatures); } void GeoJSONSource::setFeature(jni::JNIEnv& env, jni::Object jFeature) { - using namespace mbgl::android::geojson; - - // Convert the jni object - auto feature = Feature::convert(env, jFeature); - - // Update the core source - source.as()->GeoJSONSource::setGeoJSON(GeoJSON(feature)); + setCollectionAsync(env, jFeature); } void GeoJSONSource::setGeometry(jni::JNIEnv& env, jni::Object jGeometry) { - using namespace mbgl::android::geojson; - - // Convert the jni object - auto geometry = Geometry::convert(env, jGeometry); - - // Update the core source - source.as()->GeoJSONSource::setGeoJSON(GeoJSON(geometry)); + setCollectionAsync(env, jGeometry); } void GeoJSONSource::setURL(jni::JNIEnv& env, jni::String url) { @@ -125,6 +110,50 @@ namespace android { return jni::Object(GeoJSONSource::javaClass.New(env, constructor, reinterpret_cast(this)).Get()); } + template + void GeoJSONSource::setCollectionAsync(jni::JNIEnv& env, jni::Object jObject) { + + std::shared_ptr object = std::shared_ptr(jObject.NewGlobalRef(env).release()->Get(), GenericGlobalRefDeleter()); + + Update::Converter converterFn = [this, object](ActorRef _callback) { + converter->self().invoke(&FeatureConverter::convertObject, jni::Object(*object), _callback); + }; + + setAsync(converterFn); + } + + void GeoJSONSource::setAsync(Update::Converter converterFn) { + awaitingUpdate = std::make_unique( + std::move(converterFn), + std::make_unique>( + *Scheduler::GetCurrent(), + [this](GeoJSON geoJSON) { + // conversion from Java features to core ones finished + android::UniqueEnv _env = android::AttachEnv(); + + // Update the core source + source.as()->GeoJSONSource::setGeoJSON(geoJSON); + + // if there is an awaiting update, execute it, otherwise, release resources + if (awaitingUpdate) { + update = std::move(awaitingUpdate); + update->converterFn(update->callback->self()); + } else { + update.reset(); + } + }) + ); + + // If another update is running, wait + if (update) { + return; + } + + // no updates are being processed, execute this one + update = std::move(awaitingUpdate); + update->converterFn(update->callback->self()); + } + void GeoJSONSource::registerNative(jni::JNIEnv& env) { // Lookup the class GeoJSONSource::javaClass = *jni::Class::Find(env).NewGlobalRef(env).release(); @@ -147,5 +176,36 @@ namespace android { ); } + void FeatureConverter::convertJson(std::shared_ptr json, + ActorRef callback) { + using namespace mbgl::style::conversion; + + android::UniqueEnv _env = android::AttachEnv(); + + // Convert the jni object + Error error; + optional converted = parseGeoJSON(*json, error); + if(!converted) { + mbgl::Log::Error(mbgl::Event::JNI, "Error setting geo json: " + error.message); + return; + } + + callback.invoke(&Callback::operator(), *converted); + } + + template + void FeatureConverter::convertObject(jni::Object jObject, ActorRef callback) { + using namespace mbgl::android::geojson; + + android::UniqueEnv _env = android::AttachEnv(); + // Convert the jni object + auto geometry = JNIType::convert(*_env, jObject); + callback.invoke(&Callback::operator(), GeoJSON(geometry)); + } + + Update::Update(Converter _converterFn, std::unique_ptr> _callback) + : converterFn(std::move(_converterFn)) + , callback(std::move(_callback)) {} + } // namespace android } // namespace mbgl diff --git a/platform/android/src/style/sources/geojson_source.hpp b/platform/android/src/style/sources/geojson_source.hpp index c46519b04a..b9c360c67c 100644 --- a/platform/android/src/style/sources/geojson_source.hpp +++ b/platform/android/src/style/sources/geojson_source.hpp @@ -10,6 +10,24 @@ namespace mbgl { namespace android { +using Callback = std::function; + +struct FeatureConverter { + void convertJson(std::shared_ptr, ActorRef); + + template + void convertObject(jni::Object, ActorRef); +}; + +struct Update { + using Converter = std::function)>; + Converter converterFn; + + std::unique_ptr> callback; + + Update(Converter, std::unique_ptr>); +}; + class GeoJSONSource : public Source { public: @@ -35,13 +53,21 @@ public: void setURL(jni::JNIEnv&, jni::String); + jni::String getURL(jni::JNIEnv&); + jni::Array> querySourceFeatures(jni::JNIEnv&, jni::Array> jfilter); - jni::String getURL(jni::JNIEnv&); - private: jni::Object createJavaPeer(jni::JNIEnv&); + std::unique_ptr awaitingUpdate; + std::unique_ptr update; + std::unique_ptr> converter; + + template + void setCollectionAsync(jni::JNIEnv&, jni::Object); + + void setAsync(Update::Converter); }; // class GeoJSONSource -- cgit v1.2.1 From 7e6331b29f13a14076bac4ebbf22006c055933c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Mon, 13 Aug 2018 14:30:25 +0200 Subject: [android] - updated GeoJsonSource tests --- .../testapp/style/GeoJsonSourceTests.java | 124 +++++++++++---------- 1 file changed, 64 insertions(+), 60 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java index 2156c96973..124edacbd2 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/GeoJsonSourceTests.java @@ -1,21 +1,22 @@ package com.mapbox.mapboxsdk.testapp.style; import android.support.annotation.RawRes; -import android.support.test.espresso.UiController; import android.support.test.espresso.ViewAction; import android.support.test.runner.AndroidJUnit4; import android.view.View; +import com.mapbox.geojson.Feature; +import com.mapbox.geojson.FeatureCollection; +import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.style.layers.CircleLayer; import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction; import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest; import com.mapbox.mapboxsdk.testapp.activity.style.RuntimeStyleTestActivity; import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils; -import com.mapbox.geojson.Feature; -import com.mapbox.geojson.FeatureCollection; -import com.mapbox.geojson.Point; import org.hamcrest.Matcher; import org.junit.Test; @@ -25,9 +26,8 @@ import java.io.IOException; import timber.log.Timber; -import static android.support.test.espresso.Espresso.onView; import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed; -import static android.support.test.espresso.matcher.ViewMatchers.withId; +import static org.junit.Assert.assertTrue; /** * Tests for {@link GeoJsonSource} @@ -41,60 +41,69 @@ public class GeoJsonSourceTests extends BaseActivityTest { } @Test - public void testFeatureCollection() throws Exception { + public void testFeatureCollection() { validateTestSetup(); - onView(withId(R.id.mapView)).perform(new BaseViewAction() { - - @Override - public void perform(UiController uiController, View view) { - GeoJsonSource source = null; - try { - source = new GeoJsonSource("source", FeatureCollection - .fromJson(ResourceUtils.readRawResource(rule.getActivity(), R.raw.test_feature_collection))); - } catch (IOException exception) { - Timber.e(exception); - } - mapboxMap.addSource(source); - mapboxMap.addLayer(new CircleLayer("layer", source.getId())); + MapboxMapAction.invoke(mapboxMap, (uiController, mapboxMap) -> { + GeoJsonSource source = null; + try { + source = new GeoJsonSource("source", FeatureCollection + .fromJson(ResourceUtils.readRawResource(rule.getActivity(), R.raw.test_feature_collection))); + } catch (IOException exception) { + Timber.e(exception); } + mapboxMap.addSource(source); + mapboxMap.addLayer(new CircleLayer("layer", source.getId())); }); } @Test public void testPointGeometry() { validateTestSetup(); - onView(withId(R.id.mapView)).perform(new BaseViewAction() { - - @Override - public void perform(UiController uiController, View view) { - GeoJsonSource source = new GeoJsonSource("source", Point.fromLngLat(0d, 0d)); - mapboxMap.addSource(source); + MapboxMapAction.invoke(mapboxMap, (uiController, mapboxMap) -> { + GeoJsonSource source = new GeoJsonSource("source", Point.fromLngLat(0d, 0d)); + mapboxMap.addSource(source); + mapboxMap.addLayer(new CircleLayer("layer", source.getId())); + }); + } - mapboxMap.addLayer(new CircleLayer("layer", source.getId())); + @Test + public void testFeatureProperties() { + validateTestSetup(); + MapboxMapAction.invoke(mapboxMap, (uiController, mapboxMap) -> { + GeoJsonSource source = null; + try { + source = new GeoJsonSource("source", + ResourceUtils.readRawResource(rule.getActivity(), R.raw.test_feature_properties)); + } catch (IOException exception) { + Timber.e(exception); } - + mapboxMap.addSource(source); + mapboxMap.addLayer(new CircleLayer("layer", source.getId())); }); } @Test - public void testFeatureProperties() throws IOException { + public void testUpdateCoalescing() { validateTestSetup(); - onView(withId(R.id.mapView)).perform(new BaseViewAction() { - - @Override - public void perform(UiController uiController, View view) { - GeoJsonSource source = null; - try { - source = new GeoJsonSource("source", - ResourceUtils.readRawResource(rule.getActivity(), R.raw.test_feature_properties)); - } catch (IOException exception) { - Timber.e(exception); - } - mapboxMap.addSource(source); - - mapboxMap.addLayer(new CircleLayer("layer", source.getId())); + MapboxMapAction.invoke(mapboxMap, (uiController, mapboxMap) -> { + GeoJsonSource source = new GeoJsonSource("source"); + mapboxMap.addSource(source); + mapboxMap.addLayer(new CircleLayer("layer", source.getId())); + + source.setGeoJson(Point.fromLngLat(0, 0)); + source.setGeoJson(Point.fromLngLat(-25, -25)); + try { + source.setGeoJson(ResourceUtils.readRawResource(rule.getActivity(), R.raw.test_feature_properties)); + } catch (IOException exception) { + Timber.e(exception); } + source.setGeoJson(Point.fromLngLat(20, 55)); + uiController.loopMainThreadForAtLeast(1000); + assertTrue( + mapboxMap.queryRenderedFeatures( + mapboxMap.getProjection().toScreenLocation( + new LatLng(55, 20)), "layer").size() == 1); }); } @@ -135,25 +144,20 @@ public class GeoJsonSourceTests extends BaseActivityTest { protected void testFeatureFromResource(final @RawRes int resource) { validateTestSetup(); - onView(withId(R.id.mapView)).perform(new BaseViewAction() { - - @Override - public void perform(UiController uiController, View view) { - GeoJsonSource source = new GeoJsonSource("source"); - mapboxMap.addSource(source); - Layer layer = new CircleLayer("layer", source.getId()); - mapboxMap.addLayer(layer); - - try { - source.setGeoJson(Feature.fromJson(ResourceUtils.readRawResource(rule.getActivity(), resource))); - } catch (IOException exception) { - Timber.e(exception); - } - - mapboxMap.removeLayer(layer); - mapboxMap.removeSource(source); + MapboxMapAction.invoke(mapboxMap, (uiController, mapboxMap) -> { + GeoJsonSource source = new GeoJsonSource("source"); + mapboxMap.addSource(source); + Layer layer = new CircleLayer("layer", source.getId()); + mapboxMap.addLayer(layer); + + try { + source.setGeoJson(Feature.fromJson(ResourceUtils.readRawResource(rule.getActivity(), resource))); + } catch (IOException exception) { + Timber.e(exception); } + mapboxMap.removeLayer(layer); + mapboxMap.removeSource(source); }); } -- cgit v1.2.1 From 5ce64b786cfd2fbfdc28ccfbcf9c1a5216346281 Mon Sep 17 00:00:00 2001 From: Mikhail Pozdnyakov Date: Fri, 10 Aug 2018 14:45:57 +0300 Subject: [ios, macos] Introduce `MGLShapeSourceOptionLineDistanceMetrics` Exposes access to https://www.mapbox.com/mapbox-gl-js/style-spec/#sources-geojson-lineMetrics --- platform/darwin/docs/guides/For Style Authors.md.ejs | 1 + platform/darwin/src/MGLShapeSource.h | 12 ++++++++++++ platform/darwin/src/MGLShapeSource.mm | 9 +++++++++ platform/darwin/test/MGLShapeSourceTests.mm | 4 +++- platform/ios/CHANGELOG.md | 1 + platform/ios/docs/guides/For Style Authors.md | 1 + platform/macos/CHANGELOG.md | 1 + platform/macos/docs/guides/For Style Authors.md | 1 + 8 files changed, 29 insertions(+), 1 deletion(-) diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs index 940c9b1042..dd07ae9e76 100644 --- a/platform/darwin/docs/guides/For Style Authors.md.ejs +++ b/platform/darwin/docs/guides/For Style Authors.md.ejs @@ -222,6 +222,7 @@ In style JSON | In the SDK `cluster` | `MGLShapeSourceOptionClustered` `clusterRadius` | `MGLShapeSourceOptionClusterRadius` `clusterMaxZoom` | `MGLShapeSourceOptionMaximumZoomLevelForClustering` +`lineMetrics` | `MGLShapeSourceOptionLineDistanceMetrics` To create a shape source from local GeoJSON data, first [convert the GeoJSON data into a shape](working-with-geojson-data.html#converting-geojson-data-into-shape-objects), diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h index e5c62515e5..c80c329cbc 100644 --- a/platform/darwin/src/MGLShapeSource.h +++ b/platform/darwin/src/MGLShapeSource.h @@ -95,6 +95,18 @@ FOUNDATION_EXTERN MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionBuff */ FOUNDATION_EXTERN MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance; +/** + An `NSNumber` object containing a Boolean enabling or disabling calculating line distance metrics. + + Set this property to `YES` in order for the `MGLLineStyleLayer.lineGradient` property to have its intended effect. + The default value is `NO`. + + This option corresponds to the + lineMetrics + source property in the Mapbox Style Specification. + */ +FOUNDATION_EXTERN MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionLineDistanceMetrics; + /** `MGLShapeSource` is a map content source that supplies vector shapes to be shown on the map. The shapes may be instances of `MGLShape` or `MGLFeature`, diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm index 9457d2569a..c960f2a4a7 100644 --- a/platform/darwin/src/MGLShapeSource.mm +++ b/platform/darwin/src/MGLShapeSource.mm @@ -20,6 +20,7 @@ const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevel = @"MGLShapeSour const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @"MGLShapeSourceOptionMaximumZoomLevelForClustering"; const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel = @"MGLShapeSourceOptionMinimumZoomLevel"; const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance"; +const MGLShapeSourceOption MGLShapeSourceOptionLineDistanceMetrics = @"MGLShapeSourceOptionLineDistanceMetrics"; mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary *options) { auto geoJSONOptions = mbgl::style::GeoJSONOptions(); @@ -80,6 +81,14 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary Date: Fri, 17 Aug 2018 22:23:32 +0200 Subject: [android] - expose stylejsoon confiugration on MapboxMapOptions and MapView attributes --- .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 15 ++++++- .../mapbox/mapboxsdk/maps/MapboxMapOptions.java | 52 +++++++++++++++++----- .../src/main/res-public/values/public.xml | 1 + .../src/main/res/values/attrs.xml | 1 + .../mapboxsdk/maps/MapboxMapOptionsTest.java | 6 +-- .../TextureViewTransparentBackgroundActivity.java | 36 +++++++++------ .../layout/activity_textureview_transparent.xml | 11 ----- 7 files changed, 83 insertions(+), 39 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 97e2e50525..45e54a3d14 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -95,6 +95,7 @@ public final class MapboxMap { setDebugActive(options.getDebugActive()); setApiBaseUrl(options); setStyleUrl(options); + setStyleJson(options); setPrefetchesTiles(options); } @@ -1058,7 +1059,7 @@ public final class MapboxMap { * @param options the object containing the style url */ private void setStyleUrl(@NonNull MapboxMapOptions options) { - String style = options.getStyle(); + String style = options.getStyleUrl(); if (!TextUtils.isEmpty(style)) { setStyleUrl(style, null); } @@ -1086,6 +1087,18 @@ public final class MapboxMap { nativeMapView.setStyleJson(styleJson); } + /** + * Loads a new map style json from MapboxMapOptions if available. + * + * @param options the object containing the style json + */ + private void setStyleJson(@NonNull MapboxMapOptions options) { + String styleJson = options.getStyleJson(); + if (!TextUtils.isEmpty(styleJson)) { + setStyleJson(styleJson); + } + } + /** * Returns the map style json currently displayed in the map view. * diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java index 0075199b1e..f48bd92327 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java @@ -77,7 +77,8 @@ public class MapboxMapOptions implements Parcelable { @ColorInt private int foregroundLoadColor; - private String style; + private String styleUrl; + private String styleJson; private float pixelRatio; @@ -120,7 +121,8 @@ public class MapboxMapOptions implements Parcelable { zoomGesturesEnabled = in.readByte() != 0; doubleTapGesturesEnabled = in.readByte() != 0; - style = in.readString(); + styleUrl = in.readString(); + styleJson = in.readString(); apiBaseUrl = in.readString(); textureMode = in.readByte() != 0; translucentTextureSurface = in.readByte() != 0; @@ -145,6 +147,7 @@ public class MapboxMapOptions implements Parcelable { try { mapboxMapOptions.camera(new CameraPosition.Builder(typedArray).build()); mapboxMapOptions.styleUrl(typedArray.getString(R.styleable.mapbox_MapView_mapbox_styleUrl)); + mapboxMapOptions.styleJson(typedArray.getString(R.styleable.mapbox_MapView_mapbox_styleJson)); mapboxMapOptions.apiBaseUrl(typedArray.getString(R.styleable.mapbox_MapView_mapbox_apiBaseUrl)); mapboxMapOptions.zoomGesturesEnabled( @@ -258,13 +261,24 @@ public class MapboxMapOptions implements Parcelable { } /** - * Specifies the style url associated with a map view. + * Specifies the styleUrl url associated with a map view. * - * @param styleUrl Url to be used to load a style + * @param styleUrl Url to be used to load a styleUrl * @return This */ public MapboxMapOptions styleUrl(String styleUrl) { - style = styleUrl; + this.styleUrl = styleUrl; + return this; + } + + /** + * Specifies the styleJson associated with a map view. + * + * @param styleJson json to used as style + * @return This + */ + public MapboxMapOptions styleJson(String styleJson) { + this.styleJson = styleJson; return this; } @@ -716,12 +730,21 @@ public class MapboxMapOptions implements Parcelable { } /** - * Get the current configured style url for a map view. + * Get the current configured styleUrl url for a map view. * * @return Style url to be used. */ - public String getStyle() { - return style; + public String getStyleUrl() { + return styleUrl; + } + + /** + * Get the current configured styleJson for a map view. + * + * @return Style json to be used. + */ + public String getStyleJson() { + return styleJson; } /** @@ -912,7 +935,8 @@ public class MapboxMapOptions implements Parcelable { dest.writeByte((byte) (zoomGesturesEnabled ? 1 : 0)); dest.writeByte((byte) (doubleTapGesturesEnabled ? 1 : 0)); - dest.writeString(style); + dest.writeString(styleUrl); + dest.writeString(styleJson); dest.writeString(apiBaseUrl); dest.writeByte((byte) (textureMode ? 1 : 0)); dest.writeByte((byte) (translucentTextureSurface ? 1 : 0)); @@ -1002,9 +1026,14 @@ public class MapboxMapOptions implements Parcelable { if (!Arrays.equals(attributionMargins, options.attributionMargins)) { return false; } - if (style != null ? !style.equals(options.style) : options.style != null) { + if (styleUrl != null ? !styleUrl.equals(options.styleUrl) : options.styleUrl != null) { return false; } + + if (styleJson != null ? !styleJson.equals(options.styleJson) : options.styleJson != null) { + return false; + } + if (apiBaseUrl != null ? !apiBaseUrl.equals(options.apiBaseUrl) : options.apiBaseUrl != null) { return false; } @@ -1055,7 +1084,8 @@ public class MapboxMapOptions implements Parcelable { result = 31 * result + (apiBaseUrl != null ? apiBaseUrl.hashCode() : 0); result = 31 * result + (textureMode ? 1 : 0); result = 31 * result + (translucentTextureSurface ? 1 : 0); - result = 31 * result + (style != null ? style.hashCode() : 0); + result = 31 * result + (styleUrl != null ? styleUrl.hashCode() : 0); + result = 31 * result + (styleJson != null ? styleJson.hashCode() : 0); result = 31 * result + (prefetchesTiles ? 1 : 0); result = 31 * result + (zMediaOverlay ? 1 : 0); result = 31 * result + (localIdeographFontFamily != null ? localIdeographFontFamily.hashCode() : 0); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml index 8acb0c27cc..1c3653479a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res-public/values/public.xml @@ -10,6 +10,7 @@ + diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml index 3a8fa74b34..053da80ade 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml @@ -4,6 +4,7 @@ + diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java index 9dd0ca9285..b8a377604f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java @@ -155,9 +155,9 @@ public class MapboxMapOptionsTest { @Test public void testStyleUrl() { - assertEquals(Style.DARK, new MapboxMapOptions().styleUrl(Style.DARK).getStyle()); - assertNotEquals(Style.LIGHT, new MapboxMapOptions().styleUrl(Style.DARK).getStyle()); - assertNull(new MapboxMapOptions().getStyle()); + assertEquals(Style.DARK, new MapboxMapOptions().styleUrl(Style.DARK).getStyleUrl()); + assertNotEquals(Style.LIGHT, new MapboxMapOptions().styleUrl(Style.DARK).getStyleUrl()); + assertNull(new MapboxMapOptions().getStyleUrl()); } @Test diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewTransparentBackgroundActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewTransparentBackgroundActivity.java index 15da018b0e..3a62e39173 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewTransparentBackgroundActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/textureview/TextureViewTransparentBackgroundActivity.java @@ -2,10 +2,14 @@ package com.mapbox.mapboxsdk.testapp.activity.textureview; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; +import android.view.ViewGroup; import android.widget.ImageView; +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.MapboxMapOptions; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils; @@ -30,23 +34,30 @@ public class TextureViewTransparentBackgroundActivity extends AppCompatActivity } private void setupBackground() { - ImageView imageView = (ImageView) findViewById(R.id.imageView); + ImageView imageView = findViewById(R.id.imageView); imageView.setImageResource(R.drawable.water); imageView.setScaleType(ImageView.ScaleType.FIT_XY); } private void setupMapView(Bundle savedInstanceState) { - mapView = (MapView) findViewById(R.id.mapView); - mapView.onCreate(savedInstanceState); - mapView.getMapAsync(map -> { - mapboxMap = map; - - try { - map.setStyleJson(ResourceUtils.readRawResource(getApplicationContext(), R.raw.no_bg_style)); - } catch (IOException exception) { - Timber.e(exception); - } - }); + try { + MapboxMapOptions mapboxMapOptions = new MapboxMapOptions(); + mapboxMapOptions.styleJson(ResourceUtils.readRawResource(this, R.raw.no_bg_style)); + mapboxMapOptions.translucentTextureSurface(true); + mapboxMapOptions.textureMode(true); + mapboxMapOptions.camera(new CameraPosition.Builder() + .zoom(2) + .target(new LatLng(48.507879, 8.363795)) + .build() + ); + + mapView = new MapView(this, mapboxMapOptions); + mapView.onCreate(savedInstanceState); + mapView.getMapAsync(map -> mapboxMap = map); + ((ViewGroup) findViewById(R.id.coordinator_layout)).addView(mapView); + } catch (IOException exception) { + Timber.e(exception); + } } @Override @@ -90,5 +101,4 @@ public class TextureViewTransparentBackgroundActivity extends AppCompatActivity super.onLowMemory(); mapView.onLowMemory(); } - } \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml index 1d99e61d74..096d44e223 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_textureview_transparent.xml @@ -1,7 +1,6 @@ - - -- cgit v1.2.1 From 2ff1ac309727a5f34cfa9472dc5802d5b5c3113c Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 17 Aug 2018 16:25:12 -0700 Subject: [android] Move conversion code to .cpp files --- platform/android/core-files.txt | 15 ++ platform/android/src/conversion/collection.cpp | 38 ++++ platform/android/src/conversion/collection.hpp | 34 +--- platform/android/src/conversion/color.cpp | 17 ++ platform/android/src/conversion/color.hpp | 8 +- platform/android/src/conversion/constant.cpp | 86 +++++++++ platform/android/src/conversion/constant.hpp | 75 ++------ .../android/src/geojson/conversion/feature.cpp | 192 ++++++++++++++++++++ .../android/src/geojson/conversion/feature.hpp | 194 +-------------------- platform/android/src/style/conversion/filter.cpp | 26 +++ platform/android/src/style/conversion/filter.hpp | 21 +-- platform/android/src/style/conversion/position.cpp | 24 +++ platform/android/src/style/conversion/position.hpp | 26 +-- .../src/style/conversion/property_expression.hpp | 16 +- .../src/style/conversion/property_value.hpp | 16 +- .../src/style/conversion/transition_options.cpp | 16 ++ .../src/style/conversion/transition_options.hpp | 19 +- .../src/style/conversion/url_or_tileset.cpp | 30 ++++ .../src/style/conversion/url_or_tileset.hpp | 27 +-- 19 files changed, 493 insertions(+), 387 deletions(-) create mode 100644 platform/android/src/conversion/collection.cpp create mode 100644 platform/android/src/conversion/color.cpp create mode 100644 platform/android/src/conversion/constant.cpp create mode 100644 platform/android/src/geojson/conversion/feature.cpp create mode 100644 platform/android/src/style/conversion/filter.cpp create mode 100644 platform/android/src/style/conversion/position.cpp create mode 100644 platform/android/src/style/conversion/transition_options.cpp create mode 100644 platform/android/src/style/conversion/url_or_tileset.cpp diff --git a/platform/android/core-files.txt b/platform/android/core-files.txt index 7d86cb5615..ef9ec65df7 100644 --- a/platform/android/core-files.txt +++ b/platform/android/core-files.txt @@ -48,12 +48,27 @@ platform/default/mbgl/map/map_snapshotter.hpp platform/linux/src/headless_backend_egl.cpp # Conversion C++ -> Java +platform/android/src/conversion/collection.cpp +platform/android/src/conversion/collection.hpp +platform/android/src/conversion/color.cpp +platform/android/src/conversion/color.hpp +platform/android/src/conversion/constant.cpp platform/android/src/conversion/constant.hpp platform/android/src/conversion/conversion.hpp +platform/android/src/geojson/conversion/feature.cpp +platform/android/src/geojson/conversion/feature.hpp +platform/android/src/style/conversion/filter.cpp +platform/android/src/style/conversion/filter.hpp +platform/android/src/style/conversion/position.cpp +platform/android/src/style/conversion/position.hpp platform/android/src/style/conversion/property_expression.hpp platform/android/src/style/conversion/property_value.hpp +platform/android/src/style/conversion/transition_options.cpp +platform/android/src/style/conversion/transition_options.hpp platform/android/src/style/conversion/types.hpp platform/android/src/style/conversion/types_string_values.hpp +platform/android/src/style/conversion/url_or_tileset.cpp +platform/android/src/style/conversion/url_or_tileset.hpp platform/android/src/map/camera_position.cpp platform/android/src/map/camera_position.hpp platform/android/src/map/image.cpp diff --git a/platform/android/src/conversion/collection.cpp b/platform/android/src/conversion/collection.cpp new file mode 100644 index 0000000000..14d817ea88 --- /dev/null +++ b/platform/android/src/conversion/collection.cpp @@ -0,0 +1,38 @@ +#include "collection.hpp" +#include "constant.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +std::vector toVector(JNIEnv& env, jni::jarray& array) { + std::vector vector; + std::size_t len = jni::GetArrayLength(env, array); + vector.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + jni::jstring* jstr = reinterpret_cast(jni::GetObjectArrayElement(env, array, i)); + vector.push_back(*convert(env, jni::String(jstr))); + jni::DeleteLocalRef(env, jstr); + } + + return vector; +} + +std::vector toVector(JNIEnv& env, jni::Array array) { + std::size_t len = array.Length(env); + std::vector vector; + vector.reserve(len); + + for (std::size_t i = 0; i < len; i++) { + jni::String jstr = array.Get(env, i); + vector.push_back(*convert(env, jstr)); + jni::DeleteLocalRef(env, jstr); + } + + return vector; +} + +} +} +} diff --git a/platform/android/src/conversion/collection.hpp b/platform/android/src/conversion/collection.hpp index 2b953e73f4..973897b212 100644 --- a/platform/android/src/conversion/collection.hpp +++ b/platform/android/src/conversion/collection.hpp @@ -1,9 +1,7 @@ #pragma once #include "conversion.hpp" -#include "constant.hpp" -#include #include #include @@ -16,7 +14,7 @@ namespace conversion { * Convert jarray -> ArrayList */ template -inline jni::jobject* toArrayList(JNIEnv& env, jni::jarray& array) { +jni::jobject* toArrayList(JNIEnv& env, jni::jarray& array) { static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Arrays")).release(); static jni::jmethodID* asList = &jni::GetStaticMethodID(env, *javaClass, "asList", "([Ljava/lang/Object;)Ljava/util/List;"); return reinterpret_cast(jni::CallStaticMethod(env, *javaClass, *asList, array)); @@ -24,34 +22,8 @@ inline jni::jobject* toArrayList(JNIEnv& env, jni::jarray& array) { // Java -> C++ - -inline std::vector toVector(JNIEnv& env, jni::jarray& array) { - std::vector vector; - std::size_t len = jni::GetArrayLength(env, array); - vector.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - jni::jstring* jstr = reinterpret_cast(jni::GetObjectArrayElement(env, array, i)); - vector.push_back(*convert(env, jni::String(jstr))); - jni::DeleteLocalRef(env, jstr); - } - - return vector; -} - -inline std::vector toVector(JNIEnv& env, jni::Array array) { - std::size_t len = array.Length(env); - std::vector vector; - vector.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - jni::String jstr = array.Get(env, i); - vector.push_back(*convert(env, jstr)); - jni::DeleteLocalRef(env, jstr); - } - - return vector; -} +std::vector toVector(JNIEnv& env, jni::jarray& array); +std::vector toVector(JNIEnv& env, jni::Array array); } } diff --git a/platform/android/src/conversion/color.cpp b/platform/android/src/conversion/color.cpp new file mode 100644 index 0000000000..ce85943e61 --- /dev/null +++ b/platform/android/src/conversion/color.cpp @@ -0,0 +1,17 @@ +#include "color.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result Converter::operator()(jni::JNIEnv&, const int& color) const { + float r = (color >> 16) & 0xFF; + float g = (color >> 8) & 0xFF; + float b = (color) & 0xFF; + float a = (color >> 24) & 0xFF; + return { mbgl::Color( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ) }; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/platform/android/src/conversion/color.hpp b/platform/android/src/conversion/color.hpp index 40aa68d4a9..2b4144b933 100644 --- a/platform/android/src/conversion/color.hpp +++ b/platform/android/src/conversion/color.hpp @@ -10,13 +10,7 @@ namespace conversion { template <> struct Converter { - Result operator()(jni::JNIEnv&, const int& color) const { - float r = (color >> 16) & 0xFF; - float g = (color >> 8) & 0xFF; - float b = (color) & 0xFF; - float a = (color >> 24) & 0xFF; - return { mbgl::Color( r / 255.0f, g / 255.0f, b / 255.0f, a / 255.0f ) }; - } + Result operator()(jni::JNIEnv&, const int& color) const; }; } // namespace conversion diff --git a/platform/android/src/conversion/constant.cpp b/platform/android/src/conversion/constant.cpp new file mode 100644 index 0000000000..cce0796ce5 --- /dev/null +++ b/platform/android/src/conversion/constant.cpp @@ -0,0 +1,86 @@ +#include "constant.hpp" + +#include + +namespace mbgl { +namespace android { +namespace conversion { + +Result Converter::operator()(jni::JNIEnv& env, const bool& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Boolean")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(Z)V"); + return {&jni::NewObject(env, *javaClass, *constructor, (jboolean) value)}; +} + +Result Converter::operator()(jni::JNIEnv&, const bool& value) const { + return {(jni::jboolean) value}; +} + +Result Converter::operator()(jni::JNIEnv& env, const float& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Float")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(F)V"); + return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)}; +} + +Result Converter::operator()(jni::JNIEnv&, const float& value) const { + return {(jni::jfloat) value}; +} + +Result Converter::operator()(jni::JNIEnv& env, const double& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Double")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(D)V"); + return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)}; +} + +Result Converter::operator()(jni::JNIEnv&, const double& value) const { + return {(jni::jdouble) value}; +} + +Result Converter::operator()(jni::JNIEnv& env, const std::string& value) const { + return {jni::Make(env, value).Get()}; +} + +Result Converter::operator()(jni::JNIEnv& env, const std::string& value) const { + return {jni::Make(env, value).Get()}; +} + +Result Converter::operator()(jni::JNIEnv& env, const Color& value) const { + std::stringstream sstream; + sstream << "rgba(" << value.r << ", " << value.g << ", " << value.b << ", " << value.a << ")"; + std::string result = sstream.str(); + return convert(env, result); +} + +Result Converter>::operator()(jni::JNIEnv& env, const std::vector& value) const { + static jni::jclass* stringCass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/String")).release(); + jni::jarray& jarray = jni::NewObjectArray(env, value.size(), *stringCass); + + for(size_t i = 0; i < value.size(); i = i + 1) { + Result converted = convert(env, value.at(i)); + jni::SetObjectArrayElement(env, jarray, i, *converted); + } + + return &jarray; +} + +Result Converter>::operator()(jni::JNIEnv& env, const std::vector& value) const { + static jni::jclass* floatClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Float")).release(); + jni::jarray& jarray = jni::NewObjectArray(env, value.size(), *floatClass); + + for(size_t i = 0; i < value.size(); i = i + 1) { + Result converted = convert(env, value.at(i)); + jni::SetObjectArrayElement(env, jarray, i, *converted); + } + + return &jarray; +} + +// Java -> C++ + +Result Converter::operator()(jni::JNIEnv& env, const jni::String& value) const { + return { jni::Make(env, value) }; +} + +} // namespace conversion +} // namespace style +} // namespace mbgl diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp index f1c72eb5dd..52395cb9ee 100644 --- a/platform/android/src/conversion/constant.hpp +++ b/platform/android/src/conversion/constant.hpp @@ -2,14 +2,12 @@ #include "conversion.hpp" -#include #include #include #include #include #include -#include namespace mbgl { namespace android { @@ -17,51 +15,33 @@ namespace conversion { template <> struct Converter { - Result operator()(jni::JNIEnv& env, const bool& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Boolean")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(Z)V"); - return {&jni::NewObject(env, *javaClass, *constructor, (jboolean) value)}; - } + Result operator()(jni::JNIEnv& env, const bool& value) const; }; template <> struct Converter { - Result operator()(jni::JNIEnv&, const bool& value) const { - return {(jni::jboolean) value}; - } + Result operator()(jni::JNIEnv&, const bool& value) const; }; template <> struct Converter { - Result operator()(jni::JNIEnv& env, const float& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Float")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(F)V"); - return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)}; - } + Result operator()(jni::JNIEnv& env, const float& value) const; }; template <> struct Converter { - Result operator()(jni::JNIEnv&, const float& value) const { - return {(jni::jfloat) value}; - } + Result operator()(jni::JNIEnv&, const float& value) const; }; template <> struct Converter { - Result operator()(jni::JNIEnv& env, const double& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Double")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(D)V"); - return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)}; - } + Result operator()(jni::JNIEnv& env, const double& value) const; }; template <> struct Converter { - Result operator()(jni::JNIEnv&, const double& value) const { - return {(jni::jdouble) value}; - } + Result operator()(jni::JNIEnv&, const double& value) const; }; /** @@ -81,26 +61,17 @@ struct Converter:: template <> struct Converter { - Result operator()(jni::JNIEnv& env, const std::string& value) const { - return {jni::Make(env, value).Get()}; - } + Result operator()(jni::JNIEnv& env, const std::string& value) const; }; template <> struct Converter { - Result operator()(jni::JNIEnv& env, const std::string& value) const { - return {jni::Make(env, value).Get()}; - } + Result operator()(jni::JNIEnv& env, const std::string& value) const; }; template <> struct Converter { - Result operator()(jni::JNIEnv& env, const Color& value) const { - std::stringstream sstream; - sstream << "rgba(" << value.r << ", " << value.g << ", " << value.b << ", " << value.a << ")"; - std::string result = sstream.str(); - return convert(env, result); - } + Result operator()(jni::JNIEnv& env, const Color& value) const; }; template @@ -116,41 +87,19 @@ struct Converter> { template <> struct Converter> { - Result operator()(jni::JNIEnv& env, const std::vector& value) const { - static jni::jclass* stringCass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/String")).release(); - jni::jarray& jarray = jni::NewObjectArray(env, value.size(), *stringCass); - - for(size_t i = 0; i < value.size(); i = i + 1) { - Result converted = convert(env, value.at(i)); - jni::SetObjectArrayElement(env, jarray, i, *converted); - } - - return &jarray; - } + Result operator()(jni::JNIEnv& env, const std::vector& value) const; }; template <> struct Converter> { - Result operator()(jni::JNIEnv& env, const std::vector& value) const { - static jni::jclass* floatClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Float")).release(); - jni::jarray& jarray = jni::NewObjectArray(env, value.size(), *floatClass); - - for(size_t i = 0; i < value.size(); i = i + 1) { - Result converted = convert(env, value.at(i)); - jni::SetObjectArrayElement(env, jarray, i, *converted); - } - - return &jarray; - } + Result operator()(jni::JNIEnv& env, const std::vector& value) const; }; // Java -> C++ template <> struct Converter { - Result operator()(jni::JNIEnv& env, const jni::String& value) const { - return { jni::Make(env, value) }; - } + Result operator()(jni::JNIEnv& env, const jni::String& value) const; }; } // namespace conversion diff --git a/platform/android/src/geojson/conversion/feature.cpp b/platform/android/src/geojson/conversion/feature.cpp new file mode 100644 index 0000000000..8dff05aa12 --- /dev/null +++ b/platform/android/src/geojson/conversion/feature.cpp @@ -0,0 +1,192 @@ +#include "feature.hpp" +#include "geometry.hpp" + +#include "../../conversion/constant.hpp" +#include "../../conversion/conversion.hpp" +#include "../../jni/local_object.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +/** + * Turn feature identifier into std::string + */ +class FeatureIdVisitor { +public: + + template + std::string operator()(const T& i) const { + return std::to_string(i); + } + + std::string operator()(const std::string& i) const { + return i; + } + + std::string operator()(const std::nullptr_t&) const { + return ""; + } + +}; + +/** + * Turn properties into Java GSON JsonObject's + */ +class PropertyValueEvaluator { +public: + jni::JNIEnv& env; + + /** + * null + */ + jni::jobject* operator()(const mapbox::geometry::null_value_t &) const { + return (jni::jobject*) nullptr; + } + + /** + * Boolean primitive + */ + jni::jobject* operator()(const bool& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(Ljava/lang/Boolean;)V"); + + // Create JsonPrimitive + jni::LocalObject converted = jni::NewLocalObject(env, *convert(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, *converted); + + return object; + } + + /** + * String primitive + */ + jni::jobject* operator()(const std::string& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(Ljava/lang/String;)V"); + + // Create JsonPrimitive + jni::LocalObject converted = jni::NewLocalObject(env, *convert(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); + + return object; + } + + /** + * Number primitives + */ + template + jni::jobject* operator()(const Number& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(Ljava/lang/Number;)V"); + + // Create JsonPrimitive + jni::LocalObject converted = jni::NewLocalObject(env, *convert(env, value)); + jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); + + return object; + } + + + /** + * Json Array + */ + jni::jobject* operator()(const std::vector &values) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonArray")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "()V");; + static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Lcom/google/gson/JsonElement;)V"); + + // Create json array + jni::jobject* jarray = &jni::NewObject(env, *javaClass, *constructor); + + // Add values + for (const auto &v : values) { + jni::LocalObject converted = jni::NewLocalObject(env, mbgl::Value::visit(v, *this)); + jni::CallMethod(env, jarray, *add, converted.get()); + } + + return jarray; + } + + /** + * Json Object + */ + jni::jobject* operator()(const std::unordered_map &value) const { + // TODO: clean up duplication here + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "()V");; + static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V"); + + // Create json object + jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor); + + // Add items + for (auto &item : value) { + jni::LocalObject converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, *this)); + jni::LocalObject key = jni::NewLocalObject(env, *convert(env, item.first)); + jni::CallMethod(env, jsonObject, *add, key.get(), converted.get()); + } + + return jsonObject; + } +}; + +Result Converter>::operator()(jni::JNIEnv& env, const std::unordered_map& value) const { + static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release(); + static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "()V");; + static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V"); + + // Create json object + jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor); + + // Add items + PropertyValueEvaluator evaluator {env}; + for (auto &item : value) { + jni::LocalObject converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, evaluator)); + jni::LocalObject key = jni::NewLocalObject(env, *convert(env, item.first)); + jni::CallMethod(env, jsonObject, *add, key.get(), converted.get()); + } + + return {jsonObject}; +} + +Result> Converter, mbgl::Feature>::operator()(jni::JNIEnv& env, const mbgl::Feature& value) const { + + // Convert Id + FeatureIdVisitor idEvaluator; + std::string id = (value.id) ? mapbox::geometry::identifier::visit(value.id.value(), idEvaluator) : ""; + auto jid = jni::Make(env, id); + + // Convert properties + auto properties = jni::Object(*convert(env, value.properties)); + + // Convert geometry + auto geometry = *convert>(env, value.geometry); + + // Create feature + auto feature = android::geojson::Feature::fromGeometry(env, geometry, properties, jid); + + //Cleanup + jni::DeleteLocalRef(env, jid); + jni::DeleteLocalRef(env, geometry); + jni::DeleteLocalRef(env, properties); + + return feature; +} + +Result>> Converter>, std::vector>::operator()(jni::JNIEnv& env, const std::vector& value) const { + using namespace mbgl::android::geojson; + auto features = jni::Array>::New(env, value.size(), Feature::javaClass); + + for(size_t i = 0; i < value.size(); i = i + 1) { + auto converted = *convert, mbgl::Feature>(env, value.at(i)); + features.Set(env, i, converted); + jni::DeleteLocalRef(env, converted); + } + + return {features}; +} + +} // namespace conversion +} // namespace android +} // namespace mbgl diff --git a/platform/android/src/geojson/conversion/feature.hpp b/platform/android/src/geojson/conversion/feature.hpp index 8fc62a2789..031449cd23 100644 --- a/platform/android/src/geojson/conversion/feature.hpp +++ b/platform/android/src/geojson/conversion/feature.hpp @@ -1,215 +1,31 @@ #pragma once -#include "../../conversion/constant.hpp" #include "../../conversion/conversion.hpp" -#include "geometry.hpp" -#include "../../gson/json_object.hpp" +#include "../feature.hpp" #include -#include -#include - #include -#include "../../jni/local_object.hpp" -#include "../feature.hpp" -#include -#include #include -#include - -#include +#include namespace mbgl { namespace android { namespace conversion { -/** - * Turn feature identifier into std::string - */ -class FeatureIdVisitor { -public: - - template - std::string operator()(const T& i) const { - return std::to_string(i); - } - - std::string operator()(const std::string& i) const { - return i; - } - - std::string operator()(const std::nullptr_t&) const { - return ""; - } - -}; - -/** - * Turn properties into Java GSON JsonObject's - */ -class PropertyValueEvaluator { -public: - jni::JNIEnv& env; - - /** - * null - */ - jni::jobject* operator()(const mapbox::geometry::null_value_t &) const { - return (jni::jobject*) nullptr; - } - - /** - * Boolean primitive - */ - jni::jobject* operator()(const bool& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(Ljava/lang/Boolean;)V"); - - // Create JsonPrimitive - jni::LocalObject converted = jni::NewLocalObject(env, *convert(env, value)); - jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, *converted); - - return object; - } - - /** - * String primitive - */ - jni::jobject* operator()(const std::string& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(Ljava/lang/String;)V"); - - // Create JsonPrimitive - jni::LocalObject converted = jni::NewLocalObject(env, *convert(env, value)); - jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); - - return object; - } - - /** - * Number primitives - */ - template - jni::jobject* operator()(const Number& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonPrimitive")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(Ljava/lang/Number;)V"); - - // Create JsonPrimitive - jni::LocalObject converted = jni::NewLocalObject(env, *convert(env, value)); - jni::jobject* object = &jni::NewObject(env, *javaClass, *constructor, converted.get()); - - return object; - } - - - /** - * Json Array - */ - jni::jobject* operator()(const std::vector &values) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonArray")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "()V");; - static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Lcom/google/gson/JsonElement;)V"); - - // Create json array - jni::jobject* jarray = &jni::NewObject(env, *javaClass, *constructor); - - // Add values - for (const auto &v : values) { - jni::LocalObject converted = jni::NewLocalObject(env, mbgl::Value::visit(v, *this)); - jni::CallMethod(env, jarray, *add, converted.get()); - } - - return jarray; - } - - /** - * Json Object - */ - jni::jobject* operator()(const std::unordered_map &value) const { - // TODO: clean up duplication here - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "()V");; - static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V"); - - // Create json object - jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor); - - // Add items - for (auto &item : value) { - jni::LocalObject converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, *this)); - jni::LocalObject key = jni::NewLocalObject(env, *convert(env, item.first)); - jni::CallMethod(env, jsonObject, *add, key.get(), converted.get()); - } - - return jsonObject; - } -}; - template <> struct Converter> { - Result operator()(jni::JNIEnv& env, const std::unordered_map& value) const { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "com/google/gson/JsonObject")).release(); - static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "()V");; - static jni::jmethodID* add = &jni::GetMethodID(env, *javaClass, "add", "(Ljava/lang/String;Lcom/google/gson/JsonElement;)V"); - - // Create json object - jni::jobject* jsonObject = &jni::NewObject(env, *javaClass, *constructor); - - // Add items - PropertyValueEvaluator evaluator {env}; - for (auto &item : value) { - jni::LocalObject converted = jni::NewLocalObject(env, mbgl::Value::visit(item.second, evaluator)); - jni::LocalObject key = jni::NewLocalObject(env, *convert(env, item.first)); - jni::CallMethod(env, jsonObject, *add, key.get(), converted.get()); - } - - return {jsonObject}; - } + Result operator()(jni::JNIEnv& env, const std::unordered_map& value) const; }; - template <> struct Converter, mbgl::Feature> { - Result> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const { - - // Convert Id - FeatureIdVisitor idEvaluator; - std::string id = (value.id) ? mapbox::geometry::identifier::visit(value.id.value(), idEvaluator) : ""; - auto jid = jni::Make(env, id); - - // Convert properties - auto properties = jni::Object(*convert(env, value.properties)); - - // Convert geometry - auto geometry = *convert>(env, value.geometry); - - // Create feature - auto feature = android::geojson::Feature::fromGeometry(env, geometry, properties, jid); - - //Cleanup - jni::DeleteLocalRef(env, jid); - jni::DeleteLocalRef(env, geometry); - jni::DeleteLocalRef(env, properties); - - return feature; - } + Result> operator()(jni::JNIEnv& env, const mbgl::Feature& value) const; }; template <> struct Converter>, std::vector> { - Result>> operator()(jni::JNIEnv& env, const std::vector& value) const { - using namespace mbgl::android::geojson; - auto features = jni::Array>::New(env, value.size(), Feature::javaClass); - - for(size_t i = 0; i < value.size(); i = i + 1) { - auto converted = *convert, mbgl::Feature>(env, value.at(i)); - features.Set(env, i, converted); - jni::DeleteLocalRef(env, converted); - } - - return {features}; - } + Result>> operator()(jni::JNIEnv& env, const std::vector& value) const; }; } // namespace conversion diff --git a/platform/android/src/style/conversion/filter.cpp b/platform/android/src/style/conversion/filter.cpp new file mode 100644 index 0000000000..4eac0cf82b --- /dev/null +++ b/platform/android/src/style/conversion/filter.cpp @@ -0,0 +1,26 @@ +#include "filter.hpp" +#include "../android_conversion.hpp" + +#include +#include + +namespace mbgl { +namespace android { +namespace conversion { + +optional toFilter(jni::JNIEnv& env, jni::Array> jfilter) { + mbgl::optional filter; + if (jfilter) { + mbgl::style::conversion::Error error; + auto converted = mbgl::style::conversion::convert(Value(env, jfilter), error); + if (!converted) { + mbgl::Log::Error(mbgl::Event::JNI, "Error converting filter: " + error.message); + } + filter = std::move(*converted); + } + return filter; +} + +} // namespace conversion +} // namespace android +} // namespace mbgl \ No newline at end of file diff --git a/platform/android/src/style/conversion/filter.hpp b/platform/android/src/style/conversion/filter.hpp index 241c98713a..df482de8f3 100644 --- a/platform/android/src/style/conversion/filter.hpp +++ b/platform/android/src/style/conversion/filter.hpp @@ -1,30 +1,15 @@ #pragma once -#include "../android_conversion.hpp" -#include -#include +#include +#include #include -#include -#include - namespace mbgl { namespace android { namespace conversion { -inline optional toFilter(jni::JNIEnv& env, jni::Array> jfilter) { - mbgl::optional filter; - if (jfilter) { - mbgl::style::conversion::Error error; - auto converted = mbgl::style::conversion::convert(Value(env, jfilter), error); - if (!converted) { - mbgl::Log::Error(mbgl::Event::JNI, "Error converting filter: " + error.message); - } - filter = std::move(*converted); - } - return filter; -} +optional toFilter(jni::JNIEnv&, jni::Array>); } // namespace conversion } // namespace android diff --git a/platform/android/src/style/conversion/position.cpp b/platform/android/src/style/conversion/position.cpp new file mode 100644 index 0000000000..9b3925914e --- /dev/null +++ b/platform/android/src/style/conversion/position.cpp @@ -0,0 +1,24 @@ +#include "position.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result> Converter, mbgl::style::Position>::operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const { + std::array cartPosition = value.getSpherical(); + return Position::fromPosition(env, cartPosition[0], cartPosition[1], cartPosition[2]); +} + +Result Converter>::operator()(jni::JNIEnv &env, const jni::Object &value) const { + float radialCoordinate = Position::getRadialCoordinate(env, value); + float azimuthalAngle = Position::getAzimuthalAngle(env, value); + float polarAngle = Position::getPolarAngle(env, value); + std::array cartPosition {{radialCoordinate, azimuthalAngle, polarAngle}}; + mbgl::style::Position position{}; + position.set(cartPosition); + return position; +} + +} +} +} diff --git a/platform/android/src/style/conversion/position.hpp b/platform/android/src/style/conversion/position.hpp index f32a892c0c..2ef4bf4395 100644 --- a/platform/android/src/style/conversion/position.hpp +++ b/platform/android/src/style/conversion/position.hpp @@ -1,37 +1,25 @@ #pragma once #include "../../conversion/conversion.hpp" +#include "../position.hpp" -#include #include -#include "../../jni/local_object.hpp" -#include "../position.hpp" +#include namespace mbgl { namespace android { namespace conversion { -template<> +template <> struct Converter, mbgl::style::Position> { - Result> operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const { - std::array cartPosition = value.getSpherical(); - return Position::fromPosition(env, cartPosition[0], cartPosition[1], cartPosition[2]); - } + Result> operator()(jni::JNIEnv &env, const mbgl::style::Position &value) const; }; -template<> +template <> struct Converter> { - Result operator()(jni::JNIEnv &env, const jni::Object &value) const { - float radialCoordinate = Position::getRadialCoordinate(env, value); - float azimuthalAngle = Position::getAzimuthalAngle(env, value); - float polarAngle = Position::getPolarAngle(env, value); - std::array cartPosition {{radialCoordinate, azimuthalAngle, polarAngle}}; - mbgl::style::Position position{}; - position.set(cartPosition); - return position; - } + Result operator()(jni::JNIEnv &env, const jni::Object &value) const; }; } } -} \ No newline at end of file +} diff --git a/platform/android/src/style/conversion/property_expression.hpp b/platform/android/src/style/conversion/property_expression.hpp index ae9d4ea41c..08429960cb 100644 --- a/platform/android/src/style/conversion/property_expression.hpp +++ b/platform/android/src/style/conversion/property_expression.hpp @@ -1,16 +1,11 @@ #pragma once -#include #include "../../conversion/conversion.hpp" -#include "../../conversion/constant.hpp" -#include "types.hpp" -#include "../../java/lang.hpp" - -#include #include "../../gson/json_element.hpp" -#include -#include +#include + +#include namespace mbgl { namespace android { @@ -18,11 +13,8 @@ namespace conversion { template struct Converter, mbgl::style::PropertyExpression> { - Result> operator()(jni::JNIEnv& env, const mbgl::style::PropertyExpression& value) const { - // Convert expressions - mbgl::Value expressionValue = value.getExpression().serialize(); - return gson::JsonElement::New(env, expressionValue); + return gson::JsonElement::New(env, value.getExpression().serialize()); } }; diff --git a/platform/android/src/style/conversion/property_value.hpp b/platform/android/src/style/conversion/property_value.hpp index 256647cddf..e4d8f59ec3 100644 --- a/platform/android/src/style/conversion/property_value.hpp +++ b/platform/android/src/style/conversion/property_value.hpp @@ -2,6 +2,7 @@ #include #include + #include "../../conversion/conversion.hpp" #include "../../conversion/constant.hpp" #include "property_expression.hpp" @@ -17,25 +18,22 @@ namespace conversion { template class PropertyValueEvaluator { public: - PropertyValueEvaluator(jni::JNIEnv& _env) : env(_env) {} jni::jobject* operator()(const mbgl::style::Undefined) const { return nullptr; } - jni::jobject* operator()(const T &value) const { - Result result = convert(env, value); - return *result; + jni::jobject* operator()(const T& value) const { + return *convert(env, value); } - jni::jobject* operator()(const mbgl::style::PropertyExpression &value) const { - return *convert, mbgl::style::PropertyExpression>(env, value); + jni::jobject* operator()(const mbgl::style::PropertyExpression& value) const { + return *convert>(env, value); } private: jni::JNIEnv& env; - }; /** @@ -43,7 +41,6 @@ private: */ template struct Converter> { - Result operator()(jni::JNIEnv& env, const mbgl::style::PropertyValue& value) const { PropertyValueEvaluator evaluator(env); return value.evaluate(evaluator); @@ -55,8 +52,7 @@ struct Converter> { */ template <> struct Converter { - - Result operator()(jni::JNIEnv& env, const mbgl::style::ColorRampPropertyValue value) const { + Result operator()(jni::JNIEnv& env, const mbgl::style::ColorRampPropertyValue& value) const { PropertyValueEvaluator evaluator(env); return *convert(env, value.evaluate(evaluator)); } diff --git a/platform/android/src/style/conversion/transition_options.cpp b/platform/android/src/style/conversion/transition_options.cpp new file mode 100644 index 0000000000..313333ad17 --- /dev/null +++ b/platform/android/src/style/conversion/transition_options.cpp @@ -0,0 +1,16 @@ +#include "transition_options.hpp" + +namespace mbgl { +namespace android { +namespace conversion { + +Result> Converter, mbgl::style::TransitionOptions>::operator()(jni::JNIEnv& env, const mbgl::style::TransitionOptions& value) const { + return TransitionOptions::fromTransitionOptions(env, + std::chrono::duration_cast(value.duration.value_or(mbgl::Duration::zero())).count(), + std::chrono::duration_cast(value.delay.value_or(mbgl::Duration::zero())).count() + ); +} + +} +} +} diff --git a/platform/android/src/style/conversion/transition_options.hpp b/platform/android/src/style/conversion/transition_options.hpp index ae65a32194..6630456d37 100644 --- a/platform/android/src/style/conversion/transition_options.hpp +++ b/platform/android/src/style/conversion/transition_options.hpp @@ -1,11 +1,11 @@ #pragma once #include "../../conversion/conversion.hpp" +#include "../transition_options.hpp" -#include #include -#include "../../jni/local_object.hpp" -#include "../transition_options.hpp" + +#include namespace mbgl { namespace android { @@ -13,18 +13,9 @@ namespace conversion { template<> struct Converter, mbgl::style::TransitionOptions> { - Result> operator()(jni::JNIEnv &env, const mbgl::style::TransitionOptions &value) const { - - // Convert duration - jlong duration = std::chrono::duration_cast(value.duration.value_or(mbgl::Duration::zero())).count(); - // Convert delay - jlong delay = std::chrono::duration_cast(value.delay.value_or(mbgl::Duration::zero())).count(); - - // Create transition options - return TransitionOptions::fromTransitionOptions(env, duration, delay); - } + Result> operator()(jni::JNIEnv&, const mbgl::style::TransitionOptions&) const; }; } } -} \ No newline at end of file +} diff --git a/platform/android/src/style/conversion/url_or_tileset.cpp b/platform/android/src/style/conversion/url_or_tileset.cpp new file mode 100644 index 0000000000..2ec5856751 --- /dev/null +++ b/platform/android/src/style/conversion/url_or_tileset.cpp @@ -0,0 +1,30 @@ +#include "url_or_tileset.hpp" +#include "../android_conversion.hpp" + +#include +#include + +namespace mbgl { +namespace android { + +// This conversion is expected not to fail because it's used only in contexts where +// the value was originally a String or TileSet object on the Java side. If it fails +// to convert, it's a bug in our serialization or Java-side static typing. +variant convertURLOrTileset(mbgl::android::Value&& value) { + using namespace mbgl::style::conversion; + + const Convertible convertible(std::move(value)); + if (isObject(convertible)) { + Error error; + optional tileset = convert(convertible, error); + if (!tileset) { + throw std::logic_error(error.message); + } + return { *tileset }; + } else { + return { *toString(convertible) }; + } +} + +} +} diff --git a/platform/android/src/style/conversion/url_or_tileset.hpp b/platform/android/src/style/conversion/url_or_tileset.hpp index d6bf86639c..f42a9b9a2a 100644 --- a/platform/android/src/style/conversion/url_or_tileset.hpp +++ b/platform/android/src/style/conversion/url_or_tileset.hpp @@ -1,37 +1,16 @@ #pragma once -#include #include - #include -#include -#include - -#include #include +#include "../value.hpp" + namespace mbgl { namespace android { -// This conversion is expected not to fail because it's used only in contexts where -// the value was originally a String or TileSet object on the Java side. If it fails -// to convert, it's a bug in our serialization or Java-side static typing. -inline variant convertURLOrTileset(mbgl::android::Value&& value) { - using namespace mbgl::style::conversion; - - const Convertible convertible(std::move(value)); - if (isObject(convertible)) { - Error error; - optional tileset = convert(convertible, error); - if (!tileset) { - throw std::logic_error(error.message); - } - return { *tileset }; - } else { - return { *toString(convertible) }; - } -} +variant convertURLOrTileset(mbgl::android::Value&& value); } } -- cgit v1.2.1 From 1584d8f70adc86e5ddd5a80b4ad9f4b7741f4678 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 17 Aug 2018 17:04:20 -0700 Subject: [android] Remove unused --- platform/android/src/conversion/collection.cpp | 14 ------------- platform/android/src/conversion/collection.hpp | 13 ------------ platform/android/src/conversion/constant.cpp | 16 --------------- platform/android/src/conversion/constant.hpp | 21 ------------------- .../android/src/style/conversion/latlngquad.hpp | 24 ---------------------- 5 files changed, 88 deletions(-) delete mode 100644 platform/android/src/style/conversion/latlngquad.hpp diff --git a/platform/android/src/conversion/collection.cpp b/platform/android/src/conversion/collection.cpp index 14d817ea88..27b614e8cd 100644 --- a/platform/android/src/conversion/collection.cpp +++ b/platform/android/src/conversion/collection.cpp @@ -5,20 +5,6 @@ namespace mbgl { namespace android { namespace conversion { -std::vector toVector(JNIEnv& env, jni::jarray& array) { - std::vector vector; - std::size_t len = jni::GetArrayLength(env, array); - vector.reserve(len); - - for (std::size_t i = 0; i < len; i++) { - jni::jstring* jstr = reinterpret_cast(jni::GetObjectArrayElement(env, array, i)); - vector.push_back(*convert(env, jni::String(jstr))); - jni::DeleteLocalRef(env, jstr); - } - - return vector; -} - std::vector toVector(JNIEnv& env, jni::Array array) { std::size_t len = array.Length(env); std::vector vector; diff --git a/platform/android/src/conversion/collection.hpp b/platform/android/src/conversion/collection.hpp index 973897b212..bb8941c984 100644 --- a/platform/android/src/conversion/collection.hpp +++ b/platform/android/src/conversion/collection.hpp @@ -10,19 +10,6 @@ namespace mbgl { namespace android { namespace conversion { -/** - * Convert jarray -> ArrayList - */ -template -jni::jobject* toArrayList(JNIEnv& env, jni::jarray& array) { - static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Arrays")).release(); - static jni::jmethodID* asList = &jni::GetStaticMethodID(env, *javaClass, "asList", "([Ljava/lang/Object;)Ljava/util/List;"); - return reinterpret_cast(jni::CallStaticMethod(env, *javaClass, *asList, array)); -} - -// Java -> C++ - -std::vector toVector(JNIEnv& env, jni::jarray& array); std::vector toVector(JNIEnv& env, jni::Array array); } diff --git a/platform/android/src/conversion/constant.cpp b/platform/android/src/conversion/constant.cpp index cce0796ce5..16e8b32943 100644 --- a/platform/android/src/conversion/constant.cpp +++ b/platform/android/src/conversion/constant.cpp @@ -12,38 +12,22 @@ Result Converter::operator()(jni::JNIEnv& en return {&jni::NewObject(env, *javaClass, *constructor, (jboolean) value)}; } -Result Converter::operator()(jni::JNIEnv&, const bool& value) const { - return {(jni::jboolean) value}; -} - Result Converter::operator()(jni::JNIEnv& env, const float& value) const { static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Float")).release(); static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(F)V"); return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)}; } -Result Converter::operator()(jni::JNIEnv&, const float& value) const { - return {(jni::jfloat) value}; -} - Result Converter::operator()(jni::JNIEnv& env, const double& value) const { static jni::jclass* javaClass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/lang/Double")).release(); static jni::jmethodID* constructor = &jni::GetMethodID(env, *javaClass, "", "(D)V"); return {&jni::NewObject(env, *javaClass, *constructor, (jfloat) value)}; } -Result Converter::operator()(jni::JNIEnv&, const double& value) const { - return {(jni::jdouble) value}; -} - Result Converter::operator()(jni::JNIEnv& env, const std::string& value) const { return {jni::Make(env, value).Get()}; } -Result Converter::operator()(jni::JNIEnv& env, const std::string& value) const { - return {jni::Make(env, value).Get()}; -} - Result Converter::operator()(jni::JNIEnv& env, const Color& value) const { std::stringstream sstream; sstream << "rgba(" << value.r << ", " << value.g << ", " << value.b << ", " << value.a << ")"; diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp index 52395cb9ee..a067547955 100644 --- a/platform/android/src/conversion/constant.hpp +++ b/platform/android/src/conversion/constant.hpp @@ -18,32 +18,16 @@ struct Converter { Result operator()(jni::JNIEnv& env, const bool& value) const; }; -template <> -struct Converter { - Result operator()(jni::JNIEnv&, const bool& value) const; -}; - template <> struct Converter { Result operator()(jni::JNIEnv& env, const float& value) const; }; -template <> -struct Converter { - Result operator()(jni::JNIEnv&, const float& value) const; -}; - - template <> struct Converter { Result operator()(jni::JNIEnv& env, const double& value) const; }; -template <> -struct Converter { - Result operator()(jni::JNIEnv&, const double& value) const; -}; - /** * All integrals. java is limited to 64 bit signed, so... * TODO: use BigDecimal for > 64 / unsigned? @@ -64,11 +48,6 @@ struct Converter { Result operator()(jni::JNIEnv& env, const std::string& value) const; }; -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const std::string& value) const; -}; - template <> struct Converter { Result operator()(jni::JNIEnv& env, const Color& value) const; diff --git a/platform/android/src/style/conversion/latlngquad.hpp b/platform/android/src/style/conversion/latlngquad.hpp deleted file mode 100644 index 9588336855..0000000000 --- a/platform/android/src/style/conversion/latlngquad.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -namespace mbgl { -namespace style { -namespace conversion { - -template <> -optional> Converter>::operator()(const mbgl::android::Value& value, Error& error) const { - if (value.isNull() || !value.isArray()) { - error = { "value cannot be converted to LatLng array" }; - return {}; - } - - return convert(value.toString(), error); -} - -} // namespace conversion -} // namespace style -} // namespace mbgl -- cgit v1.2.1 From 9587f569f7d59c9a5eb10c7ff0abb7c5d6e88b21 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Fri, 17 Aug 2018 18:05:15 -0700 Subject: [android] Simplify enum conversion --- platform/android/core-files.txt | 2 - platform/android/scripts/generate-style-code.js | 17 -- platform/android/src/conversion/constant.hpp | 9 + .../src/style/conversion/property_value.hpp | 1 - platform/android/src/style/conversion/types.hpp | 119 ---------- .../android/src/style/conversion/types.hpp.ejs | 40 ---- .../src/style/conversion/types_string_values.hpp | 257 --------------------- .../style/conversion/types_string_values.hpp.ejs | 48 ---- 8 files changed, 9 insertions(+), 484 deletions(-) delete mode 100644 platform/android/src/style/conversion/types.hpp delete mode 100644 platform/android/src/style/conversion/types.hpp.ejs delete mode 100644 platform/android/src/style/conversion/types_string_values.hpp delete mode 100644 platform/android/src/style/conversion/types_string_values.hpp.ejs diff --git a/platform/android/core-files.txt b/platform/android/core-files.txt index ef9ec65df7..cdcffb857f 100644 --- a/platform/android/core-files.txt +++ b/platform/android/core-files.txt @@ -65,8 +65,6 @@ platform/android/src/style/conversion/property_expression.hpp platform/android/src/style/conversion/property_value.hpp platform/android/src/style/conversion/transition_options.cpp platform/android/src/style/conversion/transition_options.hpp -platform/android/src/style/conversion/types.hpp -platform/android/src/style/conversion/types_string_values.hpp platform/android/src/style/conversion/url_or_tileset.cpp platform/android/src/style/conversion/url_or_tileset.hpp platform/android/src/map/camera_position.cpp diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js index 888b9fca30..98c5a446b9 100755 --- a/platform/android/scripts/generate-style-code.js +++ b/platform/android/scripts/generate-style-code.js @@ -363,20 +363,3 @@ writeIfModified( `platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/Property.java`, enumPropertyJavaTemplate({properties: enumProperties}) ); - -// De-duplicate enum properties before processing jni property templates -const enumPropertiesDeDup = _(enumProperties).uniqBy(global.propertyNativeType).value(); - -// JNI Enum property conversion templates -const enumPropertyHppTypeStringValueTemplate = ejs.compile(fs.readFileSync('platform/android/src/style/conversion/types_string_values.hpp.ejs', 'utf8'), {strict: true}); -writeIfModified( - `platform/android/src/style/conversion/types_string_values.hpp`, - enumPropertyHppTypeStringValueTemplate({properties: enumPropertiesDeDup}) -); - -// JNI property value types conversion templates -const enumPropertyHppTypeTemplate = ejs.compile(fs.readFileSync('platform/android/src/style/conversion/types.hpp.ejs', 'utf8'), {strict: true}); -writeIfModified( - `platform/android/src/style/conversion/types.hpp`, - enumPropertyHppTypeTemplate({properties: enumPropertiesDeDup}) -); diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp index a067547955..0e665cf56a 100644 --- a/platform/android/src/conversion/constant.hpp +++ b/platform/android/src/conversion/constant.hpp @@ -3,6 +3,8 @@ #include "conversion.hpp" #include +#include + #include #include @@ -74,6 +76,13 @@ struct Converter> { Result operator()(jni::JNIEnv& env, const std::vector& value) const; }; +template +struct Converter::value>> { + Result operator()(jni::JNIEnv& env, const T& value) const { + return convert(env, Enum::toString(value)); + } +}; + // Java -> C++ template <> diff --git a/platform/android/src/style/conversion/property_value.hpp b/platform/android/src/style/conversion/property_value.hpp index e4d8f59ec3..8150285c85 100644 --- a/platform/android/src/style/conversion/property_value.hpp +++ b/platform/android/src/style/conversion/property_value.hpp @@ -6,7 +6,6 @@ #include "../../conversion/conversion.hpp" #include "../../conversion/constant.hpp" #include "property_expression.hpp" -#include "types.hpp" namespace mbgl { namespace android { diff --git a/platform/android/src/style/conversion/types.hpp b/platform/android/src/style/conversion/types.hpp deleted file mode 100644 index e87782fad0..0000000000 --- a/platform/android/src/style/conversion/types.hpp +++ /dev/null @@ -1,119 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. -#pragma once - -#include "types_string_values.hpp" -#include "../../conversion/conversion.hpp" -#include "../../conversion/constant.hpp" - -#include -#include -#include - -#include - -namespace mbgl { -namespace android { -namespace conversion { - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::VisibilityType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::LineCapType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::LineJoinType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::SymbolPlacementType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::AlignmentType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::IconTextFitType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::SymbolAnchorType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::TextJustifyType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::TextTransformType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::TranslateAnchorType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::CirclePitchScaleType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::RasterResamplingType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::HillshadeIlluminationAnchorType& value) const { - return convert(env, toString(value)); - } -}; - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::LightAnchorType& value) const { - return convert(env, toString(value)); - } -}; - - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/conversion/types.hpp.ejs b/platform/android/src/style/conversion/types.hpp.ejs deleted file mode 100644 index 3cd4764015..0000000000 --- a/platform/android/src/style/conversion/types.hpp.ejs +++ /dev/null @@ -1,40 +0,0 @@ -<% - const properties = locals.properties; --%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. -#pragma once - -#include "types_string_values.hpp" -#include "../../conversion/conversion.hpp" -#include "../../conversion/constant.hpp" - -#include -#include -#include - -#include - -namespace mbgl { -namespace android { -namespace conversion { - -template <> -struct Converter { - Result operator()(jni::JNIEnv& env, const mbgl::style::VisibilityType& value) const { - return convert(env, toString(value)); - } -}; - -<% for (const property of properties) { -%> -template <> -struct Converter> { - Result operator()(jni::JNIEnv& env, const mbgl::style::<%- propertyNativeType(property) %>& value) const { - return convert(env, toString(value)); - } -}; - -<% } -%> - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/conversion/types_string_values.hpp b/platform/android/src/style/conversion/types_string_values.hpp deleted file mode 100644 index 9f6696d181..0000000000 --- a/platform/android/src/style/conversion/types_string_values.hpp +++ /dev/null @@ -1,257 +0,0 @@ -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. -#pragma once - -#include - -#include -#include - -namespace mbgl { -namespace android { -namespace conversion { - - // visibility - inline std::string toString(mbgl::style::VisibilityType value) { - switch (value) { - case mbgl::style::VisibilityType::Visible: - return "visible"; - break; - case mbgl::style::VisibilityType::None: - return "none"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // line-cap - inline std::string toString(mbgl::style::LineCapType value) { - switch (value) { - case mbgl::style::LineCapType::Butt: - return "butt"; - break; - case mbgl::style::LineCapType::Round: - return "round"; - break; - case mbgl::style::LineCapType::Square: - return "square"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // line-join - inline std::string toString(mbgl::style::LineJoinType value) { - switch (value) { - case mbgl::style::LineJoinType::Bevel: - return "bevel"; - break; - case mbgl::style::LineJoinType::Round: - return "round"; - break; - case mbgl::style::LineJoinType::Miter: - return "miter"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // symbol-placement - inline std::string toString(mbgl::style::SymbolPlacementType value) { - switch (value) { - case mbgl::style::SymbolPlacementType::Point: - return "point"; - break; - case mbgl::style::SymbolPlacementType::Line: - return "line"; - break; - case mbgl::style::SymbolPlacementType::LineCenter: - return "line-center"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // icon-rotation-alignment - inline std::string toString(mbgl::style::AlignmentType value) { - switch (value) { - case mbgl::style::AlignmentType::Map: - return "map"; - break; - case mbgl::style::AlignmentType::Viewport: - return "viewport"; - break; - case mbgl::style::AlignmentType::Auto: - return "auto"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // icon-text-fit - inline std::string toString(mbgl::style::IconTextFitType value) { - switch (value) { - case mbgl::style::IconTextFitType::None: - return "none"; - break; - case mbgl::style::IconTextFitType::Width: - return "width"; - break; - case mbgl::style::IconTextFitType::Height: - return "height"; - break; - case mbgl::style::IconTextFitType::Both: - return "both"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // icon-anchor - inline std::string toString(mbgl::style::SymbolAnchorType value) { - switch (value) { - case mbgl::style::SymbolAnchorType::Center: - return "center"; - break; - case mbgl::style::SymbolAnchorType::Left: - return "left"; - break; - case mbgl::style::SymbolAnchorType::Right: - return "right"; - break; - case mbgl::style::SymbolAnchorType::Top: - return "top"; - break; - case mbgl::style::SymbolAnchorType::Bottom: - return "bottom"; - break; - case mbgl::style::SymbolAnchorType::TopLeft: - return "top-left"; - break; - case mbgl::style::SymbolAnchorType::TopRight: - return "top-right"; - break; - case mbgl::style::SymbolAnchorType::BottomLeft: - return "bottom-left"; - break; - case mbgl::style::SymbolAnchorType::BottomRight: - return "bottom-right"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // text-justify - inline std::string toString(mbgl::style::TextJustifyType value) { - switch (value) { - case mbgl::style::TextJustifyType::Left: - return "left"; - break; - case mbgl::style::TextJustifyType::Center: - return "center"; - break; - case mbgl::style::TextJustifyType::Right: - return "right"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // text-transform - inline std::string toString(mbgl::style::TextTransformType value) { - switch (value) { - case mbgl::style::TextTransformType::None: - return "none"; - break; - case mbgl::style::TextTransformType::Uppercase: - return "uppercase"; - break; - case mbgl::style::TextTransformType::Lowercase: - return "lowercase"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // fill-translate-anchor - inline std::string toString(mbgl::style::TranslateAnchorType value) { - switch (value) { - case mbgl::style::TranslateAnchorType::Map: - return "map"; - break; - case mbgl::style::TranslateAnchorType::Viewport: - return "viewport"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // circle-pitch-scale - inline std::string toString(mbgl::style::CirclePitchScaleType value) { - switch (value) { - case mbgl::style::CirclePitchScaleType::Map: - return "map"; - break; - case mbgl::style::CirclePitchScaleType::Viewport: - return "viewport"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // raster-resampling - inline std::string toString(mbgl::style::RasterResamplingType value) { - switch (value) { - case mbgl::style::RasterResamplingType::Linear: - return "linear"; - break; - case mbgl::style::RasterResamplingType::Nearest: - return "nearest"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // hillshade-illumination-anchor - inline std::string toString(mbgl::style::HillshadeIlluminationAnchorType value) { - switch (value) { - case mbgl::style::HillshadeIlluminationAnchorType::Map: - return "map"; - break; - case mbgl::style::HillshadeIlluminationAnchorType::Viewport: - return "viewport"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - // anchor - inline std::string toString(mbgl::style::LightAnchorType value) { - switch (value) { - case mbgl::style::LightAnchorType::Map: - return "map"; - break; - case mbgl::style::LightAnchorType::Viewport: - return "viewport"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - - -} // namespace conversion -} // namespace android -} // namespace mbgl diff --git a/platform/android/src/style/conversion/types_string_values.hpp.ejs b/platform/android/src/style/conversion/types_string_values.hpp.ejs deleted file mode 100644 index bf52919741..0000000000 --- a/platform/android/src/style/conversion/types_string_values.hpp.ejs +++ /dev/null @@ -1,48 +0,0 @@ -<% - const properties = locals.properties; --%> -// This file is generated. Edit android/platform/scripts/generate-style-code.js, then run `make android-style-code`. -#pragma once - -#include - -#include -#include - -namespace mbgl { -namespace android { -namespace conversion { - - // visibility - inline std::string toString(mbgl::style::VisibilityType value) { - switch (value) { - case mbgl::style::VisibilityType::Visible: - return "visible"; - break; - case mbgl::style::VisibilityType::None: - return "none"; - break; - default: - throw std::runtime_error("Not implemented"); - } - } - -<% for (const property of properties) { -%> - // <%- property.name %> - inline std::string toString(mbgl::style::<%- propertyNativeType(property) %> value) { - switch (value) { -<% for (const value in property.values) { -%> - case mbgl::style::<%- propertyNativeType(property) %>::<%- camelize(value) %>: - return "<%- value %>"; - break; -<% } -%> - default: - throw std::runtime_error("Not implemented"); - } - } - -<% } -%> - -} // namespace conversion -} // namespace android -} // namespace mbgl -- cgit v1.2.1 From a842c198acf0766beee786cb6eab079c67b9dfd2 Mon Sep 17 00:00:00 2001 From: John Firebaugh Date: Mon, 20 Aug 2018 11:09:00 -0700 Subject: [android] Inline geometry conversion --- .../android/src/geojson/conversion/feature.cpp | 3 +-- .../android/src/geojson/conversion/geometry.hpp | 24 ---------------------- 2 files changed, 1 insertion(+), 26 deletions(-) delete mode 100644 platform/android/src/geojson/conversion/geometry.hpp diff --git a/platform/android/src/geojson/conversion/feature.cpp b/platform/android/src/geojson/conversion/feature.cpp index 8dff05aa12..3cb6d37b17 100644 --- a/platform/android/src/geojson/conversion/feature.cpp +++ b/platform/android/src/geojson/conversion/feature.cpp @@ -1,5 +1,4 @@ #include "feature.hpp" -#include "geometry.hpp" #include "../../conversion/constant.hpp" #include "../../conversion/conversion.hpp" @@ -161,7 +160,7 @@ Result> Converter(*convert(env, value.properties)); // Convert geometry - auto geometry = *convert>(env, value.geometry); + auto geometry = android::geojson::Geometry::New(env, value.geometry); // Create feature auto feature = android::geojson::Feature::fromGeometry(env, geometry, properties, jid); diff --git a/platform/android/src/geojson/conversion/geometry.hpp b/platform/android/src/geojson/conversion/geometry.hpp deleted file mode 100644 index 242a68df02..0000000000 --- a/platform/android/src/geojson/conversion/geometry.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include -#include "../geometry.hpp" -#include - -namespace mbgl { -namespace android { -namespace conversion { - -/** - * mapbox::geometry::geometry -> Java GeoJson Geometry - */ -template -struct Converter, mapbox::geometry::geometry> { - Result> operator()(jni::JNIEnv& env, const mapbox::geometry::geometry& value) const { - return { android::geojson::Geometry::New(env, value) }; - } -}; - - -} // conversion -} // android -} // mbgl -- cgit v1.2.1 From 0218c01095bf0109ae23e268553eb741fe887f28 Mon Sep 17 00:00:00 2001 From: tobrun Date: Tue, 21 Aug 2018 11:49:18 +0200 Subject: [android] - update map intializer for OfflineRegionDefintion with OfflineGeometryRegionDefinition --- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 44 +++++++++++++++++----- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index aaed71ddec..d480d28f26 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java @@ -37,11 +37,13 @@ import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.constants.Style; +import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.renderer.MapRenderer; import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.GLSurfaceViewMapRenderer; import com.mapbox.mapboxsdk.maps.renderer.textureview.TextureViewMapRenderer; import com.mapbox.mapboxsdk.maps.widgets.CompassView; import com.mapbox.mapboxsdk.net.ConnectivityReceiver; +import com.mapbox.mapboxsdk.offline.OfflineGeometryRegionDefinition; import com.mapbox.mapboxsdk.offline.OfflineRegionDefinition; import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition; import com.mapbox.mapboxsdk.storage.FileSource; @@ -567,22 +569,46 @@ public class MapView extends FrameLayout implements NativeMapView.ViewCallback { return; } - OfflineTilePyramidRegionDefinition regionDefinition = (OfflineTilePyramidRegionDefinition) definition; - setStyleUrl(regionDefinition.getStyleURL()); + if (definition instanceof OfflineTilePyramidRegionDefinition) { + setOfflineTilePyramidRegionDefinition((OfflineTilePyramidRegionDefinition) definition); + } else if (definition instanceof OfflineGeometryRegionDefinition) { + setOfflineGeometryRegionDefinition((OfflineGeometryRegionDefinition) definition); + } else { + throw new UnsupportedOperationException("OfflineRegionDefintion instance not supported"); + } + } + + private void setOfflineRegionDefinition(String styleUrl, LatLng cameraTarget, double minZoom, double maxZoom) { CameraPosition cameraPosition = new CameraPosition.Builder() - .target(regionDefinition.getBounds().getCenter()) - .zoom(regionDefinition.getMinZoom()) + .target(cameraTarget) + .zoom(minZoom) .build(); - + setStyleUrl(styleUrl); if (!isMapInitialized()) { mapboxMapOptions.camera(cameraPosition); - mapboxMapOptions.minZoomPreference(regionDefinition.getMinZoom()); - mapboxMapOptions.maxZoomPreference(regionDefinition.getMaxZoom()); + mapboxMapOptions.minZoomPreference(minZoom); + mapboxMapOptions.maxZoomPreference(maxZoom); return; } mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); - mapboxMap.setMinZoomPreference(regionDefinition.getMinZoom()); - mapboxMap.setMaxZoomPreference(regionDefinition.getMaxZoom()); + mapboxMap.setMinZoomPreference(minZoom); + mapboxMap.setMaxZoomPreference(maxZoom); + } + + private void setOfflineTilePyramidRegionDefinition(OfflineTilePyramidRegionDefinition regionDefinition) { + setOfflineRegionDefinition(regionDefinition.getStyleURL(), + regionDefinition.getBounds().getCenter(), + regionDefinition.getMinZoom(), + regionDefinition.getMaxZoom() + ); + } + + private void setOfflineGeometryRegionDefinition(OfflineGeometryRegionDefinition regionDefinition) { + setOfflineRegionDefinition(regionDefinition.getStyleURL(), + regionDefinition.getBounds().getCenter(), + regionDefinition.getMinZoom(), + regionDefinition.getMaxZoom() + ); } // -- cgit v1.2.1 From 724832ce5df2ed2aa84791d89fd3939d9a43d085 Mon Sep 17 00:00:00 2001 From: tobrun Date: Mon, 20 Aug 2018 17:15:07 +0200 Subject: [android] - example to render symbols offline with resources loaded from assets --- .../0-255.pbf | Bin 0 -> 75287 bytes .../0-255.pbf | Bin 0 -> 73518 bytes .../0-255.pbf | Bin 0 -> 72149 bytes .../0-255.pbf | Bin 0 -> 75290 bytes .../8192-8447.pbf | Bin 0 -> 30553 bytes .../src/main/assets/streets.json | 12447 +++++++++++++++++++ .../activity/style/SymbolLayerActivity.java | 131 +- .../src/main/res/layout/activity_symbollayer.xml | 15 +- platform/android/scripts/exclude-activity-gen.json | 3 +- 9 files changed, 12529 insertions(+), 67 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Bold,Arial Unicode MS Bold/0-255.pbf create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Italic,Arial Unicode MS Regular/0-255.pbf create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Medium,Arial Unicode MS Regular/0-255.pbf create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Regular,Arial Unicode MS Regular/0-255.pbf create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Regular,Arial Unicode MS Regular/8192-8447.pbf create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/streets.json diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Bold,Arial Unicode MS Bold/0-255.pbf b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Bold,Arial Unicode MS Bold/0-255.pbf new file mode 100644 index 0000000000..457ef91106 Binary files /dev/null and b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Bold,Arial Unicode MS Bold/0-255.pbf differ diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Italic,Arial Unicode MS Regular/0-255.pbf b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Italic,Arial Unicode MS Regular/0-255.pbf new file mode 100644 index 0000000000..e7b9431539 Binary files /dev/null and b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Italic,Arial Unicode MS Regular/0-255.pbf differ diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Medium,Arial Unicode MS Regular/0-255.pbf b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Medium,Arial Unicode MS Regular/0-255.pbf new file mode 100644 index 0000000000..44b361e00a Binary files /dev/null and b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Medium,Arial Unicode MS Regular/0-255.pbf differ diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Regular,Arial Unicode MS Regular/0-255.pbf b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Regular,Arial Unicode MS Regular/0-255.pbf new file mode 100644 index 0000000000..e05af54e91 Binary files /dev/null and b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Regular,Arial Unicode MS Regular/0-255.pbf differ diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Regular,Arial Unicode MS Regular/8192-8447.pbf b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Regular,Arial Unicode MS Regular/8192-8447.pbf new file mode 100644 index 0000000000..f05c342aaa Binary files /dev/null and b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/fonts/DIN Offc Pro Regular,Arial Unicode MS Regular/8192-8447.pbf differ diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/streets.json b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/streets.json new file mode 100644 index 0000000000..5a5e298fb6 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/assets/streets.json @@ -0,0 +1,12447 @@ +{ + "version": 8, + "name": "Streets", + "metadata": { + "mapbox:autocomposite": true, + "mapbox:type": "default", + "mapbox:origin": "streets-v10", + "mapbox:groups": { + "1444934828655.3389": { + "name": "Aeroways", + "collapsed": true + }, + "1444933322393.2852": { + "name": "POI labels (scalerank 1)", + "collapsed": true + }, + "1444855786460.0557": { + "name": "Roads", + "collapsed": true + }, + "1444933575858.6992": { + "name": "Highway shields", + "collapsed": true + }, + "1444934295202.7542": { + "name": "Admin boundaries", + "collapsed": true + }, + "1444856151690.9143": { + "name": "State labels", + "collapsed": true + }, + "1444933721429.3076": { + "name": "Road labels", + "collapsed": true + }, + "1444933358918.2366": { + "name": "POI labels (scalerank 2)", + "collapsed": true + }, + "1444933808272.805": { + "name": "Water labels", + "collapsed": true + }, + "1444933372896.5967": { + "name": "POI labels (scalerank 3)", + "collapsed": true + }, + "1444855799204.86": { + "name": "Bridges", + "collapsed": true + }, + "1444856087950.3635": { + "name": "Marine labels", + "collapsed": true + }, + "1456969573402.7817": { + "name": "Hillshading", + "collapsed": true + }, + "1444862510685.128": { + "name": "City labels", + "collapsed": true + }, + "1444855769305.6016": { + "name": "Tunnels", + "collapsed": true + }, + "1456970288113.8113": { + "name": "Landcover", + "collapsed": true + }, + "1444856144497.7825": { + "name": "Country labels", + "collapsed": true + }, + "1444933456003.5437": { + "name": "POI labels (scalerank 4)", + "collapsed": true + } + }, + "mapbox:sdk-support": { + "js": "0.46.0", + "android": "6.0.0", + "ios": "4.0.0" + } + }, + "center": [ + -122.4241, + 37.78 + ], + "zoom": 9, + "sources": { + "composite": { + "url": "mapbox://mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v7", + "type": "vector" + } + }, + "sprite": "mapbox://sprites/lukaspaczos/cjkwfdgzn1fz42rqtvsk6rrmd", + "glyphs": "asset://fonts/{fontstack}/{range}.pbf", + "layers": [ + { + "id": "background", + "type": "background", + "layout": {}, + "paint": { + "background-color": { + "base": 1, + "stops": [ + [ + 11, + "hsl(35, 32%, 91%)" + ], + [ + 13, + "hsl(35, 12%, 89%)" + ] + ] + } + }, + "interactive": true + }, + { + "id": "landcover_snow", + "type": "fill", + "metadata": { + "mapbox:group": "1456970288113.8113" + }, + "source": "composite", + "source-layer": "landcover", + "filter": [ + "==", + "class", + "snow" + ], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-opacity": 0.2, + "fill-antialias": false + }, + "interactive": true + }, + { + "id": "landcover_wood", + "type": "fill", + "metadata": { + "mapbox:group": "1456970288113.8113" + }, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": [ + "==", + "class", + "wood" + ], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": { + "base": 1.5, + "stops": [ + [ + 2, + 0.3 + ], + [ + 7, + 0 + ] + ] + }, + "fill-antialias": false + }, + "interactive": true + }, + { + "id": "landcover_scrub", + "type": "fill", + "metadata": { + "mapbox:group": "1456970288113.8113" + }, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": [ + "==", + "class", + "scrub" + ], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": { + "base": 1.5, + "stops": [ + [ + 2, + 0.3 + ], + [ + 7, + 0 + ] + ] + }, + "fill-antialias": false + }, + "interactive": true + }, + { + "id": "landcover_grass", + "type": "fill", + "metadata": { + "mapbox:group": "1456970288113.8113" + }, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": [ + "==", + "class", + "grass" + ], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": { + "base": 1.5, + "stops": [ + [ + 2, + 0.3 + ], + [ + 7, + 0 + ] + ] + }, + "fill-antialias": false + }, + "interactive": true + }, + { + "id": "landcover_crop", + "type": "fill", + "metadata": { + "mapbox:group": "1456970288113.8113" + }, + "source": "composite", + "source-layer": "landcover", + "maxzoom": 14, + "filter": [ + "==", + "class", + "crop" + ], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 62%, 81%)", + "fill-opacity": { + "base": 1.5, + "stops": [ + [ + 2, + 0.3 + ], + [ + 7, + 0 + ] + ] + }, + "fill-antialias": false + }, + "interactive": true + }, + { + "id": "national_park", + "type": "fill", + "source": "composite", + "source-layer": "landuse_overlay", + "filter": [ + "==", + "class", + "national_park" + ], + "layout": {}, + "paint": { + "fill-color": "hsl(100, 58%, 76%)", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 5, + 0 + ], + [ + 6, + 0.5 + ] + ] + } + }, + "interactive": true + }, + { + "id": "hospital", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "hospital" + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [ + 15.5, + "hsl(340, 37%, 87%)" + ], + [ + 16, + "hsl(340, 63%, 89%)" + ] + ] + } + }, + "interactive": true + }, + { + "id": "school", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "school" + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [ + 15.5, + "hsl(50, 47%, 81%)" + ], + [ + 16, + "hsl(50, 63%, 84%)" + ] + ] + } + }, + "interactive": true + }, + { + "id": "park", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "park" + ], + "layout": {}, + "paint": { + "fill-color": "hsl(100, 58%, 76%)", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 5, + 0 + ], + [ + 6, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "pitch", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "pitch" + ], + "layout": {}, + "paint": { + "fill-color": "hsl(100, 57%, 72%)" + }, + "interactive": true + }, + { + "id": "pitch-line", + "type": "line", + "source": "composite", + "source-layer": "landuse", + "minzoom": 15, + "filter": [ + "==", + "class", + "pitch" + ], + "layout": { + "line-join": "miter" + }, + "paint": { + "line-color": "hsl(75, 57%, 84%)" + }, + "interactive": true + }, + { + "id": "cemetery", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "cemetery" + ], + "layout": {}, + "paint": { + "fill-color": "hsl(75, 37%, 81%)" + }, + "interactive": true + }, + { + "id": "industrial", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "industrial" + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [ + 15.5, + "hsl(230, 15%, 86%)" + ], + [ + 16, + "hsl(230, 29%, 89%)" + ] + ] + } + }, + "interactive": true + }, + { + "id": "sand", + "type": "fill", + "source": "composite", + "source-layer": "landuse", + "filter": [ + "==", + "class", + "sand" + ], + "layout": {}, + "paint": { + "fill-color": "hsl(60, 46%, 87%)" + }, + "interactive": true + }, + { + "id": "hillshade_highlight_bright", + "type": "fill", + "metadata": { + "mapbox:group": "1456969573402.7817" + }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ + "==", + "level", + 94 + ], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-opacity": { + "stops": [ + [ + 14, + 0.12 + ], + [ + 16, + 0 + ] + ] + }, + "fill-antialias": false + }, + "interactive": true + }, + { + "id": "hillshade_highlight_med", + "type": "fill", + "metadata": { + "mapbox:group": "1456969573402.7817" + }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ + "==", + "level", + 90 + ], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-opacity": { + "stops": [ + [ + 14, + 0.12 + ], + [ + 16, + 0 + ] + ] + }, + "fill-antialias": false + }, + "interactive": true + }, + { + "id": "hillshade_shadow_faint", + "type": "fill", + "metadata": { + "mapbox:group": "1456969573402.7817" + }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ + "==", + "level", + 89 + ], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": { + "stops": [ + [ + 14, + 0.05 + ], + [ + 16, + 0 + ] + ] + }, + "fill-antialias": false + }, + "interactive": true + }, + { + "id": "hillshade_shadow_med", + "type": "fill", + "metadata": { + "mapbox:group": "1456969573402.7817" + }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ + "==", + "level", + 78 + ], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": { + "stops": [ + [ + 14, + 0.05 + ], + [ + 16, + 0 + ] + ] + }, + "fill-antialias": false + }, + "interactive": true + }, + { + "id": "hillshade_shadow_dark", + "type": "fill", + "metadata": { + "mapbox:group": "1456969573402.7817" + }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ + "==", + "level", + 67 + ], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": { + "stops": [ + [ + 14, + 0.06 + ], + [ + 16, + 0 + ] + ] + }, + "fill-antialias": false + }, + "interactive": true + }, + { + "id": "hillshade_shadow_extreme", + "type": "fill", + "metadata": { + "mapbox:group": "1456969573402.7817" + }, + "source": "composite", + "source-layer": "hillshade", + "maxzoom": 16, + "filter": [ + "==", + "level", + 56 + ], + "layout": {}, + "paint": { + "fill-color": "hsl(56, 59%, 22%)", + "fill-opacity": { + "stops": [ + [ + 14, + 0.06 + ], + [ + 16, + 0 + ] + ] + }, + "fill-antialias": false + }, + "interactive": true + }, + { + "id": "waterway-river-canal", + "type": "line", + "source": "composite", + "source-layer": "waterway", + "minzoom": 8, + "filter": [ + "in", + "class", + "canal", + "river" + ], + "layout": { + "line-cap": { + "base": 1, + "stops": [ + [ + 0, + "butt" + ], + [ + 11, + "round" + ] + ] + }, + "line-join": "round" + }, + "paint": { + "line-color": "hsl(205, 87%, 76%)", + "line-width": { + "base": 1.3, + "stops": [ + [ + 8.5, + 0.1 + ], + [ + 20, + 8 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 8, + 0 + ], + [ + 8.5, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "waterway-small", + "type": "line", + "source": "composite", + "source-layer": "waterway", + "minzoom": 13, + "filter": [ + "!in", + "class", + "canal", + "river" + ], + "layout": { + "line-join": "round", + "line-cap": "round" + }, + "paint": { + "line-color": "hsl(205, 87%, 76%)", + "line-width": { + "base": 1.35, + "stops": [ + [ + 13.5, + 0.1 + ], + [ + 20, + 3 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 13, + 0 + ], + [ + 13.5, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "water-shadow", + "type": "fill", + "source": "composite", + "source-layer": "water", + "layout": {}, + "paint": { + "fill-color": "hsl(215, 84%, 69%)", + "fill-translate": { + "base": 1.2, + "stops": [ + [ + 7, + [ + 0, + 0 + ] + ], + [ + 16, + [ + -1, + -1 + ] + ] + ] + }, + "fill-translate-anchor": "viewport", + "fill-opacity": 1 + }, + "interactive": true + }, + { + "id": "water", + "type": "fill", + "source": "composite", + "source-layer": "water", + "layout": {}, + "paint": { + "fill-color": "hsl(196, 80%, 70%)" + }, + "interactive": true + }, + { + "id": "barrier_line-land-polygon", + "type": "fill", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "==", + "class", + "land" + ] + ], + "layout": {}, + "paint": { + "fill-color": "hsl(35, 12%, 89%)" + }, + "interactive": true + }, + { + "id": "barrier_line-land-line", + "type": "line", + "source": "composite", + "source-layer": "barrier_line", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "land" + ] + ], + "layout": { + "line-cap": "round" + }, + "paint": { + "line-width": { + "base": 1.99, + "stops": [ + [ + 14, + 0.75 + ], + [ + 20, + 40 + ] + ] + }, + "line-color": "hsl(35, 12%, 89%)" + }, + "interactive": true + }, + { + "id": "aeroway-polygon", + "type": "fill", + "metadata": { + "mapbox:group": "1444934828655.3389" + }, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 11, + "filter": [ + "all", + [ + "!=", + "type", + "apron" + ], + [ + "==", + "$type", + "Polygon" + ] + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [ + 15, + "hsl(230, 23%, 82%)" + ], + [ + 16, + "hsl(230, 37%, 84%)" + ] + ] + }, + "fill-opacity": { + "base": 1, + "stops": [ + [ + 11, + 0 + ], + [ + 11.5, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "aeroway-runway", + "type": "line", + "metadata": { + "mapbox:group": "1444934828655.3389" + }, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 9, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "type", + "runway" + ] + ], + "layout": {}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [ + 15, + "hsl(230, 23%, 82%)" + ], + [ + 16, + "hsl(230, 37%, 84%)" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 9, + 1 + ], + [ + 18, + 80 + ] + ] + } + }, + "interactive": true + }, + { + "id": "aeroway-taxiway", + "type": "line", + "metadata": { + "mapbox:group": "1444934828655.3389" + }, + "source": "composite", + "source-layer": "aeroway", + "minzoom": 9, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "type", + "taxiway" + ] + ], + "layout": {}, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [ + 15, + "hsl(230, 23%, 82%)" + ], + [ + 16, + "hsl(230, 37%, 84%)" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 0.5 + ], + [ + 18, + 20 + ] + ] + } + }, + "interactive": true + }, + { + "id": "building-line", + "type": "line", + "source": "composite", + "source-layer": "building", + "minzoom": 15, + "filter": [ + "all", + [ + "!=", + "type", + "building:part" + ], + [ + "==", + "underground", + "false" + ] + ], + "layout": {}, + "paint": { + "line-color": "hsl(35, 6%, 79%)", + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 0.75 + ], + [ + 20, + 3 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 15.5, + 0 + ], + [ + 16, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "building", + "type": "fill", + "source": "composite", + "source-layer": "building", + "minzoom": 15, + "filter": [ + "all", + [ + "!=", + "type", + "building:part" + ], + [ + "==", + "underground", + "false" + ] + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [ + 15, + "hsl(35, 11%, 88%)" + ], + [ + 16, + "hsl(35, 8%, 85%)" + ] + ] + }, + "fill-opacity": { + "base": 1, + "stops": [ + [ + 15.5, + 0 + ], + [ + 16, + 1 + ] + ] + }, + "fill-outline-color": "hsl(35, 6%, 79%)" + }, + "interactive": true + }, + { + "id": "tunnel-street-low", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [ + [ + 11.5, + 0 + ], + [ + 12, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "interactive": true + }, + { + "id": "tunnel-street_limited-low", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [ + [ + 11.5, + 0 + ], + [ + 12, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "interactive": true + }, + { + "id": "tunnel-service-link-track-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "trunk_link" + ], + [ + "==", + "structure", + "tunnel" + ], + [ + "in", + "class", + "link", + "service", + "track" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ] + }, + "interactive": true + }, + { + "id": "tunnel-street_limited-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "tunnel-street-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(230, 19%, 75%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "tunnel-secondary-tertiary-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "tunnel" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.2, + "stops": [ + [ + 10, + 0.75 + ], + [ + 18, + 2 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ], + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-color": "hsl(230, 19%, 75%)" + }, + "interactive": true + }, + { + "id": "tunnel-primary-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "primary" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 1 + ], + [ + 16, + 2 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ], + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "hsl(230, 19%, 75%)" + }, + "interactive": true + }, + { + "id": "tunnel-trunk_link-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "tunnel" + ], + [ + "==", + "type", + "trunk_link" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ] + }, + "interactive": true + }, + { + "id": "tunnel-motorway_link-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "motorway_link" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-dasharray": [ + 3, + 3 + ] + }, + "interactive": true + }, + { + "id": "tunnel-trunk-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "tunnel" + ], + [ + "==", + "type", + "trunk" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 1 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-opacity": 1, + "line-dasharray": [ + 3, + 3 + ] + }, + "interactive": true + }, + { + "id": "tunnel-motorway-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 1 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-opacity": 1, + "line-dasharray": [ + 3, + 3 + ] + }, + "interactive": true + }, + { + "id": "tunnel-construction", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "construction" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-join": "miter" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + }, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 0.4, + 0.8 + ] + ], + [ + 15, + [ + 0.3, + 0.6 + ] + ], + [ + 16, + [ + 0.2, + 0.3 + ] + ], + [ + 17, + [ + 0.2, + 0.25 + ] + ], + [ + 18, + [ + 0.15, + 0.15 + ] + ] + ] + } + }, + "interactive": true + }, + { + "id": "tunnel-path", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "steps" + ], + [ + "==", + "class", + "path" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 1 + ], + [ + 18, + 4 + ] + ] + }, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 1, + 0 + ] + ], + [ + 15, + [ + 1.75, + 1 + ] + ], + [ + 16, + [ + 1, + 0.75 + ] + ], + [ + 17, + [ + 1, + 0.5 + ] + ] + ] + }, + "line-color": "hsl(35, 26%, 95%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 14, + 0 + ], + [ + 14.25, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "tunnel-steps", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "tunnel" + ], + [ + "==", + "type", + "steps" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 1 + ], + [ + 16, + 1.6 + ], + [ + 18, + 6 + ] + ] + }, + "line-color": "hsl(35, 26%, 95%)", + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 1, + 0 + ] + ], + [ + 15, + [ + 1.75, + 1 + ] + ], + [ + 16, + [ + 1, + 0.75 + ] + ], + [ + 17, + [ + 0.3, + 0.3 + ] + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 14, + 0 + ], + [ + 14.25, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "tunnel-trunk_link", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "tunnel" + ], + [ + "==", + "type", + "trunk_link" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(46, 77%, 78%)", + "line-opacity": 1, + "line-dasharray": [ + 1, + 0 + ] + }, + "interactive": true + }, + { + "id": "tunnel-motorway_link", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "motorway_link" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(26, 100%, 78%)", + "line-opacity": 1, + "line-dasharray": [ + 1, + 0 + ] + }, + "interactive": true + }, + { + "id": "tunnel-pedestrian", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "pedestrian" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 1, + 0 + ] + ], + [ + 15, + [ + 1.5, + 0.4 + ] + ], + [ + 16, + [ + 1, + 0.2 + ] + ] + ] + } + }, + "interactive": true + }, + { + "id": "tunnel-service-link-track", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "trunk_link" + ], + [ + "==", + "structure", + "tunnel" + ], + [ + "in", + "class", + "link", + "service", + "track" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": [ + 1, + 0 + ] + }, + "interactive": true + }, + { + "id": "tunnel-street_limited", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "tunnel-street", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "tunnel-secondary-tertiary", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "tunnel" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": [ + 1, + 0 + ], + "line-blur": 0 + }, + "interactive": true + }, + { + "id": "tunnel-primary", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "primary" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": [ + 1, + 0 + ], + "line-blur": 0 + }, + "interactive": true + }, + { + "id": "tunnel-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "trunk_link" + ], + [ + "==", + "oneway", + "true" + ], + [ + "==", + "structure", + "tunnel" + ], + [ + "in", + "class", + "link", + "path", + "pedestrian", + "service", + "track" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 17, + "oneway-small" + ], + [ + 18, + "oneway-large" + ] + ] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {}, + "interactive": true + }, + { + "id": "tunnel-oneway-arrows-blue-major", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "trunk_link" + ], + [ + "==", + "oneway", + "true" + ], + [ + "==", + "structure", + "tunnel" + ], + [ + "in", + "class", + "primary", + "secondary", + "street", + "street_limited", + "tertiary" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-small" + ], + [ + 17, + "oneway-large" + ] + ] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {}, + "interactive": true + }, + { + "id": "tunnel-trunk", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "trunk" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "hsl(46, 77%, 78%)" + }, + "interactive": true + }, + { + "id": "tunnel-motorway", + "type": "line", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "==", + "structure", + "tunnel" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-dasharray": [ + 1, + 0 + ], + "line-opacity": 1, + "line-color": "hsl(26, 100%, 78%)", + "line-blur": 0 + }, + "interactive": true + }, + { + "id": "tunnel-oneway-arrows-white", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855769305.6016" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "type", + "primary_link", + "secondary_link", + "tertiary_link" + ], + [ + "==", + "oneway", + "true" + ], + [ + "==", + "structure", + "tunnel" + ], + [ + "in", + "class", + "link", + "motorway", + "motorway_link", + "trunk" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-white-small" + ], + [ + 17, + "oneway-white-large" + ] + ] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {}, + "interactive": true + }, + { + "id": "ferry", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "type", + "ferry" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [ + 15, + "hsl(205, 73%, 63%)" + ], + [ + 17, + "hsl(230, 73%, 63%)" + ] + ] + }, + "line-opacity": 1, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 20, + 1 + ] + ] + }, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 12, + [ + 1, + 0 + ] + ], + [ + 13, + [ + 12, + 4 + ] + ] + ] + } + }, + "interactive": true + }, + { + "id": "ferry_auto", + "type": "line", + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "type", + "ferry_auto" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [ + 15, + "hsl(205, 73%, 63%)" + ], + [ + 17, + "hsl(230, 73%, 63%)" + ] + ] + }, + "line-opacity": 1, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 20, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-path-bg", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "!in", + "type", + "crossing", + "sidewalk", + "steps" + ], + [ + "==", + "class", + "path" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 2 + ], + [ + 18, + 7 + ] + ] + }, + "line-dasharray": [ + 1, + 0 + ], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": { + "base": 1, + "stops": [ + [ + 14, + 0 + ], + [ + 14.25, + 0.75 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-steps-bg", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "type", + "steps" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 2 + ], + [ + 17, + 4.6 + ], + [ + 18, + 7 + ] + ] + }, + "line-color": "hsl(230, 17%, 82%)", + "line-dasharray": [ + 1, + 0 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 14, + 0 + ], + [ + 14.25, + 0.75 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-sidewalk-bg", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "in", + "type", + "crossing", + "sidewalk" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 2 + ], + [ + 18, + 7 + ] + ] + }, + "line-dasharray": [ + 1, + 0 + ], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": { + "base": 1, + "stops": [ + [ + 16, + 0 + ], + [ + 16.25, + 0.75 + ] + ] + } + }, + "interactive": true + }, + { + "id": "turning-features-outline", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "in", + "class", + "turning_circle", + "turning_loop" + ] + ], + "layout": { + "icon-image": "turning-circle-outline", + "icon-size": { + "base": 1.5, + "stops": [ + [ + 14, + 0.122 + ], + [ + 18, + 0.969 + ], + [ + 20, + 1 + ] + ] + }, + "icon-allow-overlap": true, + "icon-ignore-placement": true, + "icon-padding": 0, + "icon-rotation-alignment": "map" + }, + "paint": {}, + "interactive": true + }, + { + "id": "road-pedestrian-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "pedestrian" + ], + [ + "==", + "structure", + "none" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 2 + ], + [ + 18, + 14.5 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": 0, + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-street-low", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street" + ], + [ + "==", + "structure", + "none" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [ + [ + 11, + 0 + ], + [ + 11.25, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-street_limited-low", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "structure", + "none" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [ + [ + 11, + 0 + ], + [ + 11.25, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-service-link-track-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "trunk_link" + ], + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "link", + "service", + "track" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-street_limited-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "structure", + "none" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-street-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street" + ], + [ + "==", + "structure", + "none" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-secondary-tertiary-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.2, + "stops": [ + [ + 10, + 0.75 + ], + [ + 18, + 2 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 9.99, + 0 + ], + [ + 10, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-primary-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "primary" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 1 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 9.99, + 0 + ], + [ + 10, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-motorway_link-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 10, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "motorway_link" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 10.99, + 0 + ], + [ + 11, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-trunk_link-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "type", + "trunk_link" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 10.99, + 0 + ], + [ + 11, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-trunk-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "trunk" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 1 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 6, + 0 + ], + [ + 6.1, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-motorway-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "motorway" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 1 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-construction", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "construction" + ], + [ + "==", + "structure", + "none" + ] + ] + ], + "layout": { + "line-join": "miter" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + }, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 0.4, + 0.8 + ] + ], + [ + 15, + [ + 0.3, + 0.6 + ] + ], + [ + 16, + [ + 0.2, + 0.3 + ] + ], + [ + 17, + [ + 0.2, + 0.25 + ] + ], + [ + 18, + [ + 0.15, + 0.15 + ] + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-sidewalks", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "in", + "type", + "crossing", + "sidewalk" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 1 + ], + [ + 18, + 4 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 1, + 0 + ] + ], + [ + 15, + [ + 1.75, + 1 + ] + ], + [ + 16, + [ + 1, + 0.75 + ] + ], + [ + 17, + [ + 1, + 0.5 + ] + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 16, + 0 + ], + [ + 16.25, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-path", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "!in", + "type", + "crossing", + "sidewalk", + "steps" + ], + [ + "==", + "class", + "path" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 1 + ], + [ + 18, + 4 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 1, + 0 + ] + ], + [ + 15, + [ + 1.75, + 1 + ] + ], + [ + 16, + [ + 1, + 0.75 + ] + ], + [ + 17, + [ + 1, + 0.5 + ] + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 14, + 0 + ], + [ + 14.25, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-steps", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "type", + "steps" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 1 + ], + [ + 16, + 1.6 + ], + [ + 18, + 6 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 1, + 0 + ] + ], + [ + 15, + [ + 1.75, + 1 + ] + ], + [ + 16, + [ + 1, + 0.75 + ] + ], + [ + 17, + [ + 0.3, + 0.3 + ] + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 14, + 0 + ], + [ + 14.25, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-trunk_link", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "type", + "trunk_link" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(46, 85%, 67%)", + "line-opacity": 1 + }, + "interactive": true + }, + { + "id": "road-motorway_link", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 10, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "motorway_link" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(26, 100%, 68%)", + "line-opacity": 1 + }, + "interactive": true + }, + { + "id": "road-pedestrian", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "pedestrian" + ], + [ + "==", + "structure", + "none" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 1, + 0 + ] + ], + [ + 15, + [ + 1.5, + 0.4 + ] + ], + [ + 16, + [ + 1, + 0.2 + ] + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-pedestrian-polygon-fill", + "type": "fill", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "all", + [ + "==", + "structure", + "none" + ], + [ + "in", + "class", + "path", + "pedestrian" + ] + ] + ], + "layout": {}, + "paint": { + "fill-color": { + "base": 1, + "stops": [ + [ + 16, + "hsl(230, 16%, 94%)" + ], + [ + 16.25, + "hsl(230, 50%, 98%)" + ] + ] + }, + "fill-outline-color": "hsl(230, 26%, 88%)", + "fill-opacity": 1 + }, + "interactive": true + }, + { + "id": "road-pedestrian-polygon-pattern", + "type": "fill", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "all", + [ + "==", + "structure", + "none" + ], + [ + "in", + "class", + "path", + "pedestrian" + ] + ] + ], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-outline-color": "hsl(35, 10%, 83%)", + "fill-pattern": "pedestrian-polygon", + "fill-opacity": { + "base": 1, + "stops": [ + [ + 16, + 0 + ], + [ + 16.25, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-polygon", + "type": "fill", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 12, + "filter": [ + "all", + [ + "==", + "$type", + "Polygon" + ], + [ + "all", + [ + "!in", + "class", + "motorway", + "path", + "pedestrian", + "trunk" + ], + [ + "!in", + "structure", + "bridge", + "tunnel" + ] + ] + ], + "layout": {}, + "paint": { + "fill-color": "hsl(0, 0%, 100%)", + "fill-outline-color": "#d6d9e6" + }, + "interactive": true + }, + { + "id": "road-service-link-track", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "trunk_link" + ], + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "link", + "service", + "track" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)" + }, + "interactive": true + }, + { + "id": "road-street_limited", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "structure", + "none" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-street", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street" + ], + [ + "==", + "structure", + "none" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-secondary-tertiary", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-color": { + "base": 1, + "stops": [ + [ + 5, + "hsl(35, 32%, 91%)" + ], + [ + 8, + "hsl(0, 0%, 100%)" + ] + ] + }, + "line-opacity": { + "base": 1.2, + "stops": [ + [ + 5, + 0 + ], + [ + 5.5, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-primary", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "primary" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": { + "base": 1, + "stops": [ + [ + 5, + "hsl(35, 32%, 91%)" + ], + [ + 7, + "hsl(0, 0%, 100%)" + ] + ] + }, + "line-opacity": 1 + }, + "interactive": true + }, + { + "id": "road-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "trunk_link" + ], + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "oneway", + "true" + ], + [ + "in", + "class", + "link", + "path", + "pedestrian", + "service", + "track" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 17, + "oneway-small" + ], + [ + 18, + "oneway-large" + ] + ] + }, + "icon-rotation-alignment": "map", + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {}, + "interactive": true + }, + { + "id": "road-oneway-arrows-blue-major", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "trunk_link" + ], + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "oneway", + "true" + ], + [ + "in", + "class", + "primary", + "secondary", + "street", + "street_limited", + "tertiary" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-small" + ], + [ + 17, + "oneway-large" + ] + ] + }, + "icon-rotation-alignment": "map", + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {}, + "interactive": true + }, + { + "id": "road-trunk", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "trunk" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": { + "base": 1, + "stops": [ + [ + 6, + "hsl(0, 0%, 100%)" + ], + [ + 6.1, + "hsl(46, 80%, 60%)" + ], + [ + 9, + "hsl(46, 85%, 67%)" + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-motorway", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "==", + "class", + "motorway" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": { + "base": 1, + "stops": [ + [ + 8, + "hsl(26, 87%, 62%)" + ], + [ + 9, + "hsl(26, 100%, 68%)" + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-rail", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "major_rail", + "minor_rail" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": { + "stops": [ + [ + 13, + "hsl(50, 17%, 82%)" + ], + [ + 16, + "hsl(230, 10%, 74%)" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 20, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "road-rail-tracks", + "type": "line", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "in", + "class", + "major_rail", + "minor_rail" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": { + "stops": [ + [ + 13, + "hsl(50, 17%, 82%)" + ], + [ + 16, + "hsl(230, 10%, 74%)" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 4 + ], + [ + 20, + 8 + ] + ] + }, + "line-dasharray": [ + 0.1, + 15 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.75, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "level-crossings", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "class", + "level_crossing" + ] + ], + "layout": { + "icon-size": 1, + "icon-image": "level-crossing", + "icon-allow-overlap": true + }, + "paint": {}, + "interactive": true + }, + { + "id": "road-oneway-arrows-white", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "structure", + "bridge", + "tunnel" + ], + [ + "!in", + "type", + "primary_link", + "secondary_link", + "tertiary_link" + ], + [ + "==", + "oneway", + "true" + ], + [ + "in", + "class", + "link", + "motorway", + "motorway_link", + "trunk" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-white-small" + ], + [ + 17, + "oneway-white-large" + ] + ] + }, + "icon-padding": 2, + "symbol-spacing": 200 + }, + "paint": {}, + "interactive": true + }, + { + "id": "turning-features", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855786460.0557" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "in", + "class", + "turning_circle", + "turning_loop" + ] + ], + "layout": { + "icon-image": "turning-circle", + "icon-size": { + "base": 1.5, + "stops": [ + [ + 14, + 0.095 + ], + [ + 18, + 1 + ] + ] + }, + "icon-allow-overlap": true, + "icon-ignore-placement": true, + "icon-padding": 0, + "icon-rotation-alignment": "map" + }, + "paint": {}, + "interactive": true + }, + { + "id": "bridge-path-bg", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "steps" + ], + [ + "==", + "class", + "path" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 2 + ], + [ + 18, + 7 + ] + ] + }, + "line-dasharray": [ + 1, + 0 + ], + "line-color": "hsl(230, 17%, 82%)", + "line-blur": 0, + "line-opacity": { + "base": 1, + "stops": [ + [ + 15, + 0 + ], + [ + 15.25, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-steps-bg", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "bridge" + ], + [ + "==", + "type", + "steps" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 2 + ], + [ + 17, + 4.6 + ], + [ + 18, + 7 + ] + ] + }, + "line-color": "hsl(230, 17%, 82%)", + "line-dasharray": [ + 1, + 0 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 14, + 0 + ], + [ + 14.25, + 0.75 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-pedestrian-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "pedestrian" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 2 + ], + [ + 18, + 14.5 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": 0, + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-street-low", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [ + [ + 11.5, + 0 + ], + [ + 12, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-street_limited-low", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "stops": [ + [ + 11.5, + 0 + ], + [ + 12, + 1 + ], + [ + 14, + 1 + ], + [ + 14.01, + 0 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-service-link-track-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "trunk_link" + ], + [ + "==", + "structure", + "bridge" + ], + [ + "in", + "class", + "link", + "service", + "track" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-street_limited-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-street-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + }, + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 13, + 0 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-secondary-tertiary-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "bridge" + ], + [ + "in", + "class", + "secondary", + "tertiary" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.2, + "stops": [ + [ + 10, + 0.75 + ], + [ + 18, + 2 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-translate": [ + 0, + 0 + ] + }, + "interactive": true + }, + { + "id": "bridge-primary-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "primary" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 1 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-translate": [ + 0, + 0 + ] + }, + "interactive": true + }, + { + "id": "bridge-trunk_link-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "layer", + 2, + 3, + 4, + 5 + ], + [ + "==", + "structure", + "bridge" + ], + [ + "==", + "type", + "trunk_link" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 10.99, + 0 + ], + [ + 11, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-motorway_link-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "layer", + 2, + 3, + 4, + 5 + ], + [ + "==", + "class", + "motorway_link" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": 1 + }, + "interactive": true + }, + { + "id": "bridge-trunk-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "layer", + 2, + 3, + 4, + 5 + ], + [ + "==", + "class", + "trunk" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 1 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-motorway-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "layer", + 2, + 3, + 4, + 5 + ], + [ + "==", + "class", + "motorway" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 1 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-construction", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "construction" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-join": "miter" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(230, 24%, 87%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + }, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 0.4, + 0.8 + ] + ], + [ + 15, + [ + 0.3, + 0.6 + ] + ], + [ + 16, + [ + 0.2, + 0.3 + ] + ], + [ + 17, + [ + 0.2, + 0.25 + ] + ], + [ + 18, + [ + 0.15, + 0.15 + ] + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-path", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "steps" + ], + [ + "==", + "class", + "path" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 1 + ], + [ + 18, + 4 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 1, + 0 + ] + ], + [ + 15, + [ + 1.75, + 1 + ] + ], + [ + 16, + [ + 1, + 0.75 + ] + ], + [ + 17, + [ + 1, + 0.5 + ] + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 14, + 0 + ], + [ + 14.25, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-steps", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "bridge" + ], + [ + "==", + "type", + "steps" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 15, + 1 + ], + [ + 16, + 1.6 + ], + [ + 18, + 6 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 1, + 0 + ] + ], + [ + 15, + [ + 1.75, + 1 + ] + ], + [ + 16, + [ + 1, + 0.75 + ] + ], + [ + 17, + [ + 0.3, + 0.3 + ] + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 14, + 0 + ], + [ + 14.25, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-trunk_link", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "layer", + 2, + 3, + 4, + 5 + ], + [ + "==", + "structure", + "bridge" + ], + [ + "==", + "type", + "trunk_link" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(46, 85%, 67%)" + }, + "interactive": true + }, + { + "id": "bridge-motorway_link", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "layer", + 2, + 3, + 4, + 5 + ], + [ + "==", + "class", + "motorway_link" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(26, 100%, 68%)" + }, + "interactive": true + }, + { + "id": "bridge-pedestrian", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "pedestrian" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1, + "line-dasharray": { + "base": 1, + "stops": [ + [ + 14, + [ + 1, + 0 + ] + ], + [ + 15, + [ + 1.5, + 0.4 + ] + ], + [ + 16, + [ + 1, + 0.2 + ] + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-service-link-track", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 14, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!=", + "type", + "trunk_link" + ], + [ + "==", + "structure", + "bridge" + ], + [ + "in", + "class", + "link", + "service", + "track" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 18, + 12 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)" + }, + "interactive": true + }, + { + "id": "bridge-street_limited", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street_limited" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(35, 14%, 93%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-street", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "street" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12.5, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-secondary-tertiary", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "bridge" + ], + [ + "in", + "type", + "secondary", + "tertiary" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 8.5, + 0.5 + ], + [ + 10, + 0.75 + ], + [ + 18, + 26 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": { + "base": 1.2, + "stops": [ + [ + 5, + 0 + ], + [ + 5.5, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-primary", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "bridge" + ], + [ + "==", + "type", + "primary" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-opacity": 1 + }, + "interactive": true + }, + { + "id": "bridge-oneway-arrows-blue-minor", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "oneway", + "true" + ], + [ + "==", + "structure", + "bridge" + ], + [ + "in", + "class", + "link", + "path", + "pedestrian", + "service", + "track" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 17, + "oneway-small" + ], + [ + 18, + "oneway-large" + ] + ] + }, + "symbol-spacing": 200, + "icon-rotation-alignment": "map", + "icon-padding": 2 + }, + "paint": {}, + "interactive": true + }, + { + "id": "bridge-oneway-arrows-blue-major", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 15, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "oneway", + "true" + ], + [ + "==", + "structure", + "bridge" + ], + [ + "in", + "class", + "primary", + "secondary", + "street", + "street_limited", + "tertiary" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-small" + ], + [ + 17, + "oneway-large" + ] + ] + }, + "symbol-spacing": 200, + "icon-rotation-alignment": "map", + "icon-padding": 2 + }, + "paint": {}, + "interactive": true + }, + { + "id": "bridge-trunk", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "layer", + 2, + 3, + 4, + 5 + ], + [ + "==", + "class", + "trunk" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "hsl(46, 85%, 67%)" + }, + "interactive": true + }, + { + "id": "bridge-motorway", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "layer", + 2, + 3, + 4, + 5 + ], + [ + "==", + "class", + "motorway" + ], + [ + "==", + "structure", + "bridge" + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "hsl(26, 100%, 68%)" + }, + "interactive": true + }, + { + "id": "bridge-rail", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "bridge" + ], + [ + "in", + "class", + "major_rail", + "minor_rail" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": { + "stops": [ + [ + 13, + "hsl(50, 17%, 82%)" + ], + [ + 16, + "hsl(230, 10%, 74%)" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 20, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-rail-tracks", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "bridge" + ], + [ + "in", + "class", + "major_rail", + "minor_rail" + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": { + "stops": [ + [ + 13, + "hsl(50, 17%, 82%)" + ], + [ + 16, + "hsl(230, 10%, 74%)" + ] + ] + }, + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 4 + ], + [ + 20, + 8 + ] + ] + }, + "line-dasharray": [ + 0.1, + 15 + ], + "line-opacity": { + "base": 1, + "stops": [ + [ + 13.75, + 0 + ], + [ + 20, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-trunk_link-2-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "bridge" + ], + [ + "==", + "type", + "trunk_link" + ], + [ + ">=", + "layer", + 2 + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 10.99, + 0 + ], + [ + 11, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-motorway_link-2-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "motorway_link" + ], + [ + "==", + "structure", + "bridge" + ], + [ + ">=", + "layer", + 2 + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.75 + ], + [ + 20, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-opacity": 1 + }, + "interactive": true + }, + { + "id": "bridge-trunk-2-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "trunk" + ], + [ + "==", + "structure", + "bridge" + ], + [ + ">=", + "layer", + 2 + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 1 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-motorway-2-case", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "==", + "structure", + "bridge" + ], + [ + ">=", + "layer", + 2 + ] + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 10, + 1 + ], + [ + 16, + 2 + ] + ] + }, + "line-color": "hsl(0, 0%, 100%)", + "line-gap-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + } + }, + "interactive": true + }, + { + "id": "bridge-trunk_link-2", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "structure", + "bridge" + ], + [ + "==", + "type", + "trunk_link" + ], + [ + ">=", + "layer", + 2 + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(46, 85%, 67%)" + }, + "interactive": true + }, + { + "id": "bridge-motorway_link-2", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "motorway_link" + ], + [ + "==", + "structure", + "bridge" + ], + [ + ">=", + "layer", + 2 + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 12, + 0.5 + ], + [ + 14, + 2 + ], + [ + 18, + 18 + ] + ] + }, + "line-color": "hsl(26, 100%, 68%)" + }, + "interactive": true + }, + { + "id": "bridge-trunk-2", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "trunk" + ], + [ + "==", + "structure", + "bridge" + ], + [ + ">=", + "layer", + 2 + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "hsl(46, 85%, 67%)" + }, + "interactive": true + }, + { + "id": "bridge-motorway-2", + "type": "line", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "==", + "class", + "motorway" + ], + [ + "==", + "structure", + "bridge" + ], + [ + ">=", + "layer", + 2 + ] + ] + ], + "layout": { + "line-cap": "round", + "line-join": "round" + }, + "paint": { + "line-width": { + "base": 1.5, + "stops": [ + [ + 5, + 0.75 + ], + [ + 18, + 32 + ] + ] + }, + "line-color": "hsl(26, 100%, 68%)" + }, + "interactive": true + }, + { + "id": "bridge-oneway-arrows-white", + "type": "symbol", + "metadata": { + "mapbox:group": "1444855799204.86" + }, + "source": "composite", + "source-layer": "road", + "minzoom": 16, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "all", + [ + "!in", + "type", + "primary_link", + "secondary_link", + "tertiary_link" + ], + [ + "==", + "oneway", + "true" + ], + [ + "==", + "structure", + "bridge" + ], + [ + "in", + "class", + "link", + "motorway", + "motorway_link", + "trunk" + ] + ] + ], + "layout": { + "symbol-placement": "line", + "icon-image": { + "base": 1, + "stops": [ + [ + 16, + "oneway-white-small" + ], + [ + 17, + "oneway-white-large" + ] + ] + }, + "symbol-spacing": 200, + "icon-padding": 2 + }, + "paint": {}, + "interactive": true + }, + { + "id": "aerialway", + "type": "line", + "source": "composite", + "source-layer": "road", + "minzoom": 13, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "class", + "aerialway" + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-color": "hsl(230, 10%, 74%)", + "line-width": { + "base": 1.5, + "stops": [ + [ + 14, + 0.5 + ], + [ + 20, + 1 + ] + ] + } + }, + "interactive": true + }, + { + "id": "admin-3-4-boundaries-bg", + "type": "line", + "metadata": { + "mapbox:group": "1444934295202.7542" + }, + "source": "composite", + "source-layer": "admin", + "filter": [ + "all", + [ + "==", + "maritime", + 0 + ], + [ + ">=", + "admin_level", + 3 + ] + ], + "layout": { + "line-join": "bevel" + }, + "paint": { + "line-color": { + "base": 1, + "stops": [ + [ + 8, + "hsl(35, 12%, 89%)" + ], + [ + 16, + "hsl(230, 49%, 90%)" + ] + ] + }, + "line-width": { + "base": 1, + "stops": [ + [ + 7, + 3.75 + ], + [ + 12, + 5.5 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 7, + 0 + ], + [ + 8, + 0.75 + ] + ] + }, + "line-dasharray": [ + 1, + 0 + ], + "line-translate": [ + 0, + 0 + ], + "line-blur": { + "base": 1, + "stops": [ + [ + 3, + 0 + ], + [ + 8, + 3 + ] + ] + } + }, + "interactive": true + }, + { + "id": "admin-2-boundaries-bg", + "type": "line", + "metadata": { + "mapbox:group": "1444934295202.7542" + }, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": [ + "all", + [ + "==", + "admin_level", + 2 + ], + [ + "==", + "maritime", + 0 + ] + ], + "layout": { + "line-join": "miter" + }, + "paint": { + "line-width": { + "base": 1, + "stops": [ + [ + 3, + 3.5 + ], + [ + 10, + 8 + ] + ] + }, + "line-color": { + "base": 1, + "stops": [ + [ + 6, + "hsl(35, 12%, 89%)" + ], + [ + 8, + "hsl(230, 49%, 90%)" + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 3, + 0 + ], + [ + 4, + 0.5 + ] + ] + }, + "line-translate": [ + 0, + 0 + ], + "line-blur": { + "base": 1, + "stops": [ + [ + 3, + 0 + ], + [ + 10, + 2 + ] + ] + } + }, + "interactive": true + }, + { + "id": "admin-3-4-boundaries", + "type": "line", + "metadata": { + "mapbox:group": "1444934295202.7542" + }, + "source": "composite", + "source-layer": "admin", + "filter": [ + "all", + [ + "==", + "maritime", + 0 + ], + [ + ">=", + "admin_level", + 3 + ] + ], + "layout": { + "line-join": "round", + "line-cap": "round" + }, + "paint": { + "line-dasharray": { + "base": 1, + "stops": [ + [ + 6, + [ + 2, + 0 + ] + ], + [ + 7, + [ + 2, + 2, + 6, + 2 + ] + ] + ] + }, + "line-width": { + "base": 1, + "stops": [ + [ + 7, + 0.75 + ], + [ + 12, + 1.5 + ] + ] + }, + "line-opacity": { + "base": 1, + "stops": [ + [ + 2, + 0 + ], + [ + 3, + 1 + ] + ] + }, + "line-color": { + "base": 1, + "stops": [ + [ + 3, + "hsl(230, 14%, 77%)" + ], + [ + 7, + "hsl(230, 8%, 62%)" + ] + ] + } + }, + "interactive": true + }, + { + "id": "admin-2-boundaries", + "type": "line", + "metadata": { + "mapbox:group": "1444934295202.7542" + }, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": [ + "all", + [ + "==", + "admin_level", + 2 + ], + [ + "==", + "disputed", + 0 + ], + [ + "==", + "maritime", + 0 + ] + ], + "layout": { + "line-join": "round", + "line-cap": "round" + }, + "paint": { + "line-color": "hsl(230, 8%, 51%)", + "line-width": { + "base": 1, + "stops": [ + [ + 3, + 0.5 + ], + [ + 10, + 2 + ] + ] + } + }, + "interactive": true + }, + { + "id": "admin-2-boundaries-dispute", + "type": "line", + "metadata": { + "mapbox:group": "1444934295202.7542" + }, + "source": "composite", + "source-layer": "admin", + "minzoom": 1, + "filter": [ + "all", + [ + "==", + "admin_level", + 2 + ], + [ + "==", + "disputed", + 1 + ], + [ + "==", + "maritime", + 0 + ] + ], + "layout": { + "line-join": "round" + }, + "paint": { + "line-dasharray": [ + 1.5, + 1.5 + ], + "line-color": "hsl(230, 8%, 51%)", + "line-width": { + "base": 1, + "stops": [ + [ + 3, + 0.5 + ], + [ + 10, + 2 + ] + ] + } + }, + "interactive": true + }, + { + "id": "housenum-label", + "type": "symbol", + "source": "composite", + "source-layer": "housenum_label", + "minzoom": 17, + "layout": { + "text-field": "{house_num}", + "text-font": [ + "DIN Offc Pro Italic,Arial Unicode MS Regular" + ], + "text-padding": 4, + "text-max-width": 7, + "text-size": 9.5 + }, + "paint": { + "text-color": "hsl(35, 2%, 69%)", + "text-halo-color": "hsl(35, 8%, 85%)", + "text-halo-width": 0.5, + "text-halo-blur": 0 + }, + "interactive": true + }, + { + "id": "waterway-label", + "type": "symbol", + "source": "composite", + "source-layer": "waterway_label", + "minzoom": 12, + "filter": [ + "in", + "class", + "canal", + "river" + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Italic,Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-max-angle": 30, + "text-size": { + "base": 1, + "stops": [ + [ + 13, + 12 + ], + [ + 18, + 16 + ] + ] + } + }, + "paint": { + "text-halo-width": 0.5, + "text-halo-color": "hsl(196, 80%, 70%)", + "text-color": "hsl(230, 48%, 44%)", + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "poi-scalerank4-l15", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933456003.5437" + }, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 17, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ + "==", + "scalerank", + 4 + ], + [ + ">=", + "localrank", + 15 + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [ + 0, + 0.65 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "poi-scalerank4-l1", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933456003.5437" + }, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 15, + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ + "<=", + "localrank", + 14 + ], + [ + "==", + "scalerank", + 4 + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-padding": 1, + "text-offset": [ + 0, + 0.65 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "poi-parks_scalerank4", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933456003.5437" + }, + "source": "composite", + "source-layer": "poi_label", + "minzoom": 15, + "filter": [ + "all", + [ + "==", + "scalerank", + 4 + ], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-padding": 1, + "text-offset": [ + 0, + 0.65 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "poi-scalerank3", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933372896.5967" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ + "==", + "scalerank", + 3 + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-padding": 1, + "text-offset": [ + 0, + 0.65 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "poi-parks-scalerank3", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933372896.5967" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "==", + "scalerank", + 3 + ], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "icon-image": "{maki}-11", + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [ + 0, + 0.65 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "road-label-small", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933721429.3076" + }, + "source": "composite", + "source-layer": "road_label", + "minzoom": 15, + "filter": [ + "all", + [ + "!in", + "class", + "golf", + "link", + "motorway", + "pedestrian", + "primary", + "secondary", + "street", + "street_limited", + "tertiary", + "trunk" + ], + [ + "==", + "$type", + "LineString" + ] + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 15, + 10 + ], + [ + 20, + 13 + ] + ] + }, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-halo-blur": 1 + }, + "interactive": true + }, + { + "id": "road-label-medium", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933721429.3076" + }, + "source": "composite", + "source-layer": "road_label", + "minzoom": 11, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "class", + "link", + "pedestrian", + "street", + "street_limited" + ] + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 11, + 10 + ], + [ + 20, + 14 + ] + ] + }, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + }, + "interactive": true + }, + { + "id": "road-label-large", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933721429.3076" + }, + "source": "composite", + "source-layer": "road_label", + "filter": [ + "in", + "class", + "motorway", + "primary", + "secondary", + "tertiary", + "trunk" + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 9, + 10 + ], + [ + 20, + 16 + ] + ] + }, + "text-max-angle": 30, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-padding": 1, + "text-rotation-alignment": "map", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsla(0, 0%, 100%, 0.75)", + "text-halo-width": 1, + "text-halo-blur": 1 + }, + "interactive": true + }, + { + "id": "road-shields-black", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933575858.6992" + }, + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + [ + "!in", + "shield", + "at-expressway", + "at-motorway", + "at-state-b", + "bg-motorway", + "bg-national", + "ch-main", + "ch-motorway", + "cz-motorway", + "cz-road", + "de-motorway", + "e-road", + "fi-main", + "gr-motorway", + "gr-national", + "hr-motorway", + "hr-state", + "hu-main", + "hu-motorway", + "nz-state", + "pl-expressway", + "pl-motorway", + "pl-national", + "ro-county", + "ro-motorway", + "ro-national", + "rs-motorway", + "rs-state-1b", + "se-main", + "si-expressway", + "si-motorway", + "sk-highway", + "sk-road", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex", + "us-interstate-truck", + "za-metropolitan", + "za-national", + "za-provincial", + "za-regional" + ], + [ + "<=", + "reflen", + 6 + ] + ], + "layout": { + "text-size": 9, + "icon-image": "{shield}-{reflen}", + "icon-rotation-alignment": "viewport", + "text-max-angle": 38, + "symbol-spacing": { + "base": 1, + "stops": [ + [ + 11, + 150 + ], + [ + 14, + 200 + ] + ] + }, + "text-font": [ + "DIN Offc Pro Bold,Arial Unicode MS Bold" + ], + "symbol-placement": { + "base": 1, + "stops": [ + [ + 10, + "point" + ], + [ + 11, + "line" + ] + ] + }, + "text-padding": 2, + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 2 + }, + "paint": { + "text-color": "hsl(0, 0%, 7%)", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0 + }, + "interactive": true + }, + { + "id": "road-shields-white", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933575858.6992" + }, + "source": "composite", + "source-layer": "road_label", + "filter": [ + "all", + [ + "<=", + "reflen", + 6 + ], + [ + "in", + "shield", + "at-expressway", + "at-motorway", + "at-state-b", + "bg-motorway", + "bg-national", + "ch-main", + "ch-motorway", + "cz-motorway", + "cz-road", + "de-motorway", + "e-road", + "fi-main", + "gr-motorway", + "gr-national", + "hr-motorway", + "hr-state", + "hu-main", + "hu-motorway", + "nz-state", + "pl-expressway", + "pl-motorway", + "pl-national", + "ro-county", + "ro-motorway", + "ro-national", + "rs-motorway", + "rs-state-1b", + "se-main", + "si-expressway", + "si-motorway", + "sk-highway", + "sk-road", + "us-interstate", + "us-interstate-business", + "us-interstate-duplex", + "us-interstate-truck", + "za-metropolitan", + "za-national", + "za-provincial", + "za-regional" + ] + ], + "layout": { + "text-size": 9, + "icon-image": "{shield}-{reflen}", + "icon-rotation-alignment": "viewport", + "text-max-angle": 38, + "symbol-spacing": { + "base": 1, + "stops": [ + [ + 11, + 150 + ], + [ + 14, + 200 + ] + ] + }, + "text-font": [ + "DIN Offc Pro Bold,Arial Unicode MS Bold" + ], + "symbol-placement": { + "base": 1, + "stops": [ + [ + 10, + "point" + ], + [ + 11, + "line" + ] + ] + }, + "text-padding": 2, + "text-rotation-alignment": "viewport", + "text-field": "{ref}", + "text-letter-spacing": 0.05, + "icon-padding": 2 + }, + "paint": { + "text-color": "hsl(0, 0%, 100%)", + "icon-halo-color": "rgba(0, 0, 0, 1)", + "icon-halo-width": 1, + "text-opacity": 1, + "icon-color": "white", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0 + }, + "interactive": true + }, + { + "id": "motorway-junction", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933575858.6992" + }, + "source": "composite", + "source-layer": "motorway_junction", + "minzoom": 14, + "filter": [ + "all", + [ + "<=", + "reflen", + 9 + ], + [ + ">", + "reflen", + 0 + ] + ], + "layout": { + "text-field": "{ref}", + "text-size": 9, + "icon-image": "motorway-exit-{reflen}", + "text-font": [ + "DIN Offc Pro Bold,Arial Unicode MS Bold" + ] + }, + "paint": { + "text-color": "hsl(0, 0%, 100%)", + "text-translate": [ + 0, + 0 + ] + }, + "interactive": true + }, + { + "id": "poi-scalerank2", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933358918.2366" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ + "==", + "scalerank", + 2 + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 14, + 11 + ], + [ + 20, + 14 + ] + ] + }, + "icon-image": { + "stops": [ + [ + 14, + "{maki}-11" + ], + [ + 15, + "{maki}-15" + ] + ] + }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [ + 0, + 0.65 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "poi-parks-scalerank2", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933358918.2366" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "==", + "scalerank", + 2 + ], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 14, + 11 + ], + [ + 20, + 14 + ] + ] + }, + "icon-image": { + "stops": [ + [ + 14, + "{maki}-11" + ], + [ + 15, + "{maki}-15" + ] + ] + }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [ + 0, + 0.65 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "rail-label", + "type": "symbol", + "source": "composite", + "source-layer": "rail_station_label", + "minzoom": 12, + "filter": [ + "!=", + "maki", + "entrance" + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 11 + ], + [ + 20, + 13 + ] + ] + }, + "icon-image": "{network}", + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-offset": [ + 0, + 0.85 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": { + "base": 1, + "stops": [ + [ + 0, + "" + ], + [ + 13, + "{name_en}" + ] + ] + }, + "text-letter-spacing": 0.01, + "icon-padding": 0, + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(230, 48%, 44%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "icon-halo-width": 4, + "icon-halo-color": "#fff", + "text-opacity": { + "base": 1, + "stops": [ + [ + 13.99, + 0 + ], + [ + 14, + 1 + ] + ] + }, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "water-label-sm", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933808272.805" + }, + "source": "composite", + "source-layer": "water_label", + "minzoom": 15, + "filter": [ + "<=", + "area", + 10000 + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Italic,Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": { + "base": 1, + "stops": [ + [ + 16, + 13 + ], + [ + 20, + 16 + ] + ] + } + }, + "paint": { + "text-color": "hsl(230, 48%, 44%)" + }, + "interactive": true + }, + { + "id": "water-label", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933808272.805" + }, + "source": "composite", + "source-layer": "water_label", + "minzoom": 5, + "filter": [ + ">", + "area", + 10000 + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Italic,Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": { + "base": 1, + "stops": [ + [ + 13, + 13 + ], + [ + 18, + 18 + ] + ] + } + }, + "paint": { + "text-color": "hsl(230, 48%, 44%)" + }, + "interactive": true + }, + { + "id": "place-residential", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 18, + "filter": [ + "all", + [ + "all", + [ + "<=", + "localrank", + 10 + ], + [ + "==", + "type", + "residential" + ] + ], + [ + "in", + "$type", + "LineString", + "Point", + "Polygon" + ] + ], + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 11 + ], + [ + 18, + 14 + ] + ] + }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [ + 0, + 0 + ], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "poi-parks-scalerank1", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933322393.2852" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "<=", + "scalerank", + 1 + ], + [ + "in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 11 + ], + [ + 18, + 14 + ] + ] + }, + "icon-image": { + "stops": [ + [ + 13, + "{maki}-11" + ], + [ + 14, + "{maki}-15" + ] + ] + }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [ + 0, + 0.65 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(100, 100%, 20%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "poi-scalerank1", + "type": "symbol", + "metadata": { + "mapbox:group": "1444933322393.2852" + }, + "source": "composite", + "source-layer": "poi_label", + "filter": [ + "all", + [ + "!in", + "maki", + "campsite", + "cemetery", + "dog-park", + "garden", + "golf", + "park", + "picnic-site", + "playground", + "zoo" + ], + [ + "<=", + "scalerank", + 1 + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 11 + ], + [ + 18, + 14 + ] + ] + }, + "icon-image": { + "stops": [ + [ + 13, + "{maki}-11" + ], + [ + 14, + "{maki}-15" + ] + ] + }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [ + 0, + 0.65 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(26, 25%, 32%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "airport-label", + "type": "symbol", + "source": "composite", + "source-layer": "airport_label", + "minzoom": 9, + "filter": [ + "<=", + "scalerank", + 2 + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 12 + ], + [ + 18, + 18 + ] + ] + }, + "icon-image": { + "stops": [ + [ + 12, + "{maki}-11" + ], + [ + 13, + "{maki}-15" + ] + ] + }, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [ + 0, + 0.75 + ], + "text-rotation-alignment": "viewport", + "text-anchor": "top", + "text-field": { + "stops": [ + [ + 11, + "{ref}" + ], + [ + 12, + "{name_en}" + ] + ] + }, + "text-letter-spacing": 0.01, + "text-max-width": 9 + }, + "paint": { + "text-color": "hsl(230, 48%, 44%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 0.5, + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "place-islet-archipelago-aboriginal", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 16, + "filter": [ + "in", + "type", + "aboriginal_lands", + "archipelago", + "islet" + ], + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 11 + ], + [ + 18, + 16 + ] + ] + }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [ + 0, + 0 + ], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 8 + }, + "paint": { + "text-color": "hsl(230, 29%, 35%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + }, + "interactive": true + }, + { + "id": "place-neighbourhood", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": [ + "==", + "type", + "neighbourhood" + ], + "layout": { + "text-field": "{name_en}", + "text-transform": "uppercase", + "text-letter-spacing": 0.1, + "text-max-width": 7, + "text-font": [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ], + "text-padding": 3, + "text-size": { + "base": 1, + "stops": [ + [ + 12, + 11 + ], + [ + 16, + 16 + ] + ] + } + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-color": "hsl(230, 29%, 35%)", + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "place-suburb", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": [ + "==", + "type", + "suburb" + ], + "layout": { + "text-field": "{name_en}", + "text-transform": "uppercase", + "text-font": [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ], + "text-letter-spacing": 0.15, + "text-max-width": 7, + "text-padding": 3, + "text-size": { + "base": 1, + "stops": [ + [ + 11, + 11 + ], + [ + 15, + 18 + ] + ] + } + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "text-color": "hsl(230, 29%, 35%)", + "text-halo-blur": 0.5 + }, + "interactive": true + }, + { + "id": "place-hamlet", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 10, + "maxzoom": 16, + "filter": [ + "==", + "type", + "hamlet" + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 12, + 11.5 + ], + [ + 15, + 16 + ] + ] + } + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-color": "hsl(0, 0%, 0%)" + }, + "interactive": true + }, + { + "id": "place-village", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 8, + "maxzoom": 15, + "filter": [ + "==", + "type", + "village" + ], + "layout": { + "text-field": "{name_en}", + "text-font": [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ], + "text-max-width": 7, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 11.5 + ], + [ + 16, + 18 + ] + ] + } + }, + "paint": { + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "text-color": "hsl(0, 0%, 0%)" + }, + "interactive": true + }, + { + "id": "place-town", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "minzoom": 6, + "maxzoom": 15, + "filter": [ + "==", + "type", + "town" + ], + "layout": { + "icon-image": "dot-9", + "text-font": { + "base": 1, + "stops": [ + [ + 11, + [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ] + ], + [ + 12, + [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ] + ] + ] + }, + "text-offset": { + "base": 1, + "stops": [ + [ + 7, + [ + 0, + -0.15 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "bottom" + ], + [ + 8, + "center" + ] + ] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { + "base": 1, + "stops": [ + [ + 7, + 11.5 + ], + [ + 15, + 20 + ] + ] + } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + } + }, + "interactive": true + }, + { + "id": "place-island", + "type": "symbol", + "source": "composite", + "source-layer": "place_label", + "maxzoom": 16, + "filter": [ + "==", + "type", + "island" + ], + "layout": { + "text-line-height": 1.2, + "text-size": { + "base": 1, + "stops": [ + [ + 10, + 11 + ], + [ + 18, + 16 + ] + ] + }, + "text-max-angle": 38, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ], + "text-padding": 2, + "text-offset": [ + 0, + 0 + ], + "text-rotation-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.01, + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(230, 29%, 35%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + }, + "interactive": true + }, + { + "id": "place-city-sm", + "type": "symbol", + "metadata": { + "mapbox:group": "1444862510685.128" + }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ + "all", + [ + "!in", + "scalerank", + 0, + 1, + 2, + 3, + 4, + 5 + ], + [ + "==", + "type", + "city" + ] + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 6, + 12 + ], + [ + 14, + 22 + ] + ] + }, + "icon-image": "dot-9", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ] + ], + [ + 8, + [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ] + ] + ] + }, + "text-offset": { + "base": 1, + "stops": [ + [ + 7.99, + [ + 0, + -0.2 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "bottom" + ], + [ + 8, + "center" + ] + ] + }, + "text-field": "{name_en}", + "text-max-width": 7 + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1.25, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + } + }, + "interactive": true + }, + { + "id": "place-city-md-s", + "type": "symbol", + "metadata": { + "mapbox:group": "1444862510685.128" + }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ + "all", + [ + "==", + "type", + "city" + ], + [ + "in", + "ldir", + "E", + "S", + "SE", + "SW" + ], + [ + "in", + "scalerank", + 3, + 4, + 5 + ] + ], + "layout": { + "text-field": "{name_en}", + "icon-image": "dot-10", + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "top" + ], + [ + 8, + "center" + ] + ] + }, + "text-offset": { + "base": 1, + "stops": [ + [ + 7.99, + [ + 0, + 0.1 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-font": { + "base": 1, + "stops": [ + [ + 7, + [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ] + ], + [ + 8, + [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ] + ] + ] + }, + "text-size": { + "base": 0.9, + "stops": [ + [ + 5, + 12 + ], + [ + 12, + 22 + ] + ] + } + }, + "paint": { + "text-halo-width": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-color": "hsl(0, 0%, 0%)", + "text-halo-blur": 1, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + } + }, + "interactive": true + }, + { + "id": "place-city-md-n", + "type": "symbol", + "metadata": { + "mapbox:group": "1444862510685.128" + }, + "source": "composite", + "source-layer": "place_label", + "maxzoom": 14, + "filter": [ + "all", + [ + "==", + "type", + "city" + ], + [ + "in", + "ldir", + "N", + "NE", + "NW", + "W" + ], + [ + "in", + "scalerank", + 3, + 4, + 5 + ] + ], + "layout": { + "icon-image": "dot-10", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ] + ], + [ + 8, + [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ] + ] + ] + }, + "text-offset": { + "base": 1, + "stops": [ + [ + 7.99, + [ + 0, + -0.25 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "bottom" + ], + [ + 8, + "center" + ] + ] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { + "base": 0.9, + "stops": [ + [ + 5, + 12 + ], + [ + 12, + 22 + ] + ] + } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + }, + "text-halo-blur": 1 + }, + "interactive": true + }, + { + "id": "place-city-lg-s", + "type": "symbol", + "metadata": { + "mapbox:group": "1444862510685.128" + }, + "source": "composite", + "source-layer": "place_label", + "minzoom": 1, + "maxzoom": 14, + "filter": [ + "all", + [ + "<=", + "scalerank", + 2 + ], + [ + "==", + "type", + "city" + ], + [ + "in", + "ldir", + "E", + "S", + "SE", + "SW" + ] + ], + "layout": { + "icon-image": "dot-11", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ] + ], + [ + 8, + [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ] + ] + ] + }, + "text-offset": { + "base": 1, + "stops": [ + [ + 7.99, + [ + 0, + 0.15 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "top" + ], + [ + 8, + "center" + ] + ] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { + "base": 0.9, + "stops": [ + [ + 4, + 12 + ], + [ + 10, + 22 + ] + ] + } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + }, + "text-halo-blur": 1 + }, + "interactive": true + }, + { + "id": "place-city-lg-n", + "type": "symbol", + "metadata": { + "mapbox:group": "1444862510685.128" + }, + "source": "composite", + "source-layer": "place_label", + "minzoom": 1, + "maxzoom": 14, + "filter": [ + "all", + [ + "<=", + "scalerank", + 2 + ], + [ + "==", + "type", + "city" + ], + [ + "in", + "ldir", + "N", + "NE", + "NW", + "W" + ] + ], + "layout": { + "icon-image": "dot-11", + "text-font": { + "base": 1, + "stops": [ + [ + 7, + [ + "DIN Offc Pro Regular,Arial Unicode MS Regular" + ] + ], + [ + 8, + [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ] + ] + ] + }, + "text-offset": { + "base": 1, + "stops": [ + [ + 7.99, + [ + 0, + -0.25 + ] + ], + [ + 8, + [ + 0, + 0 + ] + ] + ] + }, + "text-anchor": { + "base": 1, + "stops": [ + [ + 7, + "bottom" + ], + [ + 8, + "center" + ] + ] + }, + "text-field": "{name_en}", + "text-max-width": 7, + "text-size": { + "base": 0.9, + "stops": [ + [ + 4, + 12 + ], + [ + 10, + 22 + ] + ] + } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-opacity": 1, + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1, + "icon-opacity": { + "base": 1, + "stops": [ + [ + 7.99, + 1 + ], + [ + 8, + 0 + ] + ] + }, + "text-halo-blur": 1 + }, + "interactive": true + }, + { + "id": "marine-label-sm-ln", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856087950.3635" + }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 3, + "maxzoom": 10, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + ">=", + "labelrank", + 4 + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1, + "stops": [ + [ + 3, + 12 + ], + [ + 6, + 16 + ] + ] + }, + "symbol-spacing": { + "base": 1, + "stops": [ + [ + 4, + 100 + ], + [ + 6, + 400 + ] + ] + }, + "text-font": [ + "DIN Offc Pro Italic,Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.1, + "text-max-width": 5 + }, + "paint": { + "text-color": "hsl(205, 83%, 88%)" + }, + "interactive": true + }, + { + "id": "marine-label-sm-pt", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856087950.3635" + }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 3, + "maxzoom": 10, + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + ">=", + "labelrank", + 4 + ] + ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.1, + "text-line-height": 1.5, + "text-font": [ + "DIN Offc Pro Italic,Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 3, + 12 + ], + [ + 6, + 16 + ] + ] + } + }, + "paint": { + "text-color": "hsl(205, 83%, 88%)" + }, + "interactive": true + }, + { + "id": "marine-label-md-ln", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856087950.3635" + }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 2, + "maxzoom": 8, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "in", + "labelrank", + 2, + 3 + ] + ], + "layout": { + "text-line-height": 1.1, + "text-size": { + "base": 1.1, + "stops": [ + [ + 2, + 12 + ], + [ + 5, + 20 + ] + ] + }, + "symbol-spacing": 250, + "text-font": [ + "DIN Offc Pro Italic,Arial Unicode MS Regular" + ], + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-field": "{name_en}", + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": { + "text-color": "hsl(205, 83%, 88%)" + }, + "interactive": true + }, + { + "id": "marine-label-md-pt", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856087950.3635" + }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 2, + "maxzoom": 8, + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "in", + "labelrank", + 2, + 3 + ] + ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 5, + "text-letter-spacing": 0.15, + "text-line-height": 1.5, + "text-font": [ + "DIN Offc Pro Italic,Arial Unicode MS Regular" + ], + "text-size": { + "base": 1.1, + "stops": [ + [ + 2, + 14 + ], + [ + 5, + 20 + ] + ] + } + }, + "paint": { + "text-color": "hsl(205, 83%, 88%)" + }, + "interactive": true + }, + { + "id": "marine-label-lg-ln", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856087950.3635" + }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 1, + "maxzoom": 4, + "filter": [ + "all", + [ + "==", + "$type", + "LineString" + ], + [ + "==", + "labelrank", + 1 + ] + ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.1, + "symbol-placement": "line", + "text-pitch-alignment": "viewport", + "text-font": [ + "DIN Offc Pro Italic,Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 1, + 14 + ], + [ + 4, + 30 + ] + ] + } + }, + "paint": { + "text-color": "hsl(205, 83%, 88%)" + }, + "interactive": true + }, + { + "id": "marine-label-lg-pt", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856087950.3635" + }, + "source": "composite", + "source-layer": "marine_label", + "minzoom": 1, + "maxzoom": 4, + "filter": [ + "all", + [ + "==", + "$type", + "Point" + ], + [ + "==", + "labelrank", + 1 + ] + ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 4, + "text-letter-spacing": 0.25, + "text-line-height": 1.5, + "text-font": [ + "DIN Offc Pro Italic,Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 1, + 14 + ], + [ + 4, + 30 + ] + ] + } + }, + "paint": { + "text-color": "hsl(205, 83%, 88%)" + }, + "interactive": true + }, + { + "id": "state-label-sm", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856151690.9143" + }, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 9, + "filter": [ + "<", + "area", + 20000 + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 6, + 10 + ], + [ + 9, + 14 + ] + ] + }, + "text-transform": "uppercase", + "text-font": [ + "DIN Offc Pro Bold,Arial Unicode MS Bold" + ], + "text-field": { + "base": 1, + "stops": [ + [ + 0, + "{abbr}" + ], + [ + 6, + "{name_en}" + ] + ] + }, + "text-letter-spacing": 0.15, + "text-max-width": 5 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + }, + "interactive": true + }, + { + "id": "state-label-md", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856151690.9143" + }, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 8, + "filter": [ + "all", + [ + "<", + "area", + 80000 + ], + [ + ">=", + "area", + 20000 + ] + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 5, + 10 + ], + [ + 8, + 16 + ] + ] + }, + "text-transform": "uppercase", + "text-font": [ + "DIN Offc Pro Bold,Arial Unicode MS Bold" + ], + "text-field": { + "base": 1, + "stops": [ + [ + 0, + "{abbr}" + ], + [ + 5, + "{name_en}" + ] + ] + }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + }, + "interactive": true + }, + { + "id": "state-label-lg", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856151690.9143" + }, + "source": "composite", + "source-layer": "state_label", + "minzoom": 3, + "maxzoom": 7, + "filter": [ + ">=", + "area", + 80000 + ], + "layout": { + "text-size": { + "base": 1, + "stops": [ + [ + 4, + 10 + ], + [ + 7, + 18 + ] + ] + }, + "text-transform": "uppercase", + "text-font": [ + "DIN Offc Pro Bold,Arial Unicode MS Bold" + ], + "text-padding": 1, + "text-field": { + "base": 1, + "stops": [ + [ + 0, + "{abbr}" + ], + [ + 4, + "{name_en}" + ] + ] + }, + "text-letter-spacing": 0.15, + "text-max-width": 6 + }, + "paint": { + "text-opacity": 1, + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": "hsl(0, 0%, 100%)", + "text-halo-width": 1 + }, + "interactive": true + }, + { + "id": "country-label-sm", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856144497.7825" + }, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 10, + "filter": [ + ">=", + "scalerank", + 5 + ], + "layout": { + "text-field": "{name_en}", + "text-max-width": 6, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-size": { + "base": 0.9, + "stops": [ + [ + 5, + 14 + ], + [ + 9, + 22 + ] + ] + } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { + "base": 1, + "stops": [ + [ + 2, + "rgba(255,255,255,0.75)" + ], + [ + 3, + "hsl(0, 0%, 100%)" + ] + ] + }, + "text-halo-width": 1.25 + }, + "interactive": true + }, + { + "id": "country-label-md", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856144497.7825" + }, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 8, + "filter": [ + "in", + "scalerank", + 3, + 4 + ], + "layout": { + "text-field": { + "base": 1, + "stops": [ + [ + 0, + "{code}" + ], + [ + 2, + "{name_en}" + ] + ] + }, + "text-max-width": 6, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 3, + 10 + ], + [ + 8, + 24 + ] + ] + } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { + "base": 1, + "stops": [ + [ + 2, + "rgba(255,255,255,0.75)" + ], + [ + 3, + "hsl(0, 0%, 100%)" + ] + ] + }, + "text-halo-width": 1.25 + }, + "interactive": true + }, + { + "id": "country-label-lg", + "type": "symbol", + "metadata": { + "mapbox:group": "1444856144497.7825" + }, + "source": "composite", + "source-layer": "country_label", + "minzoom": 1, + "maxzoom": 7, + "filter": [ + "in", + "scalerank", + 1, + 2 + ], + "layout": { + "text-field": "{name_en}", + "text-max-width": { + "base": 1, + "stops": [ + [ + 0, + 5 + ], + [ + 3, + 6 + ] + ] + }, + "text-font": [ + "DIN Offc Pro Medium,Arial Unicode MS Regular" + ], + "text-size": { + "base": 1, + "stops": [ + [ + 1, + 10 + ], + [ + 6, + 24 + ] + ] + } + }, + "paint": { + "text-color": "hsl(0, 0%, 0%)", + "text-halo-color": { + "base": 1, + "stops": [ + [ + 2, + "rgba(255,255,255,0.75)" + ], + [ + 3, + "hsl(0, 0%, 100%)" + ] + ] + }, + "text-halo-width": 1.25 + }, + "interactive": true + } + ], + "created": "2018-08-16T10:31:44.982Z", + "id": "cjkwfdgzn1fz42rqtvsk6rrmd", + "modified": "2018-08-16T10:31:44.982Z", + "owner": "lukaspaczos", + "visibility": "private", + "draft": false +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java index 13913de26e..c62eef20f4 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/SymbolLayerActivity.java @@ -9,100 +9,119 @@ import android.support.annotation.NonNull; import android.support.v7.app.AppCompatActivity; import android.view.Menu; import android.view.MenuItem; - +import android.view.ViewGroup; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.mapbox.geojson.Feature; import com.mapbox.geojson.FeatureCollection; import com.mapbox.geojson.Point; -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; +import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.MapboxMapOptions; +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.style.layers.Property; import com.mapbox.mapboxsdk.style.layers.SymbolLayer; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.utils.BitmapUtils; - -import java.util.Arrays; import java.util.List; -import static com.mapbox.mapboxsdk.style.expressions.Expression.any; import static com.mapbox.mapboxsdk.style.expressions.Expression.get; -import static com.mapbox.mapboxsdk.style.expressions.Expression.has; -import static com.mapbox.mapboxsdk.style.expressions.Expression.literal; -import static com.mapbox.mapboxsdk.style.expressions.Expression.lte; -import static com.mapbox.mapboxsdk.style.expressions.Expression.not; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAnchor; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconColor; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAllowOverlap; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textAnchor; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textColor; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textField; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textFont; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textIgnorePlacement; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.textSize; /** * Test activity showcasing runtime manipulation of symbol layers. + *

+ * Showcases the ability to offline render a symbol layer by using a packaged style and fonts from the assets folder. + *

*/ -public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.OnMapClickListener { +public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap.OnMapClickListener, OnMapReadyCallback { + + private static final String MARKER_SOURCE = "marker-source"; + private static final String MARKER_LAYER = "marker-layer"; + private static final String MARKER_ICON = "my-layers-image"; - public static final String MARKER_SOURCE = "marker-source"; - public static final String MARKER_LAYER = "marker-layer"; private MapboxMap mapboxMap; private MapView mapView; + private boolean initialFont; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_symbollayer); - mapView = (MapView) findViewById(R.id.mapView); + // Create map configuration + MapboxMapOptions mapboxMapOptions = new MapboxMapOptions(); + mapboxMapOptions.camera(new CameraPosition.Builder().target( + new LatLng(52.35273, 4.91638)) + .zoom(13) + .build() + ); + mapboxMapOptions.styleUrl("asset://streets.json"); + + // Create map programmatically, add to view hierarchy + mapView = new MapView(this, mapboxMapOptions); + mapView.getMapAsync(this); mapView.onCreate(savedInstanceState); - mapView.getMapAsync(map -> { - mapboxMap = map; - - // Add a sdf image for the makers - Drawable icLayersDrawable = getResources().getDrawable(R.drawable.ic_layers); - Bitmap icLayersBitmap = BitmapUtils.getBitmapFromDrawable(icLayersDrawable); - mapboxMap.addImage( - "my-layers-image", - icLayersBitmap, - true - ); - - // Add a source - FeatureCollection markers = FeatureCollection.fromFeatures(new Feature[] { - Feature.fromGeometry(Point.fromLngLat(4.91638, 52.35673), featureProperties("Marker 1")), - Feature.fromGeometry(Point.fromLngLat(4.91638, 52.34673), featureProperties("Marker 2")) - }); - mapboxMap.addSource(new GeoJsonSource(MARKER_SOURCE, markers)); - - // Add the symbol-layer - mapboxMap.addLayer( - new SymbolLayer(MARKER_LAYER, MARKER_SOURCE) - .withProperties( - iconImage("my-layers-image"), - iconAllowOverlap(true), - iconAnchor(Property.ICON_ANCHOR_BOTTOM), - textField(get("title")), - iconColor(Color.RED), - textColor(Color.RED), - textAnchor(Property.TEXT_ANCHOR_TOP), - textSize(10f) - ).withFilter((any(not(has("price")), lte(get("price"), literal(25))))) - ); - - // Show - mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(52.35273, 4.91638), 14)); - - // Set a click-listener so we can manipulate the map - mapboxMap.setOnMapClickListener(SymbolLayerActivity.this); + ((ViewGroup) findViewById(R.id.container)).addView(mapView); + } + + @Override + public void onMapReady(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + + // Add a sdf image for the makers + Drawable icLayersDrawable = getResources().getDrawable(R.drawable.ic_layers); + Bitmap icLayersBitmap = BitmapUtils.getBitmapFromDrawable(icLayersDrawable); + mapboxMap.addImage( + MARKER_ICON, + icLayersBitmap, + true + ); + + // Add a source + FeatureCollection markers = FeatureCollection.fromFeatures(new Feature[] { + Feature.fromGeometry(Point.fromLngLat(4.91638, 52.35673), featureProperties("Marker 1")), + Feature.fromGeometry(Point.fromLngLat(4.91638, 52.34673), featureProperties("Marker 2")) }); + mapboxMap.addSource(new GeoJsonSource(MARKER_SOURCE, markers)); + + // Add the symbol-layer + mapboxMap.addLayer( + new SymbolLayer(MARKER_LAYER, MARKER_SOURCE) + .withProperties( + iconImage(MARKER_ICON), + iconIgnorePlacement(true), + iconAllowOverlap(true), + iconAnchor(Property.ICON_ANCHOR_BOTTOM), + iconColor(Color.RED), + textField(get("title")), + textFont(new String[] {"DIN Offc Pro Regular", "Arial Unicode MS Regular"}), + textColor(Color.RED), + textAllowOverlap(true), + textIgnorePlacement(true), + textAnchor(Property.TEXT_ANCHOR_TOP), + textSize(10f) + ) + ); + + // Set a click-listener so we can manipulate the map + mapboxMap.addOnMapClickListener(SymbolLayerActivity.this); } @Override @@ -132,13 +151,12 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap. private void toggleTextFont() { SymbolLayer layer = mapboxMap.getLayerAs(MARKER_LAYER); - - String[] fonts = layer.getTextFont().getValue(); - if (fonts == null || fonts.length == 0 || Arrays.asList(fonts).contains("Arial Unicode MS Regular")) { + if (initialFont) { layer.setProperties(textFont(new String[] {"DIN Offc Pro Bold", "Arial Unicode MS Bold"})); } else { layer.setProperties(textFont(new String[] {"DIN Offc Pro Medium", "Arial Unicode MS Regular"})); } + initialFont = !initialFont; } private JsonObject featureProperties(String title) { @@ -186,6 +204,9 @@ public class SymbolLayerActivity extends AppCompatActivity implements MapboxMap. @Override public void onDestroy() { super.onDestroy(); + if (mapboxMap != null) { + mapboxMap.removeOnMapClickListener(this); + } mapView.onDestroy(); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_symbollayer.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_symbollayer.xml index 9b88994f1c..62bcc3b34f 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_symbollayer.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_symbollayer.xml @@ -1,15 +1,8 @@ - - - + android:orientation="vertical"/> - diff --git a/platform/android/scripts/exclude-activity-gen.json b/platform/android/scripts/exclude-activity-gen.json index 36d8d36e68..e4418bdc53 100644 --- a/platform/android/scripts/exclude-activity-gen.json +++ b/platform/android/scripts/exclude-activity-gen.json @@ -35,5 +35,6 @@ "SymbolGeneratorActivity", "TextureViewTransparentBackgroundActivity", "SimpleMapActivity", - "RenderTestActivity" + "RenderTestActivity", + "SymbolLayerActivity" ] -- cgit v1.2.1 From c5ab61d1992d39af438c9ed3a8b0255ea22bd0b6 Mon Sep 17 00:00:00 2001 From: langsmith Date: Tue, 21 Aug 2018 10:41:58 -0700 Subject: added zh_CN strings.xml file --- .../src/main/res/values-zh_CN/strings.xml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml new file mode 100644 index 0000000000..1d510d1923 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml @@ -0,0 +1,15 @@ + + + Attribution图标,点击以显示attribution对话框。 + 定位视图,在地图上显示当前位置。 + 显示由Mapbox创建的地图,通过拖动两个手指来滚动,捏两个手指来放大。 + Mapbox Maps SDK for Android + 让Mapbox地图变得更好 + 您的匿名数据帮助OpenStreetMap和Mapbox的地图变得更好。 + 继续参与 + 不再参与 + 更多信息 + 设备中未安装任何浏览器,不能打开该网页 + 提供的OfflineRegionDefinition不符合标准地理范围:%s + Telemetry设置 + -- cgit v1.2.1 From 516131d4b0052d8dd33e8e69be53d2c54fc3fd10 Mon Sep 17 00:00:00 2001 From: langsmith Date: Tue, 21 Aug 2018 10:56:18 -0700 Subject: added zh_CN: zh-Hans to android lang_map in tx config file --- .tx/config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.tx/config b/.tx/config index 272fe45b16..42ef4ab563 100644 --- a/.tx/config +++ b/.tx/config @@ -46,7 +46,7 @@ type = STRINGS [mapbox-gl-native.stringsxml-android] file_filter = platform/android/MapboxGLAndroidSDK/src/main/res/values-/strings.xml -lang_map = pt_PT: pt-rPT +lang_map = pt_PT: pt-rPT, zh_CN: zh-Hans source_file = platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml source_lang = en type = ANDROID -- cgit v1.2.1 From 427a7ba2d392a370d49d5fda88e95bdc6626982e Mon Sep 17 00:00:00 2001 From: langsmith Date: Tue, 21 Aug 2018 10:58:45 -0700 Subject: fixed spacing --- .../android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml index 1d510d1923..f56e16dde2 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml @@ -12,4 +12,4 @@ 设备中未安装任何浏览器,不能打开该网页 提供的OfflineRegionDefinition不符合标准地理范围:%s Telemetry设置 -
+ -- cgit v1.2.1 From 250eaff9da3708d52a0d2b69a6d4cfb3aa790221 Mon Sep 17 00:00:00 2001 From: langsmith Date: Tue, 21 Aug 2018 11:04:23 -0700 Subject: abbreviation update --- .tx/config | 2 +- .../src/main/res/values-zh-rCN/strings.xml | 15 +++++++++++++++ .../src/main/res/values-zh_CN/strings.xml | 15 --------------- 3 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/values-zh-rCN/strings.xml delete mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml diff --git a/.tx/config b/.tx/config index 42ef4ab563..6ac5784884 100644 --- a/.tx/config +++ b/.tx/config @@ -46,7 +46,7 @@ type = STRINGS [mapbox-gl-native.stringsxml-android] file_filter = platform/android/MapboxGLAndroidSDK/src/main/res/values-/strings.xml -lang_map = pt_PT: pt-rPT, zh_CN: zh-Hans +lang_map = pt_PT: pt-rPT, zh_CN: zh-rCN source_file = platform/android/MapboxGLAndroidSDK/src/main/res/values/strings.xml source_lang = en type = ANDROID diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh-rCN/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh-rCN/strings.xml new file mode 100644 index 0000000000..f56e16dde2 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh-rCN/strings.xml @@ -0,0 +1,15 @@ + + + Attribution图标,点击以显示attribution对话框。 + 定位视图,在地图上显示当前位置。 + 显示由Mapbox创建的地图,通过拖动两个手指来滚动,捏两个手指来放大。 + Mapbox Maps SDK for Android + 让Mapbox地图变得更好 + 您的匿名数据帮助OpenStreetMap和Mapbox的地图变得更好。 + 继续参与 + 不再参与 + 更多信息 + 设备中未安装任何浏览器,不能打开该网页 + 提供的OfflineRegionDefinition不符合标准地理范围:%s + Telemetry设置 + diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml deleted file mode 100644 index f56e16dde2..0000000000 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/values-zh_CN/strings.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - Attribution图标,点击以显示attribution对话框。 - 定位视图,在地图上显示当前位置。 - 显示由Mapbox创建的地图,通过拖动两个手指来滚动,捏两个手指来放大。 - Mapbox Maps SDK for Android - 让Mapbox地图变得更好 - 您的匿名数据帮助OpenStreetMap和Mapbox的地图变得更好。 - 继续参与 - 不再参与 - 更多信息 - 设备中未安装任何浏览器,不能打开该网页 - 提供的OfflineRegionDefinition不符合标准地理范围:%s - Telemetry设置 - -- cgit v1.2.1 From 33cd094d853f9c74aeaa1466e9fe6986db448139 Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 21 Aug 2018 15:42:00 -0700 Subject: [core] fix icon-size for small data-driven values port of mapbox/mapbox-gl-js#7125 --- src/mbgl/programs/symbol_program.hpp | 4 +- src/mbgl/shaders/source.cpp | 374 +++++++++++++++++------------------ src/mbgl/shaders/symbol_icon.cpp | 2 +- src/mbgl/shaders/symbol_sdf.cpp | 4 +- 4 files changed, 192 insertions(+), 192 deletions(-) diff --git a/src/mbgl/programs/symbol_program.hpp b/src/mbgl/programs/symbol_program.hpp index 0378cc0970..651f12828f 100644 --- a/src/mbgl/programs/symbol_program.hpp +++ b/src/mbgl/programs/symbol_program.hpp @@ -66,8 +66,8 @@ struct SymbolLayoutAttributes : gl::Attributes< {{ tx, ty, - static_cast(sizeData.min * 10), - static_cast(sizeData.max * 10) + static_cast(sizeData.min * 256), + static_cast(sizeData.max * 256) }} }; } diff --git a/src/mbgl/shaders/source.cpp b/src/mbgl/shaders/source.cpp index d5a4593ad9..242b726004 100644 --- a/src/mbgl/shaders/source.cpp +++ b/src/mbgl/shaders/source.cpp @@ -1272,193 +1272,193 @@ const char* source() { 0xaf, 0xea, 0x39, 0x92, 0x2d, 0xac, 0x48, 0x1c, 0xf1, 0x0c, 0x60, 0x84, 0xdf, 0x0e, 0xde, 0x75, 0x24, 0xee, 0x6f, 0x87, 0xef, 0x3a, 0x9a, 0x51, - 0xe1, 0xa1, 0x3b, 0x1c, 0xa8, 0x53, 0xf7, 0x0f, - 0x81, 0xb3, 0x4f, 0x48, 0xdc, 0x1a, 0x0e, 0xba, - 0xff, 0xba, 0x9e, 0x9a, 0x86, 0x7b, 0xad, 0x9e, - 0x24, 0x4b, 0xb4, 0xe1, 0x37, 0xd7, 0xa9, 0xba, - 0xdc, 0x79, 0x4d, 0xee, 0xfb, 0xdb, 0x68, 0xa0, - 0xf6, 0x82, 0x1b, 0xde, 0x09, 0x0c, 0x73, 0x91, - 0x18, 0xde, 0x09, 0x90, 0x5c, 0xd0, 0xbd, 0x8d, - 0xd6, 0x5f, 0xcf, 0x02, 0x72, 0x8b, 0x27, 0x17, - 0x55, 0x54, 0x16, 0x99, 0x65, 0xa2, 0xf1, 0xa1, - 0xc7, 0x97, 0x90, 0xa5, 0x6e, 0x14, 0x54, 0x66, - 0x9c, 0x84, 0xa5, 0xbb, 0xe9, 0xc5, 0x37, 0x46, - 0x5e, 0xad, 0x45, 0xa9, 0xdf, 0xc4, 0xec, 0xc5, - 0xb1, 0x86, 0xd0, 0x54, 0xab, 0x5f, 0x0f, 0xbf, - 0x3c, 0x3b, 0xd6, 0x9d, 0x8a, 0xc6, 0x9c, 0x0d, - 0x52, 0xba, 0x2f, 0xfc, 0x1f, 0x5b, 0x5f, 0xf8, - 0xf6, 0xcf, 0x1d, 0x69, 0xa7, 0x50, 0x0f, 0x56, - 0x01, 0xe6, 0xef, 0x75, 0x1a, 0x9c, 0xd3, 0xdc, - 0xa1, 0x13, 0x2e, 0x2e, 0xeb, 0x54, 0xc4, 0x81, - 0x97, 0x76, 0x67, 0x61, 0x10, 0xa9, 0xd7, 0x0a, - 0x19, 0xdb, 0x0d, 0xf1, 0x8a, 0x6b, 0xda, 0xc7, - 0x7a, 0x48, 0x62, 0x78, 0x2c, 0x6b, 0xfd, 0x44, - 0xfd, 0xef, 0xc0, 0x58, 0xb6, 0x88, 0x56, 0x40, - 0x12, 0x2f, 0xe1, 0xed, 0x6c, 0xda, 0x19, 0x48, - 0x92, 0x67, 0xf2, 0xba, 0x49, 0x33, 0x65, 0xf1, - 0x0d, 0xb7, 0xee, 0x8b, 0xd1, 0x01, 0x5d, 0x5f, - 0x4b, 0x8e, 0x5b, 0xe2, 0x10, 0xbc, 0xd6, 0x74, - 0x58, 0xb2, 0xc9, 0x43, 0x6f, 0x0d, 0xde, 0x7d, - 0xce, 0x31, 0x6a, 0x13, 0xfb, 0xd6, 0x84, 0xa3, - 0x69, 0x9b, 0x79, 0xdc, 0xeb, 0xad, 0x28, 0x5c, - 0xa5, 0xc8, 0x1b, 0xca, 0xd4, 0x7e, 0x56, 0x1e, - 0x58, 0xc3, 0x02, 0xcb, 0x44, 0x4d, 0xd7, 0x75, - 0xd5, 0x84, 0xae, 0x9b, 0xf9, 0xfa, 0x22, 0xf6, - 0x75, 0x45, 0xe3, 0xca, 0x92, 0x8d, 0xd5, 0x75, - 0x79, 0xc6, 0x28, 0x67, 0x4e, 0x0b, 0x2f, 0xb6, - 0xba, 0x02, 0x5f, 0x65, 0x10, 0x61, 0xdb, 0x92, - 0x45, 0x47, 0xe0, 0x0d, 0x19, 0x16, 0x5e, 0xb8, - 0x19, 0xc5, 0xed, 0x95, 0x20, 0x1e, 0x3d, 0xc6, - 0xfc, 0x47, 0xa7, 0x9c, 0xe1, 0xc0, 0xe1, 0xdd, - 0x4f, 0x8a, 0xfd, 0x56, 0x6c, 0x7e, 0x86, 0x30, - 0xa1, 0xa3, 0x87, 0xf2, 0x5e, 0x6c, 0x05, 0x01, - 0xef, 0x9a, 0x85, 0xfa, 0xa6, 0x96, 0xe2, 0x94, - 0xaf, 0xa0, 0x35, 0xc4, 0x8e, 0xf2, 0xda, 0xd0, - 0x58, 0x76, 0xca, 0xbf, 0x4e, 0x9c, 0x54, 0x51, - 0xf6, 0x45, 0x35, 0x1f, 0x87, 0x55, 0x52, 0x87, - 0xb5, 0xe8, 0x76, 0x6d, 0x58, 0x8b, 0xaa, 0xec, - 0x0d, 0x8e, 0x65, 0xae, 0x20, 0x9f, 0xe8, 0xdb, - 0xeb, 0x02, 0x1c, 0x9b, 0x20, 0xe8, 0xd3, 0x06, - 0xa6, 0xa2, 0x38, 0x5e, 0xb4, 0x96, 0xaa, 0x23, - 0x19, 0xb4, 0x3f, 0x4e, 0x73, 0xa4, 0x37, 0x56, - 0xbb, 0x6c, 0x74, 0x3e, 0xd7, 0x47, 0x33, 0xfe, - 0xdb, 0xb7, 0xa5, 0x1a, 0x4d, 0x68, 0xb6, 0xe4, - 0x62, 0x44, 0x0f, 0xf9, 0xa1, 0xe5, 0xaa, 0x05, - 0x6e, 0xd6, 0x4b, 0x23, 0x77, 0x42, 0x3b, 0xbb, - 0x1a, 0x9c, 0x99, 0x64, 0x11, 0xc0, 0x6c, 0x30, - 0x8e, 0x7c, 0x8a, 0xe9, 0x97, 0x0a, 0x02, 0x2b, - 0xa3, 0x59, 0x40, 0x62, 0xe9, 0x5d, 0xb4, 0x68, - 0x2c, 0x68, 0x82, 0xc7, 0xec, 0x6f, 0x2e, 0x78, - 0x38, 0x1d, 0x9f, 0xd8, 0xdd, 0x17, 0xf2, 0xd0, - 0xdb, 0xa6, 0x27, 0x69, 0x12, 0x39, 0xf9, 0x64, - 0x31, 0x0a, 0x6f, 0x2e, 0x2d, 0xde, 0xe2, 0x0b, - 0x4e, 0x5b, 0xda, 0x97, 0x57, 0x1c, 0xaa, 0xd1, - 0x5e, 0x09, 0x9d, 0x2b, 0xf2, 0x46, 0xcb, 0xdf, - 0xe5, 0xbd, 0x43, 0x5b, 0x3d, 0x1e, 0xfa, 0xc2, - 0xb5, 0x61, 0x69, 0x2e, 0xe1, 0x03, 0x74, 0xa6, - 0xe4, 0x5a, 0x5c, 0x57, 0x37, 0x37, 0x5c, 0x7e, - 0xb9, 0xa2, 0xbb, 0x2d, 0x9d, 0xbd, 0x8b, 0xd3, - 0xef, 0x28, 0xbd, 0x13, 0x0d, 0xc2, 0xff, 0x8b, - 0x33, 0xd8, 0x09, 0x01, 0xdc, 0x1f, 0x5d, 0x84, - 0x42, 0x4f, 0x5e, 0xbe, 0x47, 0xcf, 0x36, 0x29, - 0xac, 0x65, 0x4a, 0xf6, 0x44, 0xe5, 0x14, 0x8e, - 0x76, 0xcc, 0xdb, 0x39, 0xd5, 0xb5, 0xb2, 0x64, - 0x9d, 0x4e, 0x8c, 0xba, 0xcb, 0x89, 0x3b, 0xfd, - 0x30, 0x46, 0x14, 0xa2, 0x4b, 0xf8, 0x8f, 0xb2, - 0x65, 0xe3, 0x33, 0x49, 0x3e, 0xe0, 0x8e, 0x39, - 0x1b, 0x18, 0x7d, 0x05, 0xdc, 0x8a, 0x08, 0x88, - 0x00, 0x8b, 0xe8, 0xd1, 0x22, 0xdd, 0x08, 0xe0, - 0xfb, 0xc3, 0x75, 0x4a, 0x86, 0x49, 0x29, 0x47, - 0x5a, 0x28, 0x16, 0xd5, 0xed, 0xec, 0x18, 0xcb, - 0xde, 0x12, 0x89, 0x10, 0xb4, 0x16, 0xbd, 0xda, - 0xfc, 0x1f, 0x10, 0x1c, 0xce, 0x40, 0x61, 0xef, - 0x28, 0x10, 0xed, 0x0e, 0xd6, 0x13, 0x56, 0x3d, - 0x7a, 0xc8, 0x59, 0xae, 0x27, 0xde, 0xed, 0x4c, - 0x0f, 0xca, 0xf4, 0x50, 0x7b, 0xf9, 0x1f, 0x46, - 0x51, 0xd3, 0x43, 0x19, 0x53, 0xde, 0xf0, 0x5a, - 0xc6, 0x54, 0xaa, 0x7c, 0x32, 0x63, 0x17, 0x37, - 0x78, 0x76, 0xb8, 0xd5, 0x1a, 0x5d, 0x16, 0x16, - 0x5e, 0x94, 0x34, 0x61, 0x6d, 0xca, 0x1b, 0xb0, - 0x36, 0x95, 0x2a, 0xb1, 0xb6, 0x8b, 0x1b, 0xb0, - 0x76, 0xab, 0x7d, 0x01, 0x6f, 0x6b, 0x68, 0x40, - 0x0d, 0x8f, 0x33, 0x4c, 0x79, 0x3d, 0xae, 0xa6, - 0x4e, 0x25, 0xba, 0x76, 0x71, 0x03, 0xc6, 0x6e, - 0xb5, 0xab, 0x91, 0xae, 0x7f, 0x52, 0xa5, 0x8b, - 0xaf, 0x40, 0xb9, 0xf6, 0x71, 0x95, 0x55, 0x7a, - 0x15, 0xc2, 0x05, 0x0f, 0xa2, 0x87, 0x67, 0x9e, - 0xba, 0x27, 0xa3, 0xe2, 0xb5, 0x8d, 0x9c, 0xd5, - 0x56, 0xc8, 0x6d, 0x6d, 0x69, 0x78, 0x3a, 0xbb, - 0x77, 0x80, 0xfb, 0xf2, 0xeb, 0xf0, 0x3a, 0x56, - 0x34, 0x8b, 0x1f, 0x92, 0x7c, 0xaa, 0xff, 0xac, - 0x7c, 0xdc, 0x63, 0x8a, 0x3b, 0x05, 0x5e, 0x59, - 0xf7, 0xcc, 0xc7, 0x05, 0x58, 0xc9, 0xf3, 0x1a, - 0xb0, 0xb3, 0xf8, 0x1e, 0xc1, 0xd5, 0x7f, 0x56, - 0x62, 0x67, 0x8a, 0x3b, 0x05, 0x9e, 0x58, 0x87, - 0x9d, 0x0b, 0xb0, 0x92, 0xb7, 0x7d, 0x26, 0x8f, - 0x82, 0x2c, 0x2e, 0xa6, 0x67, 0xaa, 0xfe, 0x75, - 0x89, 0x29, 0xee, 0x14, 0x38, 0x5c, 0x1d, 0x5e, - 0x2e, 0xc0, 0x4a, 0x56, 0x75, 0x15, 0x76, 0xda, - 0x5b, 0x4d, 0xff, 0x55, 0x8f, 0x9b, 0x7a, 0xc7, - 0x65, 0x31, 0xb2, 0x46, 0xcc, 0xb4, 0xd7, 0x5b, - 0x15, 0x4b, 0xfa, 0x4c, 0xed, 0xb6, 0x45, 0xb3, - 0xed, 0xce, 0x6e, 0xfb, 0x27, 0xb3, 0xdb, 0xbe, - 0x92, 0xb1, 0x5d, 0xf0, 0xac, 0x44, 0x91, 0x57, - 0x9a, 0x17, 0x4d, 0xc6, 0xd5, 0x25, 0xbe, 0x6d, - 0x8a, 0xbc, 0xcb, 0x64, 0x4d, 0xaf, 0x3b, 0xa6, - 0x89, 0x72, 0x5f, 0xe4, 0x7a, 0x19, 0x6c, 0xad, - 0xa0, 0x63, 0xa5, 0x1c, 0x9d, 0x2c, 0x28, 0xb7, - 0x68, 0xc6, 0x20, 0xb5, 0xe3, 0x90, 0xc6, 0x45, - 0xc5, 0x09, 0x48, 0x83, 0x88, 0xdf, 0x18, 0x81, - 0x64, 0xaf, 0x33, 0x21, 0x13, 0x34, 0xfb, 0x89, - 0x08, 0x25, 0x56, 0x0e, 0xd0, 0x81, 0x09, 0x9d, - 0x31, 0x64, 0x28, 0x1a, 0xf4, 0xc6, 0xe7, 0xd4, - 0xa7, 0xfe, 0xa5, 0x4e, 0xc0, 0x8a, 0x07, 0x94, - 0x7c, 0x0f, 0x63, 0x3b, 0xc6, 0xd3, 0x01, 0xda, - 0xab, 0x19, 0x2d, 0x86, 0x89, 0xa9, 0x1e, 0x30, - 0x45, 0x91, 0xd1, 0xc3, 0x8e, 0x0b, 0x18, 0x5e, - 0x67, 0xbc, 0x91, 0x97, 0xce, 0x0b, 0xc3, 0xc5, - 0x72, 0x49, 0x4a, 0xa0, 0xa9, 0xd0, 0xfb, 0x14, - 0xcb, 0x11, 0x73, 0xd9, 0xdb, 0x6e, 0xe0, 0x94, - 0x17, 0xfd, 0xea, 0x51, 0xff, 0x39, 0x4c, 0xee, - 0xdb, 0x98, 0xdb, 0x6f, 0xdf, 0xd4, 0xfe, 0x19, - 0x99, 0xd9, 0x99, 0xa5, 0x48, 0x1a, 0x25, 0x5a, - 0x7f, 0xac, 0x00, 0x75, 0xbd, 0x28, 0x9c, 0xc7, - 0x78, 0x56, 0x1c, 0x23, 0xf1, 0x3f, 0x26, 0xaf, - 0x3a, 0x58, 0x91, 0xf0, 0x03, 0x60, 0xeb, 0x45, - 0x5c, 0x1b, 0xf3, 0x99, 0x53, 0xb2, 0xe1, 0x84, - 0x5d, 0xec, 0xe8, 0xe5, 0x8a, 0xdd, 0xc1, 0x9b, - 0x04, 0xe4, 0xb0, 0x39, 0xea, 0xc7, 0xb8, 0x65, - 0x88, 0x56, 0xf9, 0xe4, 0x09, 0x63, 0xc3, 0x7d, - 0xe4, 0xf6, 0xa1, 0xed, 0x95, 0x7a, 0x1b, 0x0c, - 0x1b, 0xb2, 0xc0, 0x5d, 0x65, 0xf5, 0xa6, 0xdc, - 0x90, 0xb1, 0x17, 0x1b, 0xbe, 0x6c, 0x29, 0x41, - 0x89, 0x30, 0xe7, 0xe7, 0x93, 0xcb, 0xc0, 0xa3, - 0xb0, 0x4f, 0x80, 0x4d, 0x6d, 0x7f, 0xbd, 0xdd, - 0x15, 0xc2, 0xee, 0x0a, 0xe1, 0x8b, 0xbb, 0x42, - 0x30, 0x5c, 0xc5, 0x7d, 0x2d, 0xe6, 0x3c, 0x34, - 0xb3, 0x25, 0xca, 0xcf, 0xe2, 0xb2, 0x41, 0x3d, - 0xe2, 0xd5, 0xa6, 0xbe, 0xe9, 0x2d, 0xdc, 0x3e, - 0xc8, 0x6b, 0x0c, 0x52, 0x67, 0xd5, 0xe3, 0x30, - 0x7c, 0x17, 0x7b, 0x41, 0xa1, 0xb9, 0x4c, 0x3c, - 0x32, 0x56, 0x6d, 0x95, 0x1f, 0x9b, 0x35, 0xad, - 0x1d, 0xc1, 0xa1, 0xc0, 0x6a, 0xf1, 0xe2, 0x2b, - 0x0e, 0x15, 0xdf, 0xe8, 0xec, 0xbb, 0xef, 0xc7, - 0xaf, 0xff, 0x29, 0x8e, 0xac, 0xd0, 0x51, 0x2f, - 0xbf, 0xfb, 0xe1, 0xe5, 0xf8, 0x87, 0x17, 0x7f, - 0xff, 0xfb, 0x0b, 0x98, 0x8c, 0xe1, 0xe0, 0xb0, - 0x5f, 0x7e, 0xfb, 0x50, 0x65, 0x7c, 0x40, 0x55, - 0xe3, 0x64, 0x0b, 0x3b, 0xe3, 0x7d, 0x5b, 0x08, - 0xef, 0xd5, 0xb6, 0x77, 0x7f, 0xc6, 0xb9, 0x7b, - 0xb6, 0xab, 0xdd, 0x89, 0x51, 0xac, 0xf2, 0x7e, - 0xad, 0xda, 0x80, 0xe4, 0xbc, 0xb3, 0xa9, 0xb3, - 0x7c, 0xdd, 0x86, 0x51, 0xe8, 0x4a, 0x9b, 0xd0, - 0xcd, 0xac, 0x39, 0x57, 0x1b, 0x73, 0x6e, 0x64, - 0x86, 0xb9, 0xeb, 0xf7, 0x6b, 0x05, 0x3b, 0xca, - 0xcd, 0x2c, 0x20, 0x57, 0x19, 0x40, 0x6e, 0x66, - 0xbd, 0xe0, 0x33, 0x42, 0x2e, 0xb2, 0x36, 0x3a, - 0x54, 0x1d, 0x33, 0x72, 0xc9, 0x7b, 0x17, 0x45, - 0x23, 0x82, 0x55, 0x76, 0x59, 0x3a, 0x23, 0xcc, - 0x8c, 0xc9, 0x3a, 0x45, 0xef, 0xb1, 0x6b, 0x4b, - 0xc8, 0xca, 0xde, 0x6c, 0x3c, 0xd4, 0x6d, 0x8a, - 0x29, 0xca, 0x26, 0xfc, 0x12, 0xea, 0xd4, 0x66, - 0xc7, 0x7d, 0xd1, 0x32, 0x9d, 0xee, 0xb9, 0xbb, - 0x42, 0x1e, 0x0c, 0xf6, 0xd3, 0xc7, 0xf5, 0x6c, - 0x86, 0x9e, 0xd8, 0xa3, 0xc3, 0xa7, 0xf4, 0x60, - 0x9f, 0xe3, 0x8a, 0x00, 0x62, 0xf8, 0xb7, 0x2d, - 0x8c, 0x4b, 0xe6, 0x5d, 0xf2, 0xba, 0x87, 0xc6, - 0x36, 0xed, 0xa9, 0x32, 0x85, 0x58, 0xcb, 0x2c, - 0xd6, 0x1e, 0x1c, 0xf4, 0xc3, 0xe7, 0x00, 0x5b, - 0x1e, 0x27, 0x4f, 0x2c, 0xac, 0xdb, 0xdb, 0xa0, - 0x4d, 0x51, 0x8c, 0x24, 0xbe, 0x8c, 0xad, 0x45, - 0x5f, 0x7d, 0x4b, 0xae, 0xd0, 0x7d, 0x38, 0x52, - 0xa1, 0x35, 0x6a, 0xf9, 0x56, 0xad, 0xf2, 0xa2, - 0x19, 0xaf, 0x99, 0xd5, 0x7b, 0x81, 0xd2, 0x54, - 0x33, 0x3e, 0x53, 0x0a, 0xa5, 0x81, 0x03, 0xdc, - 0x13, 0xa5, 0xb7, 0x7d, 0x8e, 0xe8, 0x28, 0xaf, - 0xbf, 0xad, 0x57, 0x6e, 0x34, 0x80, 0xae, 0x03, - 0xad, 0xc3, 0xa3, 0x7a, 0x52, 0xf8, 0x78, 0x83, - 0xe7, 0x6c, 0x28, 0x5d, 0xb9, 0xa7, 0xf8, 0x2d, - 0x5c, 0x93, 0xff, 0x7f, 0xc9, 0x73, 0xe5, 0xd5 + 0x91, 0xcf, 0x31, 0xa6, 0xa5, 0x93, 0xc2, 0x8b, + 0xc0, 0xe9, 0x27, 0x2c, 0x6e, 0x0d, 0x09, 0x8d, + 0x40, 0x6d, 0x57, 0x4d, 0x03, 0xbe, 0x56, 0x57, + 0x92, 0x29, 0xda, 0xf0, 0x9b, 0xeb, 0x54, 0x5d, + 0xef, 0xbc, 0x26, 0x07, 0xfe, 0x6d, 0x74, 0x50, + 0x7b, 0xc9, 0x0d, 0xf7, 0x04, 0x96, 0xb9, 0x48, + 0x0c, 0xf7, 0x04, 0x48, 0x2e, 0xe8, 0xde, 0x46, + 0x6b, 0xb0, 0x67, 0x01, 0x39, 0xc6, 0x93, 0x93, + 0x2a, 0xaa, 0x8b, 0xcc, 0x34, 0xd1, 0xfc, 0xd0, + 0xe3, 0x6b, 0xc8, 0x52, 0x37, 0x0a, 0x2a, 0xb3, + 0x4e, 0xc2, 0xd2, 0xdd, 0xf6, 0xe2, 0x1b, 0x23, + 0xb1, 0xd6, 0xa2, 0xd4, 0x6f, 0x62, 0xf7, 0xe2, + 0x58, 0x43, 0x68, 0xaa, 0xd5, 0xaf, 0x87, 0x5f, + 0x9e, 0x1d, 0xeb, 0x56, 0x45, 0x63, 0xce, 0x26, + 0x29, 0xdd, 0x17, 0xfe, 0x8f, 0xed, 0x2f, 0x7c, + 0xff, 0xe7, 0x8e, 0xb4, 0x53, 0xa8, 0x07, 0xab, + 0x00, 0xf3, 0xf7, 0x3a, 0x0d, 0xce, 0x69, 0xee, + 0xd0, 0x0d, 0x17, 0x97, 0x75, 0x2a, 0xe2, 0xc0, + 0x4b, 0xbb, 0xb3, 0x30, 0x88, 0xd4, 0x7b, 0x85, + 0x8c, 0x2d, 0x87, 0x78, 0xc9, 0x35, 0xed, 0x63, + 0x3d, 0x24, 0x31, 0x3c, 0x98, 0xb5, 0x86, 0xa2, + 0xfe, 0x77, 0x60, 0x6c, 0x5b, 0x44, 0x2b, 0x20, + 0x8b, 0x97, 0xf0, 0x76, 0xb6, 0xed, 0x0c, 0x64, + 0xc9, 0x33, 0x79, 0xe1, 0xa4, 0xd9, 0xb2, 0xf8, + 0x86, 0x5b, 0x03, 0xb1, 0x1f, 0xd0, 0x05, 0xb6, + 0xe4, 0xb9, 0x25, 0x1e, 0xc1, 0x6b, 0x4d, 0xc7, + 0x25, 0x1b, 0x3d, 0x06, 0x6a, 0x6b, 0xf0, 0xf6, + 0x73, 0x0e, 0x52, 0x9b, 0xd8, 0xb7, 0x26, 0x1c, + 0x4d, 0xdb, 0xcc, 0xe5, 0x5e, 0x6f, 0x45, 0xe1, + 0x2a, 0x49, 0xde, 0x50, 0x26, 0xf7, 0xb3, 0x32, + 0xc1, 0x1a, 0x26, 0x58, 0x26, 0x6a, 0xba, 0xb0, + 0xab, 0x26, 0x74, 0xdd, 0xcc, 0xd7, 0x57, 0xb1, + 0xaf, 0x2b, 0x1a, 0x57, 0x96, 0x6c, 0xac, 0xae, + 0xcb, 0x33, 0x46, 0x59, 0x73, 0x5a, 0x78, 0xb5, + 0xd5, 0x15, 0xf8, 0x2e, 0x83, 0x08, 0xdb, 0x96, + 0x2d, 0x3a, 0x02, 0xef, 0xc8, 0xb0, 0xf0, 0xc2, + 0xcd, 0x29, 0x6e, 0xaf, 0x04, 0x71, 0xe9, 0x31, + 0x66, 0x40, 0x3a, 0xe5, 0x1c, 0x07, 0x0e, 0xf7, + 0x7e, 0x52, 0xec, 0xb7, 0x62, 0xf3, 0x33, 0x84, + 0x09, 0x1d, 0x3e, 0x94, 0xf9, 0x62, 0x2b, 0x08, + 0x78, 0xdb, 0x2c, 0xd4, 0x37, 0xb5, 0x14, 0xa7, + 0x7c, 0x09, 0xad, 0x21, 0x76, 0x94, 0xdf, 0x86, + 0xc6, 0xb2, 0x53, 0xfe, 0x75, 0xe2, 0x24, 0x8b, + 0xb2, 0xaf, 0xaa, 0xf9, 0x40, 0xac, 0x92, 0x3b, + 0xac, 0x45, 0xb7, 0x6b, 0xc3, 0x5a, 0x54, 0xe5, + 0x6f, 0x70, 0x6c, 0x73, 0x05, 0x09, 0x45, 0xdf, + 0x5f, 0x17, 0xe0, 0xd8, 0x04, 0x41, 0x9f, 0x36, + 0x30, 0x15, 0xc5, 0xf1, 0xa2, 0xbd, 0x54, 0x1d, + 0xca, 0xa0, 0xff, 0x71, 0xa2, 0x23, 0xbd, 0xb1, + 0xda, 0x65, 0xb3, 0xf3, 0xb9, 0x3e, 0x9c, 0xf1, + 0xdf, 0xbe, 0x2d, 0xd7, 0x68, 0x42, 0xb3, 0x65, + 0x17, 0x23, 0x7c, 0xc8, 0x0f, 0x2d, 0x57, 0x31, + 0x70, 0xf3, 0x5e, 0x1a, 0xc9, 0x13, 0xda, 0xd9, + 0xd5, 0xe0, 0xd4, 0x24, 0x9b, 0x00, 0xe6, 0x83, + 0x71, 0x24, 0x54, 0x4c, 0xc0, 0x54, 0x10, 0x59, + 0x19, 0xcd, 0x02, 0x12, 0x4b, 0xef, 0xa2, 0x45, + 0x63, 0x41, 0x23, 0x3c, 0xe6, 0x7f, 0x73, 0xc1, + 0xc3, 0xf1, 0xf8, 0xc4, 0xee, 0xbe, 0x90, 0x89, + 0xde, 0x36, 0x3e, 0x49, 0xa3, 0xc8, 0xc9, 0x27, + 0x8b, 0x52, 0x78, 0x73, 0x79, 0xf1, 0x16, 0xdf, + 0x70, 0xda, 0xf2, 0xbe, 0xbc, 0xe4, 0x50, 0x8d, + 0xf6, 0x4a, 0xe8, 0x5c, 0x91, 0x39, 0x5a, 0xfe, + 0x2e, 0x6f, 0x1e, 0xda, 0xea, 0xf9, 0xd0, 0x17, + 0xae, 0x0f, 0x4b, 0x83, 0x09, 0x1f, 0xa0, 0x33, + 0x25, 0xd9, 0xe2, 0xba, 0xba, 0xd9, 0xe1, 0xf2, + 0xcb, 0x15, 0xdd, 0x6e, 0xe9, 0xfc, 0x5d, 0x9c, + 0x80, 0x47, 0x69, 0x9e, 0x68, 0x12, 0xfe, 0x5f, + 0x9c, 0xc1, 0x4e, 0x08, 0xe0, 0xfe, 0xe8, 0x22, + 0x14, 0x7a, 0xf4, 0xf2, 0x3d, 0xfa, 0xb6, 0x49, + 0x61, 0x2d, 0x53, 0xd2, 0x27, 0xaa, 0xa7, 0x70, + 0xb4, 0x63, 0xe6, 0xce, 0xa9, 0xae, 0x95, 0x25, + 0xeb, 0x74, 0x62, 0x14, 0x5e, 0x4e, 0xdd, 0xe9, + 0x87, 0x31, 0xa2, 0x10, 0x5d, 0xc2, 0x7f, 0x94, + 0x35, 0x1b, 0x1f, 0x4a, 0xf2, 0x01, 0x77, 0xcc, + 0xf9, 0xc0, 0xe8, 0x2b, 0xe0, 0x56, 0x44, 0x40, + 0x04, 0x58, 0x44, 0xcf, 0x16, 0xe9, 0x4e, 0x00, + 0x5f, 0x20, 0xae, 0x53, 0x32, 0x4d, 0x4a, 0x39, + 0xd2, 0x42, 0xb1, 0xa8, 0x70, 0x67, 0xc7, 0x58, + 0xf6, 0x96, 0x48, 0x84, 0xa0, 0xb5, 0xe8, 0xdd, + 0xe6, 0xff, 0x80, 0xe0, 0x70, 0x06, 0x2a, 0x7b, + 0x47, 0x81, 0x68, 0x77, 0xb0, 0x9e, 0xb0, 0xea, + 0xd1, 0x53, 0xce, 0x72, 0x3d, 0xf1, 0x6e, 0x67, + 0x7c, 0x50, 0xc6, 0x87, 0xda, 0xeb, 0xff, 0x30, + 0x8a, 0x9a, 0x9e, 0xca, 0x98, 0xf2, 0x86, 0xf7, + 0x32, 0xa6, 0x52, 0xe5, 0xa3, 0x19, 0xbb, 0xb8, + 0xc1, 0xb7, 0xc3, 0xad, 0xd6, 0xe8, 0xb4, 0xb0, + 0xf0, 0xa2, 0xa4, 0x09, 0x6b, 0x53, 0xde, 0x80, + 0xb5, 0xa9, 0x54, 0x89, 0xb5, 0x5d, 0xdc, 0x80, + 0xb5, 0x5b, 0xed, 0x0b, 0x78, 0x5d, 0x43, 0x03, + 0x6a, 0x78, 0x9e, 0x61, 0xca, 0xeb, 0x71, 0x35, + 0x75, 0x2a, 0xd1, 0xb5, 0x8b, 0x1b, 0x30, 0x76, + 0xab, 0x5d, 0x8d, 0x74, 0xfd, 0xa3, 0x2a, 0x5d, + 0x7c, 0x05, 0xca, 0xb5, 0xcf, 0xab, 0xac, 0xd2, + 0xab, 0x10, 0x2e, 0xf8, 0x10, 0x3d, 0x3c, 0x03, + 0xd5, 0x3d, 0x99, 0x15, 0xaf, 0x6d, 0xe6, 0xac, + 0xb6, 0x43, 0x6e, 0x6b, 0x4d, 0xc3, 0xd3, 0xd9, + 0xbd, 0x05, 0xdc, 0x97, 0x5f, 0x87, 0xd7, 0xb1, + 0xa3, 0x59, 0xfc, 0x90, 0xe4, 0x53, 0xfd, 0x67, + 0xe5, 0xf3, 0x1e, 0x53, 0xdc, 0x29, 0xf0, 0xca, + 0xba, 0x87, 0x3e, 0x2e, 0xc0, 0x4a, 0x9e, 0xd7, + 0x80, 0x9d, 0xc5, 0xf7, 0x08, 0xae, 0xfe, 0xb3, + 0x12, 0x3b, 0x53, 0xdc, 0x29, 0xf0, 0xc4, 0x3a, + 0xec, 0x5c, 0x80, 0x95, 0xbc, 0xed, 0x33, 0x79, + 0x16, 0x64, 0x71, 0x31, 0x3d, 0x53, 0xf5, 0xef, + 0x4b, 0x4c, 0x71, 0xa7, 0xc0, 0xe1, 0xea, 0xf0, + 0x72, 0x01, 0x56, 0xb2, 0xaa, 0xab, 0xb0, 0xd3, + 0xfe, 0x6a, 0xfa, 0xaf, 0x7a, 0xdc, 0xd4, 0x4b, + 0x2e, 0x8b, 0x91, 0x35, 0x62, 0xa6, 0xfd, 0xde, + 0xaa, 0x58, 0xd2, 0x67, 0x6a, 0xb9, 0x2d, 0x1a, + 0x6e, 0x77, 0x96, 0xdb, 0x3f, 0x9d, 0xe5, 0xf6, + 0x95, 0x8c, 0xef, 0x82, 0xa7, 0x25, 0x0a, 0xbd, + 0xd2, 0xc0, 0x68, 0xb2, 0xae, 0x2e, 0xf1, 0x7d, + 0x53, 0xe4, 0x5d, 0x26, 0x6b, 0x7a, 0xe1, 0x31, + 0x4d, 0x94, 0x0b, 0x23, 0xd7, 0xcb, 0x60, 0x73, + 0x05, 0x1d, 0x2b, 0xed, 0xe8, 0x64, 0x41, 0xf9, + 0x45, 0x33, 0x06, 0xa9, 0x9d, 0x87, 0x34, 0x2e, + 0x2a, 0x56, 0x40, 0x1a, 0x44, 0xfc, 0xce, 0x08, + 0x64, 0x7b, 0x9d, 0x0d, 0x99, 0xa0, 0xd9, 0xcf, + 0x44, 0x28, 0xb9, 0x72, 0x80, 0x4e, 0x4c, 0xe8, + 0x90, 0x21, 0xc3, 0xd1, 0xa0, 0x47, 0x3e, 0xa7, + 0x3f, 0xf5, 0x2f, 0x75, 0x12, 0x56, 0x3c, 0xa2, + 0xe4, 0x9b, 0x18, 0xdb, 0x39, 0x9e, 0x8e, 0xd0, + 0x5e, 0xcd, 0x68, 0x31, 0x54, 0x4c, 0xf5, 0x80, + 0x29, 0x92, 0x8c, 0x1e, 0x76, 0x5c, 0xc0, 0xf0, + 0x3a, 0xe3, 0x8d, 0xbc, 0x74, 0x5e, 0x18, 0x2e, + 0x96, 0x4b, 0x52, 0x02, 0x5d, 0x85, 0xde, 0xa8, + 0x58, 0xce, 0x98, 0xcb, 0xde, 0x76, 0x03, 0xa7, + 0xdc, 0xe8, 0x57, 0x8f, 0xfa, 0xcf, 0x61, 0x74, + 0xdf, 0xc6, 0xe0, 0x7e, 0xfb, 0xc6, 0xf6, 0xcf, + 0xc8, 0xd0, 0xce, 0x2c, 0x45, 0xd2, 0x28, 0xd1, + 0xfa, 0x63, 0x05, 0xa8, 0xeb, 0x45, 0xe1, 0x3c, + 0xc6, 0xd3, 0xe2, 0x18, 0x89, 0xff, 0x31, 0x79, + 0xd6, 0xc1, 0x8a, 0x84, 0x1f, 0x00, 0x5b, 0x2f, + 0xe2, 0xda, 0x98, 0xd3, 0x9c, 0x12, 0x0e, 0x27, + 0xec, 0x66, 0x47, 0xaf, 0x57, 0xec, 0x0e, 0xde, + 0x24, 0x20, 0x89, 0xcd, 0x51, 0x43, 0xc6, 0x2d, + 0x43, 0xb4, 0xca, 0x67, 0x4f, 0x18, 0x1b, 0xee, + 0x23, 0xb7, 0x0f, 0x6d, 0xaf, 0xd4, 0xdb, 0x60, + 0xe8, 0x90, 0x05, 0xee, 0x2a, 0xab, 0x37, 0xe5, + 0x8a, 0x8c, 0xbd, 0xd8, 0xf0, 0x65, 0x4b, 0x09, + 0x4a, 0x84, 0x39, 0x3f, 0xa1, 0x5c, 0x06, 0x1e, + 0x85, 0x7e, 0x02, 0x6c, 0x6a, 0xfb, 0xeb, 0xed, + 0x2e, 0x11, 0x76, 0x97, 0x08, 0x5f, 0xdc, 0x25, + 0x82, 0xe1, 0x2a, 0xee, 0x8b, 0x31, 0xe7, 0xb1, + 0x99, 0x2d, 0x53, 0x7e, 0x16, 0xd7, 0x0d, 0xea, + 0x21, 0xaf, 0x36, 0xf6, 0x4d, 0x6f, 0xe1, 0xfe, + 0x41, 0x5e, 0x64, 0x90, 0x42, 0xab, 0x1e, 0x88, + 0xe1, 0xdb, 0xd8, 0x0b, 0x0a, 0xcf, 0x65, 0x62, + 0x92, 0xb1, 0x72, 0xab, 0x7c, 0xd9, 0xac, 0x69, + 0xed, 0x08, 0x0e, 0x07, 0x56, 0x8b, 0x17, 0x5f, + 0x72, 0xa8, 0x18, 0x47, 0x67, 0xdf, 0x7d, 0x3f, + 0x7e, 0xfd, 0x4f, 0x71, 0x64, 0x85, 0x8f, 0x7a, + 0xf9, 0xdd, 0x0f, 0x2f, 0xc7, 0x3f, 0xbc, 0xf8, + 0xfb, 0xdf, 0x5f, 0xc0, 0x64, 0x0c, 0x07, 0x87, + 0xfd, 0xf2, 0xfb, 0x87, 0x2a, 0xf3, 0x03, 0x2a, + 0x1b, 0x27, 0x5b, 0x58, 0x1a, 0xef, 0xdb, 0x46, + 0x78, 0xaf, 0xd6, 0xbd, 0xfb, 0x33, 0xcf, 0xdd, + 0xb3, 0x65, 0xed, 0x4e, 0xcc, 0x62, 0x95, 0x37, + 0x6c, 0xd5, 0x26, 0x24, 0xe7, 0xad, 0x4d, 0x9d, + 0xed, 0xeb, 0x36, 0xcc, 0x42, 0x57, 0x5a, 0x85, + 0x6e, 0x66, 0xcf, 0xb9, 0xda, 0x9c, 0x73, 0x23, + 0x43, 0xcc, 0x5d, 0xbf, 0x61, 0x2b, 0x58, 0x52, + 0x6e, 0x66, 0x03, 0xb9, 0xca, 0x04, 0x72, 0x33, + 0xfb, 0x05, 0x9f, 0x11, 0x72, 0x91, 0xb5, 0xd9, + 0xa1, 0xea, 0x98, 0x91, 0x4b, 0xde, 0xbb, 0x28, + 0x9a, 0x11, 0xac, 0xb2, 0xcb, 0xd2, 0x19, 0x61, + 0x66, 0x4c, 0xd6, 0x29, 0x7a, 0x90, 0x5d, 0x5b, + 0x42, 0x56, 0x16, 0x67, 0xe3, 0xa5, 0x6e, 0x53, + 0x4c, 0x51, 0x36, 0xe1, 0xd7, 0x50, 0xa7, 0x36, + 0x3b, 0xee, 0x8b, 0x96, 0xe9, 0x74, 0xcf, 0xdd, + 0x15, 0xf2, 0x60, 0xb0, 0x9f, 0x3f, 0xae, 0x67, + 0x33, 0xf4, 0xc6, 0x26, 0x33, 0x02, 0xc8, 0x52, + 0x1c, 0x5b, 0xc4, 0x31, 0x2b, 0x68, 0xd3, 0x05, + 0xce, 0x74, 0xc9, 0xf3, 0x1e, 0x1a, 0xdb, 0xb4, + 0xa7, 0xca, 0x14, 0x62, 0x2d, 0xb3, 0x58, 0x7b, + 0x70, 0xd0, 0x0f, 0x9f, 0x03, 0x6c, 0x79, 0x9c, + 0x3c, 0xb1, 0xb0, 0x6e, 0x6f, 0x83, 0x36, 0x45, + 0x32, 0x92, 0xf8, 0x32, 0xb6, 0x16, 0x7d, 0xf5, + 0x2d, 0xb9, 0x42, 0xf7, 0xe1, 0x48, 0x85, 0xd6, + 0xa8, 0xe5, 0x7b, 0xb5, 0xca, 0xab, 0x66, 0xbc, + 0x68, 0x56, 0x6f, 0x06, 0x4a, 0x53, 0xcd, 0xf8, + 0x4c, 0x29, 0x9c, 0x06, 0x0e, 0x70, 0x4f, 0x94, + 0xde, 0xf7, 0x39, 0xa2, 0xa3, 0xbc, 0x00, 0xb7, + 0x5e, 0xba, 0xd1, 0x00, 0xba, 0x0e, 0xb4, 0x0e, + 0x8f, 0xea, 0x49, 0xe1, 0xe3, 0x0d, 0x9e, 0xb4, + 0xa1, 0x74, 0xe5, 0x9e, 0xe2, 0xb7, 0x70, 0x51, + 0xfe, 0xff, 0x01, 0x25, 0x68, 0xe6, 0xc5 }; static std::string decompressed = util::decompress(std::string(reinterpret_cast(compressed), sizeof(compressed))); return decompressed.c_str(); diff --git a/src/mbgl/shaders/symbol_icon.cpp b/src/mbgl/shaders/symbol_icon.cpp index 9e33b99def..db758b656b 100644 --- a/src/mbgl/shaders/symbol_icon.cpp +++ b/src/mbgl/shaders/symbol_icon.cpp @@ -8,7 +8,7 @@ namespace shaders { const char* symbol_icon::name = "symbol_icon"; const char* symbol_icon::vertexSource = source() + 59607; -const char* symbol_icon::fragmentSource = source() + 63011; +const char* symbol_icon::fragmentSource = source() + 63013; } // namespace shaders } // namespace mbgl diff --git a/src/mbgl/shaders/symbol_sdf.cpp b/src/mbgl/shaders/symbol_sdf.cpp index 3443b4f21c..de9d3729a3 100644 --- a/src/mbgl/shaders/symbol_sdf.cpp +++ b/src/mbgl/shaders/symbol_sdf.cpp @@ -7,8 +7,8 @@ namespace mbgl { namespace shaders { const char* symbol_sdf::name = "symbol_sdf"; -const char* symbol_sdf::vertexSource = source() + 63461; -const char* symbol_sdf::fragmentSource = source() + 69382; +const char* symbol_sdf::vertexSource = source() + 63463; +const char* symbol_sdf::fragmentSource = source() + 69386; } // namespace shaders } // namespace mbgl -- cgit v1.2.1 From fd1767efba85dcfa5a3db27136306eca53519b8a Mon Sep 17 00:00:00 2001 From: Chris Loer Date: Tue, 21 Aug 2018 16:19:43 -0700 Subject: [core, test] Bump GL JS pin to bring gl-native back in sync with gl-js. Requires changing `generate-style-code` to treat 'formatted' as being the same as 'string' until gl-native gets 'formatted' support with https://github.com/mapbox/mapbox-gl-native/pull/12624. To make nitpick happy, PropertyFunction.java uses the latest "text-field" description from v8.json. It's technically correct, just kind of pointless since the "If a plain `string` is provided" clause will always be true. --- mapbox-gl-js | 2 +- .../com/mapbox/mapboxsdk/style/layers/PropertyFactory.java | 4 ++-- platform/android/scripts/generate-style-code.js | 7 +++++++ platform/darwin/scripts/generate-style-code.js | 11 ++++++++++- platform/node/test/ignores.json | 12 ++++++++++++ scripts/generate-style-code.js | 2 ++ 6 files changed, 34 insertions(+), 4 deletions(-) diff --git a/mapbox-gl-js b/mapbox-gl-js index 6c22a1720d..754ec0bf51 160000 --- a/mapbox-gl-js +++ b/mapbox-gl-js @@ -1 +1 @@ -Subproject commit 6c22a1720dac51eac1c898ca06b3e2f24dbe0810 +Subproject commit 754ec0bf51c3798d096aa38c3f009dcb58d3be71 diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java index 1cedf8c9ca..cd7bd473f3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java @@ -2055,7 +2055,7 @@ public class PropertyFactory { } /** - * Value to use for a text label. + * Value to use for a text label. If a plain `string` is provided, it will be treated as a `formatted` with default/inherited formatting options. * * @param value a String value * @return property wrapper around String @@ -2065,7 +2065,7 @@ public class PropertyFactory { } /** - * Value to use for a text label. + * Value to use for a text label. If a plain `string` is provided, it will be treated as a `formatted` with default/inherited formatting options. * * @param value a String value * @return property wrapper around String diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js index 98c5a446b9..0825ef1c26 100755 --- a/platform/android/scripts/generate-style-code.js +++ b/platform/android/scripts/generate-style-code.js @@ -55,6 +55,7 @@ global.propertyType = function propertyType(property) { return 'Boolean'; case 'number': return 'Float'; + case 'formatted': case 'string': return 'String'; case 'enum': @@ -74,6 +75,7 @@ global.propertyJavaType = function propertyType(property) { return 'boolean'; case 'number': return 'float'; + case 'formatted': case 'string': return 'String'; case 'enum': @@ -121,6 +123,7 @@ global.propertyNativeType = function (property) { return 'bool'; case 'number': return 'float'; + case 'formatted': case 'string': return 'std::string'; case 'enum': @@ -155,6 +158,7 @@ global.defaultExpressionJava = function(property) { return 'boolean'; case 'number': return 'number'; + case 'formatted': case 'string': return "string"; case 'enum': @@ -179,6 +183,7 @@ global.defaultValueJava = function(property) { return 'true'; case 'number': return '0.3f'; + case 'formatted': case 'string': return '"' + property['default'] + '"'; case 'enum': @@ -187,6 +192,7 @@ global.defaultValueJava = function(property) { return '"rgba(0, 0, 0, 1)"'; case 'array': switch (property.value) { + case 'formatted': case 'string': return '[' + property['default'] + "]"; case 'number': @@ -301,6 +307,7 @@ global.evaluatedType = function (property) { return 'bool'; case 'number': return 'float'; + case 'formatted': case 'string': return 'std::string'; case 'enum': diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js index 0e5bf89fd4..e89a4e29a3 100755 --- a/platform/darwin/scripts/generate-style-code.js +++ b/platform/darwin/scripts/generate-style-code.js @@ -102,6 +102,7 @@ global.objCTestValue = function (property, layerType, arraysAsStructs, indent) { return property.default ? '@"false"' : '@"true"'; case 'number': return '@"1"'; + case 'formatted': case 'string': return `@"'${_.startCase(propertyName)}'"`; case 'enum': @@ -146,6 +147,7 @@ global.mbglTestValue = function (property, layerType) { return property.default ? 'false' : 'true'; case 'number': return '1.0'; + case 'formatted': case 'string': return `"${_.startCase(propertyName)}"`; case 'enum': { @@ -218,6 +220,7 @@ global.testHelperMessage = function (property, layerType, isFunction) { return 'testBool' + fnSuffix; case 'number': return 'testNumber' + fnSuffix; + case 'formatted': case 'string': return 'testString' + fnSuffix; case 'enum': @@ -385,6 +388,7 @@ global.describeType = function (property) { return 'Boolean'; case 'number': return 'numeric'; + case 'formatted': case 'string': return 'string'; case 'enum': @@ -428,6 +432,7 @@ global.describeValue = function (value, property, layerType) { return value ? '`YES`' : '`NO`'; case 'number': return 'the float ' + '`' + formatNumber(value) + '`'; + case 'formatted': case 'string': if (value === '') { return 'the empty string'; @@ -509,6 +514,7 @@ global.propertyType = function (property) { return 'NSNumber *'; case 'number': return 'NSNumber *'; + case 'formatted': case 'string': return 'NSString *'; case 'enum': @@ -539,7 +545,8 @@ global.isInterpolatable = function (property) { const type = property.type === 'array' ? property.value : property.type; return type !== 'boolean' && type !== 'enum' && - type !== 'string'; + type !== 'string' && + type !== 'formatted'; }; global.valueTransformerArguments = function (property) { @@ -549,6 +556,7 @@ global.valueTransformerArguments = function (property) { return ['bool', objCType]; case 'number': return ['float', objCType]; + case 'formatted': case 'string': return ['std::string', objCType]; case 'enum': @@ -582,6 +590,7 @@ global.mbglType = function(property) { return 'bool'; case 'number': return 'float'; + case 'formatted': case 'string': return 'std::string'; case 'enum': { diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json index 18e9e11c49..2d46317a95 100644 --- a/platform/node/test/ignores.json +++ b/platform/node/test/ignores.json @@ -1,5 +1,9 @@ { "expression-tests/collator/accent-equals-de": "Locale-specific behavior changes based on platform.", + "expression-tests/formatted/basic": "skip - https://github.com/mapbox/mapbox-gl-native/pull/12624", + "expression-tests/formatted/to-string": "skip - https://github.com/mapbox/mapbox-gl-native/pull/12624", + "expression-tests/interpolate-hcl/linear": "https://github.com/mapbox/mapbox-gl-native/issues/8720", + "expression-tests/interpolate-lab/linear": "https://github.com/mapbox/mapbox-gl-native/issues/8720", "expression-tests/is-supported-script/default": "This tests RTL text plugin behavior specific to GL JS", "expression-tests/resolved-locale/basic": "Even the 'en' locale may not be present on some test systems.", "query-tests/geometry/multilinestring": "needs investigation", @@ -9,12 +13,16 @@ "query-tests/world-wrapping/point": "skip - needs issue", "query-tests/circle-radius/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue", "query-tests/circle-stroke-width/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue", + "query-tests/fill-extrusion-translate/multiple-layers": "https://github.com/mapbox/mapbox-gl-native/issues/12701", + "query-tests/fill-translate/multiple-layers": "https://github.com/mapbox/mapbox-gl-native/issues/12701", "query-tests/line-gap-width/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue", "query-tests/line-offset/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue", "query-tests/line-width/feature-state": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue", "query-tests/feature-state/default": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue", "query-tests/regressions/mapbox-gl-js#6555": "skip - no querySourceFeatures in mbgl-node; needs issue", "render-tests/background-color/transition": "https://github.com/mapbox/mapbox-gl-native/issues/10619", + "render-tests/basic-v9/z0-wide": "https://github.com/mapbox/mapbox-gl-native/pull/12611", + "render-tests/bright-v9/z0-wide": "https://github.com/mapbox/mapbox-gl-native/pull/12611", "render-tests/collator/resolved-locale": "Some test platforms don't resolve 'en' locale", "render-tests/collator/default": "Some test platforms don't resolve 'en' locale", "render-tests/debug/collision": "https://github.com/mapbox/mapbox-gl-native/issues/3841", @@ -56,9 +64,13 @@ "render-tests/runtime-styling/image-add-sdf": "https://github.com/mapbox/mapbox-gl-native/issues/9847", "render-tests/runtime-styling/paint-property-fill-flat-to-extrude": "https://github.com/mapbox/mapbox-gl-native/issues/6745", "render-tests/runtime-styling/set-style-paint-property-fill-flat-to-extrude": "https://github.com/mapbox/mapbox-gl-native/issues/6745", + "render-tests/satellite-v9/z0-wide": "https://github.com/mapbox/mapbox-gl-native/pull/12611", "render-tests/symbol-cross-fade/chinese": "https://github.com/mapbox/mapbox-gl-native/issues/10619", "render-tests/symbol-placement/line-overscaled": "https://github.com/mapbox/mapbox-gl-js/issues/5654", "render-tests/symbol-visibility/visible": "https://github.com/mapbox/mapbox-gl-native/issues/10409", + "render-tests/text-field/formatted-arabic": "skip - https://github.com/mapbox/mapbox-gl-native/pull/12624", + "render-tests/text-field/formatted-line": "skip - https://github.com/mapbox/mapbox-gl-native/pull/12624", + "render-tests/text-field/formatted": "skip - https://github.com/mapbox/mapbox-gl-native/pull/12624", "render-tests/text-no-cross-source-collision/default": "skip - gl-js only", "render-tests/text-pitch-alignment/auto-text-rotation-alignment-map": "https://github.com/mapbox/mapbox-gl-native/issues/9732", "render-tests/text-pitch-alignment/map-text-rotation-alignment-map": "https://github.com/mapbox/mapbox-gl-native/issues/9732", diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js index 9a7b2842f7..236df0a921 100755 --- a/scripts/generate-style-code.js +++ b/scripts/generate-style-code.js @@ -37,6 +37,7 @@ global.evaluatedType = function (property) { return 'bool'; case 'number': return 'float'; + case 'formatted': case 'string': return 'std::string'; case 'enum': @@ -120,6 +121,7 @@ global.defaultValue = function (property) { switch (property.type) { case 'number': return property.default; + case 'formatted': case 'string': return JSON.stringify(property.default || ""); case 'enum': -- cgit v1.2.1 From 49cf31d2b8918fbfaf5becb6c068b44af29a2276 Mon Sep 17 00:00:00 2001 From: Molly Lloyd Date: Tue, 21 Aug 2018 16:28:57 -0700 Subject: [core] add exception for unimplemented expressions in tests --- test/style/expression/expression.test.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test/style/expression/expression.test.cpp b/test/style/expression/expression.test.cpp index 982a769b93..4c2ec5cf92 100644 --- a/test/style/expression/expression.test.cpp +++ b/test/style/expression/expression.test.cpp @@ -29,7 +29,11 @@ TEST(Expression, IsExpression) { for(auto& entry : allExpressions.GetObject()) { const std::string name { entry.name.GetString(), entry.name.GetStringLength() }; - if (name == "line-progress" || name == "feature-state") { + if (name == "line-progress" || + name == "feature-state" || + name == "interpolate-hcl" || + name == "interpolate-lab" || + name == "format") { // Not yet implemented continue; } -- cgit v1.2.1 From 67f6891ea7ebe0360458c13ff20fa83648a3bc66 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 22 Aug 2018 07:37:12 +0200 Subject: [android] - GeoJsonOptions javadoc correction on minZoom level and default values --- .../java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java index 79cde7429c..6961027338 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java @@ -11,9 +11,9 @@ import java.util.HashMap; public class GeoJsonOptions extends HashMap { /** - * Maximum zoom level at which to create vector tiles (higher means greater detail at high zoom levels). + * Minimum zoom level at which to create vector tiles (lower means more field of view detail at low zoom levels). * - * @param minZoom the maximum zoom - Defaults to 18. + * @param minZoom the minimum zoom - Defaults to 0. * @return the current instance for chaining */ public GeoJsonOptions withMinZoom(int minZoom) { @@ -24,7 +24,7 @@ public class GeoJsonOptions extends HashMap { /** * Maximum zoom level at which to create vector tiles (higher means greater detail at high zoom levels). * - * @param maxZoom the maximum zoom - Defaults to 18. + * @param maxZoom the maximum zoom - Defaults to 25.5 * @return the current instance for chaining */ public GeoJsonOptions withMaxZoom(int maxZoom) { -- cgit v1.2.1 From 87f73bb0a2ec0bc2d9830c17a754dde66b0f113a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Paczos?= Date: Mon, 20 Aug 2018 19:38:16 +0200 Subject: [android] "collator" and "resolved-locale" expressions support --- .../mapboxsdk/style/expressions/Expression.java | 596 +++++++++++++++++++-- .../style/expressions/ExpressionTest.java | 77 +++ .../mapboxsdk/testapp/style/ExpressionTest.java | 63 ++- 3 files changed, 701 insertions(+), 35 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java index 1aa0ce9093..bd4d5d7d4b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java @@ -4,17 +4,22 @@ import android.support.annotation.ColorInt; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.support.annotation.Size; + import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonNull; +import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import com.mapbox.mapboxsdk.style.layers.PropertyFactory; import com.mapbox.mapboxsdk.style.layers.PropertyValue; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Locale; +import java.util.Map; /** * The value for any layout property, paint property, or filter may be specified as an expression. @@ -345,7 +350,8 @@ public class Expression { * @return expression * @see Style specification */ - public static Expression rgba(@NonNull Number red, @NonNull Number green, @NonNull Number blue, @NonNull Number alpha) { + public static Expression rgba(@NonNull Number red, @NonNull Number green, @NonNull Number blue, @NonNull Number + alpha) { return rgba(literal(red), literal(green), literal(blue), literal(alpha)); } @@ -384,6 +390,32 @@ public class Expression { return new Expression("==", compareOne, compareTwo); } + /** + * Returns true if the input values are equal, false otherwise. + * The inputs must be numbers, strings, or booleans, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     eq(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second expression + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression eq(@NonNull Expression compareOne, @NonNull Expression compareTwo, + @NonNull Expression collator) { + return new Expression("==", compareOne, compareTwo, collator); + } + /** * Returns true if the input values are equal, false otherwise. *

@@ -430,6 +462,32 @@ public class Expression { return eq(compareOne, literal(compareTwo)); } + /** + * Returns true if the input values are equal, false otherwise. + * The inputs must be numbers, strings, or booleans, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     eq(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second String + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression eq(@NonNull Expression compareOne, @NonNull String compareTwo, + @NonNull Expression collator) { + return eq(compareOne, literal(compareTwo), collator); + } + /** * Returns true if the input values are equal, false otherwise. *

@@ -477,6 +535,32 @@ public class Expression { return new Expression("!=", compareOne, compareTwo); } + /** + * Returns true if the input values are not equal, false otherwise. + * The inputs must be numbers, strings, or booleans, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     neq(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second expression + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression neq(@NonNull Expression compareOne, @NonNull Expression compareTwo, + @NonNull Expression collator) { + return new Expression("!=", compareOne, compareTwo, collator); + } + /** * Returns true if the input values are equal, false otherwise. *

@@ -523,6 +607,32 @@ public class Expression { return new Expression("!=", compareOne, literal(compareTwo)); } + /** + * Returns true if the input values are not equal, false otherwise. + * The inputs must be numbers, strings, or booleans, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     neq(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second String + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression neq(@NonNull Expression compareOne, @NonNull String compareTwo, + @NonNull Expression collator) { + return new Expression("!=", compareOne, literal(compareTwo), collator); + } + /** * Returns `true` if the input values are not equal, `false` otherwise. *

@@ -570,6 +680,32 @@ public class Expression { return new Expression(">", compareOne, compareTwo); } + /** + * Returns true if the first input is strictly greater than the second, false otherwise. + * The inputs must be numbers or strings, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     gt(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second expression + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression gt(@NonNull Expression compareOne, @NonNull Expression compareTwo, + @NonNull Expression collator) { + return new Expression(">", compareOne, compareTwo, collator); + } + /** * Returns true if the first input is strictly greater than the second, false otherwise. *

@@ -616,6 +752,32 @@ public class Expression { return new Expression(">", compareOne, literal(compareTwo)); } + /** + * Returns true if the first input is strictly greater than the second, false otherwise. + * The inputs must be numbers or strings, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     gt(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second String + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression gt(@NonNull Expression compareOne, @NonNull String compareTwo, + @NonNull Expression collator) { + return new Expression(">", compareOne, literal(compareTwo), collator); + } + /** * Returns true if the first input is strictly less than the second, false otherwise. * The inputs must be numbers or strings, and both of the same type. @@ -626,13 +788,13 @@ public class Expression { * {@code * FillLayer fillLayer = new FillLayer("layer-id", "source-id"); * fillLayer.setFilter( - * lt(get("keyToValue"), get("keyToOtherValue")) + * lt(get("keyToValue"), get("keyToOtherValue"), collator(true, false)) * ); * } * * * @param compareOne the first expression - * @param compareTwo the second number + * @param compareTwo the second expression * @return expression * @see Style specification */ @@ -640,6 +802,32 @@ public class Expression { return new Expression("<", compareOne, compareTwo); } + /** + * Returns true if the first input is strictly less than the second, false otherwise. + * The inputs must be numbers or strings, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     lt(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second number + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression lt(@NonNull Expression compareOne, @NonNull Expression compareTwo, + @NonNull Expression collator) { + return new Expression("<", compareOne, compareTwo, collator); + } + /** * Returns true if the first input is strictly less than the second, false otherwise. *

@@ -686,6 +874,32 @@ public class Expression { return new Expression("<", compareOne, literal(compareTwo)); } + /** + * Returns true if the first input is strictly less than the second, false otherwise. + * The inputs must be numbers or strings, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     lt(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second String + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression lt(@NonNull Expression compareOne, @NonNull String compareTwo, + @NonNull Expression collator) { + return new Expression("<", compareOne, literal(compareTwo), collator); + } + /** * Returns true if the first input is greater than or equal to the second, false otherwise. * The inputs must be numbers or strings, and both of the same type. @@ -710,6 +924,32 @@ public class Expression { return new Expression(">=", compareOne, compareTwo); } + /** + * Returns true if the first input is greater than or equal to the second, false otherwise. + * The inputs must be numbers or strings, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     gte(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second expression + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression gte(@NonNull Expression compareOne, @NonNull Expression compareTwo, + @NonNull Expression collator) { + return new Expression(">=", compareOne, compareTwo, collator); + } + /** * Returns true if the first input is greater than or equal to the second, false otherwise. *

@@ -756,6 +996,32 @@ public class Expression { return new Expression(">=", compareOne, literal(compareTwo)); } + /** + * Returns true if the first input is greater than or equal to the second, false otherwise. + * The inputs must be numbers or strings, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     gte(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second String + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression gte(@NonNull Expression compareOne, @NonNull String compareTwo, + @NonNull Expression collator) { + return new Expression(">=", compareOne, literal(compareTwo), collator); + } + /** * Returns true if the first input is less than or equal to the second, false otherwise. * The inputs must be numbers or strings, and both of the same type. @@ -780,6 +1046,32 @@ public class Expression { return new Expression("<=", compareOne, compareTwo); } + /** + * Returns true if the first input is less than or equal to the second, false otherwise. + * The inputs must be numbers or strings, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     lte(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second expression + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression lte(@NonNull Expression compareOne, @NonNull Expression compareTwo, + @NonNull Expression collator) { + return new Expression("<=", compareOne, compareTwo, collator); + } + /** * Returns true if the first input is less than or equal to the second, false otherwise. *

@@ -826,6 +1118,32 @@ public class Expression { return new Expression("<=", compareOne, literal(compareTwo)); } + /** + * Returns true if the first input is less than or equal to the second, false otherwise. + * The inputs must be numbers or strings, and both of the same type. + *

+ * Example usage: + *

+ *
+   * {@code
+   * FillLayer fillLayer = new FillLayer("layer-id", "source-id");
+   * fillLayer.setFilter(
+   *     lte(get("keyToValue"), get("keyToOtherValue"), collator(true, false))
+   * );
+   * }
+   * 
+ * + * @param compareOne the first expression + * @param compareTwo the second String + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression lte(@NonNull Expression compareOne, @NonNull String compareTwo, + @NonNull Expression collator) { + return new Expression("<=", compareOne, literal(compareTwo), collator); + } + /** * Returns `true` if all the inputs are `true`, `false` otherwise. *

@@ -2478,6 +2796,32 @@ public class Expression { return floor(literal(number)); } + /** + * Returns the IETF language tag of the locale being used by the provided collator. + * This can be used to determine the default system locale, + * or to determine if a requested locale was successfully loaded. + *

+ * Example usage: + *

+ *
+   * {@code
+   * CircleLayer circleLayer = new CircleLayer("layer-id", "source-id");
+   * circleLayer.setProperties(
+   * circleColor(switchCase(
+     eq(literal("it"), resolvedLocale(collator(true, true, "it"))), literal(ColorUtils.colorToRgbaString(Color.GREEN)),
+          literal(ColorUtils.colorToRgbaString(Color.RED))))
+   * );
+   * }
+   * 
+ * + * @param collator the collator expression + * @return expression + * @see Style specification + */ + public static Expression resolvedLocale(Expression collator) { + return new Expression("resolved-locale", collator); + } + /** * Returns the input string converted to uppercase. *

@@ -2696,6 +3040,104 @@ public class Expression { return new Expression("boolean", input); } + /** + * Returns a collator for use in locale-dependent comparison operations. + * The case-sensitive and diacritic-sensitive options default to false. + * The locale argument specifies the IETF language tag of the locale to use. + * If none is provided, the default locale is used. If the requested locale is not available, + * the collator will use a system-defined fallback locale. + * Use resolved-locale to test the results of locale fallback behavior. + * + * @param caseSensitive case sensitive flag + * @param diacriticSensitive diacritic sensitive flag + * @param locale locale + * @return expression + * @see Style specification + */ + public static Expression collator(boolean caseSensitive, boolean diacriticSensitive, Locale locale) { + Map map = new HashMap<>(); + map.put("case-sensitive", literal(caseSensitive)); + map.put("diacritic-sensitive", literal(diacriticSensitive)); + + StringBuilder localeStringBuilder = new StringBuilder(); + + String language = locale.getLanguage(); + if (language != null && !language.isEmpty()) { + localeStringBuilder.append(language); + } + + String country = locale.getCountry(); + if (country != null && !country.isEmpty()) { + localeStringBuilder.append("-"); + localeStringBuilder.append(country); + } + + map.put("locale", literal(localeStringBuilder.toString())); + return new Expression("collator", new ExpressionMap(map)); + } + + /** + * Returns a collator for use in locale-dependent comparison operations. + * The case-sensitive and diacritic-sensitive options default to false. + * The locale argument specifies the IETF language tag of the locale to use. + * If none is provided, the default locale is used. If the requested locale is not available, + * the collator will use a system-defined fallback locale. + * Use resolved-locale to test the results of locale fallback behavior. + * + * @param caseSensitive case sensitive flag + * @param diacriticSensitive diacritic sensitive flag + * @return expression + * @see Style specification + */ + public static Expression collator(boolean caseSensitive, boolean diacriticSensitive) { + Map map = new HashMap<>(); + map.put("case-sensitive", literal(caseSensitive)); + map.put("diacritic-sensitive", literal(diacriticSensitive)); + return new Expression("collator", new ExpressionMap(map)); + } + + /** + * Returns a collator for use in locale-dependent comparison operations. + * The case-sensitive and diacritic-sensitive options default to false. + * The locale argument specifies the IETF language tag of the locale to use. + * If none is provided, the default locale is used. If the requested locale is not available, + * the collator will use a system-defined fallback locale. + * Use resolved-locale to test the results of locale fallback behavior. + * + * @param caseSensitive case sensitive flag + * @param diacriticSensitive diacritic sensitive flag + * @param locale locale + * @return expression + * @see Style specification + */ + public static Expression collator(Expression caseSensitive, Expression diacriticSensitive, Expression locale) { + Map map = new HashMap<>(); + map.put("case-sensitive", caseSensitive); + map.put("diacritic-sensitive", diacriticSensitive); + map.put("locale", locale); + return new Expression("collator", new ExpressionMap(map)); + } + + /** + * Returns a collator for use in locale-dependent comparison operations. + * The case-sensitive and diacritic-sensitive options default to false. + * The locale argument specifies the IETF language tag of the locale to use. + * If none is provided, the default locale is used. If the requested locale is not available, + * the collator will use a system-defined fallback locale. + * Use resolved-locale to test the results of locale fallback behavior. + * + * @param caseSensitive case sensitive flag + * @param diacriticSensitive diacritic sensitive flag + * @return expression + * @see Style specification + */ + public static Expression collator(Expression caseSensitive, Expression diacriticSensitive) { + Map map = new HashMap<>(); + map.put("case-sensitive", caseSensitive); + map.put("diacritic-sensitive", diacriticSensitive); + return new Expression("collator", new ExpressionMap(map)); + } + /** * Asserts that the input value is an object. If it is not, the expression is an error * The asserted input value is returned as result. @@ -3422,8 +3864,8 @@ public class Expression { array.add(operator); if (arguments != null) { for (Expression argument : arguments) { - if (argument instanceof Expression.ExpressionLiteral) { - array.add(toValue((ExpressionLiteral) argument)); + if (argument instanceof ValueExpression) { + array.add(((ValueExpression) argument).toValue()); } else { array.add(argument.toArray()); } @@ -3432,22 +3874,6 @@ public class Expression { return array.toArray(); } - /** - * Converts the expression value to an Object. - * - * @param expressionValue the expression value to convert - * @return the converted object expression - */ - private Object toValue(ExpressionLiteral expressionValue) { - Object value = expressionValue.toValue(); - if (value instanceof PropertyValue) { - throw new IllegalArgumentException("PropertyValue are not allowed as an expression literal, use value instead."); - } else if (value instanceof Expression.ExpressionLiteral) { - return toValue((ExpressionLiteral) value); - } - return value; - } - /** * Returns a string representation of the object that matches the definition set in the style specification. *

@@ -3549,7 +3975,7 @@ public class Expression { * {@link #literal(String)} and {@link #literal(Object)}. *

*/ - public static class ExpressionLiteral extends Expression { + public static class ExpressionLiteral extends Expression implements ValueExpression { protected Object literal; @@ -3572,7 +3998,14 @@ public class Expression { * * @return the literal object */ - Object toValue() { + @Override + public Object toValue() { + if (literal instanceof PropertyValue) { + throw new IllegalArgumentException( + "PropertyValue are not allowed as an expression literal, use value instead."); + } else if (literal instanceof Expression.ExpressionLiteral) { + return ((ExpressionLiteral) literal).toValue(); + } return literal; } @@ -3589,7 +4022,13 @@ public class Expression { */ @Override public String toString() { - return literal.toString(); + String string; + if (literal instanceof String) { + string = "\"" + literal + "\""; + } else { + string = literal.toString(); + } + return string; } /** @@ -3627,7 +4066,7 @@ public class Expression { return result; } - private String unwrapStringLiteral(String value) { + private static String unwrapStringLiteral(String value) { if (value.length() > 1 && value.charAt(0) == '\"' && value.charAt(value.length() - 1) == '\"') { return value.substring(1, value.length() - 1); @@ -3727,19 +4166,35 @@ public class Expression { JsonElement jsonElement; for (int i = 1; i < jsonArray.size(); i++) { jsonElement = jsonArray.get(i); - if (jsonElement instanceof JsonArray) { - arguments.add(convert((JsonArray) jsonElement)); - } else if (jsonElement instanceof JsonPrimitive) { - arguments.add(convert((JsonPrimitive) jsonElement)); - } else if (jsonElement instanceof JsonNull) { - arguments.add(new Expression.ExpressionLiteral("")); - } else { - throw new RuntimeException("Unsupported expression conversion for " + jsonElement.getClass()); - } + arguments.add(convert(jsonElement)); } return new Expression(operator, arguments.toArray(new Expression[arguments.size()])); } + /** + * Converts a JsonElement to an expression + * + * @param jsonElement the json element to convert + * @return the expression + */ + private static Expression convert(@NonNull JsonElement jsonElement) { + if (jsonElement instanceof JsonArray) { + return convert((JsonArray) jsonElement); + } else if (jsonElement instanceof JsonPrimitive) { + return convert((JsonPrimitive) jsonElement); + } else if (jsonElement instanceof JsonNull) { + return new Expression.ExpressionLiteral(""); + } else if (jsonElement instanceof JsonObject) { + Map map = new HashMap<>(); + for (String key : ((JsonObject) jsonElement).keySet()) { + map.put(key, convert(((JsonObject) jsonElement).get(key))); + } + return new ExpressionMap(map); + } else { + throw new RuntimeException("Unsupported expression conversion for " + jsonElement.getClass()); + } + } + /** * Converts a JsonPrimitive to an expression literal * @@ -3815,6 +4270,79 @@ public class Expression { } } + /** + * Wraps an expression value stored in a Map. + */ + private static class ExpressionMap extends Expression implements ValueExpression { + private Map map; + + ExpressionMap(Map map) { + this.map = map; + } + + @Override + public Object toValue() { + Map unwrappedMap = new HashMap<>(); + for (String key : map.keySet()) { + Expression expression = map.get(key); + if (expression instanceof Expression.ExpressionLiteral) { + unwrappedMap.put(key, ((ExpressionLiteral) expression).toValue()); + } else { + unwrappedMap.put(key, expression.toArray()); + } + } + + return unwrappedMap; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("{"); + for (String key : map.keySet()) { + builder.append("\"").append(key).append("\": "); + builder.append(map.get(key)); + builder.append(", "); + } + + if (map.size() > 0) { + builder.delete(builder.length() - 2, builder.length()); + } + + builder.append("}"); + return builder.toString(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + if (!super.equals(o)) { + return false; + } + ExpressionMap that = (ExpressionMap) o; + return map.equals(that.map); + } + + @Override + public int hashCode() { + int result = super.hashCode(); + result = 31 * result + (map == null ? 0 : map.hashCode()); + return result; + } + } + + /** + * Interface used to describe expressions that hold a Java value. + */ + private interface ValueExpression { + Object toValue(); + } + /** * Converts an object that is a primitive array to an Object[] * diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java index fb74904f96..79bcdd7b5e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/expressions/ExpressionTest.java @@ -1,12 +1,16 @@ package com.mapbox.mapboxsdk.style.expressions; import android.graphics.Color; + import com.mapbox.mapboxsdk.style.layers.PropertyFactory; + import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import java.util.Arrays; +import java.util.HashMap; +import java.util.Locale; import static com.mapbox.mapboxsdk.style.expressions.Expression.abs; import static com.mapbox.mapboxsdk.style.expressions.Expression.acos; @@ -19,6 +23,7 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.atan; import static com.mapbox.mapboxsdk.style.expressions.Expression.bool; import static com.mapbox.mapboxsdk.style.expressions.Expression.ceil; import static com.mapbox.mapboxsdk.style.expressions.Expression.coalesce; +import static com.mapbox.mapboxsdk.style.expressions.Expression.collator; import static com.mapbox.mapboxsdk.style.expressions.Expression.color; import static com.mapbox.mapboxsdk.style.expressions.Expression.concat; import static com.mapbox.mapboxsdk.style.expressions.Expression.cos; @@ -60,6 +65,7 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.pow; import static com.mapbox.mapboxsdk.style.expressions.Expression.product; import static com.mapbox.mapboxsdk.style.expressions.Expression.properties; import static com.mapbox.mapboxsdk.style.expressions.Expression.raw; +import static com.mapbox.mapboxsdk.style.expressions.Expression.resolvedLocale; import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb; import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba; import static com.mapbox.mapboxsdk.style.expressions.Expression.round; @@ -1290,4 +1296,75 @@ public class ExpressionTest { String alpha = color.substring(0, color.length() - 1); assertEquals("alpha value should match", 0.254f, Float.valueOf(alpha), 0.001f); } + + @Test + public void testCollator() { + Object[] expected = new Object[] {"collator", + new HashMap() { + { + put("case-sensitive", true); + put("diacritic-sensitive", true); + put("locale", "it-IT"); + } + } + }; + Object[] actual = collator(true, true, Locale.ITALY).toArray(); + assertTrue("expression should match", Arrays.deepEquals(expected, actual)); + } + + @Test + public void testStringCollator() { + String expected = "[\"collator\", {\"diacritic-sensitive\": true, \"case-sensitive\": true, \"locale\": " + + "\"it\"}]"; + String actual = collator(true, true, Locale.ITALIAN).toString(); + assertEquals("expression should match", expected, actual); + } + + @Test + public void testResolvedLocale() { + Object[] expected = new Object[] {"resolved-locale", + new Object[] {"collator", + new HashMap() { + { + put("case-sensitive", false); + put("diacritic-sensitive", false); + put("locale", "it"); + } + } + } + }; + Object[] actual = resolvedLocale(collator(false, false, Locale.ITALIAN)).toArray(); + assertTrue("expression should match", Arrays.deepEquals(expected, actual)); + } + + @Test + public void testRawCollator() { + Object[] expected = new Object[] {"collator", + new HashMap() { + { + put("case-sensitive", true); + put("diacritic-sensitive", true); + put("locale", "it-IT"); + } + } + }; + Object[] actual = raw("[\"collator\", {\"diacritic-sensitive\": true, \"case-sensitive\": true, \"locale\": " + + "\"it-IT\"}]").toArray(); + assertTrue("expression should match", Arrays.deepEquals(expected, actual)); + } + + @Test + public void testRawCollatorDoubleConversion() { + Expression expected = collator(false, false, Locale.ITALIAN); + Object[] actual = raw(expected.toString()).toArray(); + assertTrue("expression should match", Arrays.deepEquals(expected.toArray(), actual)); + } + + @Test + public void testStringNestedCollator() { + String expected = "[\"collator\", {\"diacritic-sensitive\": [\"==\", 2.0, 1.0], \"case-sensitive\": false," + + " \"locale\": \"it\"}]"; + String actual = collator(literal(false), eq(literal(2), literal(1)), literal("it")).toString(); + assertEquals("expression should match", expected, actual); + } } \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java index f1f260c919..4e284cdc14 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/ExpressionTest.java @@ -2,20 +2,30 @@ package com.mapbox.mapboxsdk.testapp.style; import android.graphics.Color; import android.support.test.runner.AndroidJUnit4; + +import com.mapbox.geojson.Point; +import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.style.expressions.Expression; +import com.mapbox.mapboxsdk.style.layers.CircleLayer; import com.mapbox.mapboxsdk.style.layers.FillLayer; +import com.mapbox.mapboxsdk.style.layers.Layer; import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; import com.mapbox.mapboxsdk.style.sources.Source; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.testapp.activity.BaseActivityTest; import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity; import com.mapbox.mapboxsdk.testapp.utils.ResourceUtils; +import com.mapbox.mapboxsdk.utils.ColorUtils; + import org.junit.Test; import org.junit.runner.RunWith; -import timber.log.Timber; import java.io.IOException; +import timber.log.Timber; + +import static com.mapbox.mapboxsdk.style.expressions.Expression.collator; +import static com.mapbox.mapboxsdk.style.expressions.Expression.eq; import static com.mapbox.mapboxsdk.style.expressions.Expression.exponential; import static com.mapbox.mapboxsdk.style.expressions.Expression.get; import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate; @@ -26,13 +36,16 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.rgba; import static com.mapbox.mapboxsdk.style.expressions.Expression.step; import static com.mapbox.mapboxsdk.style.expressions.Expression.stop; import static com.mapbox.mapboxsdk.style.expressions.Expression.string; +import static com.mapbox.mapboxsdk.style.expressions.Expression.switchCase; import static com.mapbox.mapboxsdk.style.expressions.Expression.toColor; import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom; +import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.circleColor; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillAntialias; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillColor; import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.fillOutlineColor; import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; @RunWith(AndroidJUnit4.class) public class ExpressionTest extends BaseActivityTest { @@ -204,6 +217,54 @@ public class ExpressionTest extends BaseActivityTest { }); } + @Test + public void testCollatorExpression() { + validateTestSetup(); + setupStyle(); + invoke(mapboxMap, (uiController, mapboxMap) -> { + LatLng latLng = new LatLng(51, 17); + + Expression expression1 = eq(literal("Łukasz"), literal("lukasz"), collator(true, true)); + Expression expression2 = eq(literal("Łukasz"), literal("lukasz"), collator(literal(false), eq(literal(1), + literal(1)), literal("en"))); + Expression expression3 = eq(literal("Łukasz"), literal("lukasz"), collator(literal(false), eq(literal(2), + literal(1)))); + + mapboxMap.addSource(new GeoJsonSource("source", Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()))); + Layer layer = new CircleLayer("layer", "source") + .withProperties(circleColor( + switchCase( + expression1, literal(ColorUtils.colorToRgbaString(Color.GREEN)), + literal(ColorUtils.colorToRgbaString(Color.RED)) + ) + )); + mapboxMap.addLayer(layer); + uiController.loopMainThreadForAtLeast(1000); + assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") + .isEmpty()); + + layer.setProperties(circleColor( + switchCase( + expression2, literal(ColorUtils.colorToRgbaString(Color.GREEN)), + literal(ColorUtils.colorToRgbaString(Color.RED)) + ) + )); + uiController.loopMainThreadForAtLeast(1000); + assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") + .isEmpty()); + + layer.setProperties(circleColor( + switchCase( + expression3, literal(ColorUtils.colorToRgbaString(Color.GREEN)), + literal(ColorUtils.colorToRgbaString(Color.RED)) + ) + )); + uiController.loopMainThreadForAtLeast(1000); + assertFalse(mapboxMap.queryRenderedFeatures(mapboxMap.getProjection().toScreenLocation(latLng), "layer") + .isEmpty()); + }); + } + private void setupStyle() { invoke(mapboxMap, (uiController, mapboxMap) -> { // Add a source -- cgit v1.2.1 From 1662be7ea546ac78654396e700b9ed7107407904 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 22 Aug 2018 06:23:11 +0200 Subject: [android] - update user agent telemetry --- platform/android/MapboxGLAndroidSDK/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index 5a505af959..597eddc334 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -31,7 +31,7 @@ android { buildConfigField "String", "MAPBOX_SDK_IDENTIFIER", String.format("\"%s\"", "mapbox-maps-android") buildConfigField "String", "MAPBOX_SDK_VERSION", String.format("\"%s\"", project.VERSION_NAME) buildConfigField "String", "MAPBOX_VERSION_STRING", String.format("\"Mapbox/%s\"", project.VERSION_NAME) - buildConfigField "String", "MAPBOX_EVENTS_USER_AGENT", String.format("\"MapboxEventsAndroid/%s\"", project.VERSION_NAME) + buildConfigField "String", "MAPBOX_EVENTS_USER_AGENT", String.format("\"mapbox-maps-android/%s\"", project.VERSION_NAME) } defaultPublishConfig project.hasProperty("mapbox.buildtype") ? project.getProperty("mapbox.buildtype") : "debug" -- cgit v1.2.1 From 520df7f02049cdbbb9e68041e755d6c3a8d5b21f Mon Sep 17 00:00:00 2001 From: Tobrun Date: Wed, 22 Aug 2018 07:20:59 +0200 Subject: [android] - replace hardcode telemetry settings string by resources string --- .../mapboxsdk/attribution/AttributionParser.java | 24 +++++++++++++++++++--- .../mapboxsdk/maps/AttributionDialogManager.java | 16 ++++++++++++--- .../attribution/AttributionParseTest.java | 14 +++++++++++++ 3 files changed, 48 insertions(+), 6 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java index 90bb23429f..3e75a34b4a 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/attribution/AttributionParser.java @@ -1,10 +1,13 @@ package com.mapbox.mapboxsdk.attribution; +import android.content.Context; import android.text.Html; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.URLSpan; +import com.mapbox.mapboxsdk.R; +import java.lang.ref.WeakReference; import java.util.LinkedHashSet; import java.util.Set; @@ -17,6 +20,7 @@ import java.util.Set; */ public class AttributionParser { + private final WeakReference context; private final Set attributions = new LinkedHashSet<>(); private final String attributionData; private final boolean withImproveMap; @@ -24,8 +28,9 @@ public class AttributionParser { private final boolean withTelemetryAttribution; private final boolean withMapboxAttribution; - AttributionParser(String attributionData, boolean withImproveMap, boolean withCopyrightSign, - boolean withTelemetryAttribution, boolean withMapboxAttribution) { + AttributionParser(WeakReference context, String attributionData, boolean withImproveMap, + boolean withCopyrightSign, boolean withTelemetryAttribution, boolean withMapboxAttribution) { + this.context = context; this.attributionData = attributionData; this.withImproveMap = withImproveMap; this.withCopyrightSign = withCopyrightSign; @@ -167,7 +172,13 @@ public class AttributionParser { */ private void addAdditionalAttributions() { if (withTelemetryAttribution) { - attributions.add(new Attribution(Attribution.TELEMETRY, Attribution.TELEMETRY_URL)); + Context context = this.context.get(); + attributions.add( + new Attribution( + context != null ? context.getString(R.string.mapbox_telemetrySettings) : Attribution.TELEMETRY, + Attribution.TELEMETRY_URL + ) + ); } } @@ -196,6 +207,7 @@ public class AttributionParser { *

*/ public static class Options { + private WeakReference context; private boolean withImproveMap = true; private boolean withCopyrightSign = true; private boolean withTelemetryAttribution = false; @@ -227,6 +239,11 @@ public class AttributionParser { return this; } + public Options withContext(Context context) { + this.context = new WeakReference<>(context); + return this; + } + public AttributionParser build() { if (attributionDataStringArray == null) { throw new IllegalStateException("Using builder without providing attribution data"); @@ -234,6 +251,7 @@ public class AttributionParser { String fullAttributionString = parseAttribution(attributionDataStringArray); AttributionParser attributionParser = new AttributionParser( + context, fullAttributionString, withImproveMap, withCopyrightSign, diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java index 546ee62804..c2114f458e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AttributionDialogManager.java @@ -17,10 +17,12 @@ import com.mapbox.mapboxsdk.attribution.AttributionParser; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.style.sources.Source; +import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; import java.util.List; -import java.util.Locale; import java.util.Set; +import java.util.Locale; /** * Responsible for managing attribution interactions on the map. @@ -47,7 +49,7 @@ public class AttributionDialogManager implements View.OnClickListener, DialogInt // Called when someone presses the attribution icon on the map @Override public void onClick(View view) { - attributionSet = new AttributionBuilder(mapboxMap).build(); + attributionSet = new AttributionBuilder(mapboxMap, view.getContext()).build(); boolean isActivityFinishing = false; if (context instanceof Activity) { @@ -148,12 +150,19 @@ public class AttributionDialogManager implements View.OnClickListener, DialogInt private static class AttributionBuilder { private final MapboxMap mapboxMap; + private final WeakReference context; - AttributionBuilder(MapboxMap mapboxMap) { + AttributionBuilder(MapboxMap mapboxMap, Context context) { this.mapboxMap = mapboxMap; + this.context = new WeakReference<>(context); } private Set build() { + Context context = this.context.get(); + if (context == null) { + return Collections.emptySet(); + } + List attributions = new ArrayList<>(); for (Source source : mapboxMap.getSources()) { attributions.add(source.getAttribution()); @@ -162,6 +171,7 @@ public class AttributionDialogManager implements View.OnClickListener, DialogInt return new AttributionParser.Options() .withCopyrightSign(true) .withImproveMap(true) + .withContext(context) .withTelemetryAttribution(true) .withAttributionData(attributions.toArray(new String[attributions.size()])) .build().getAttributions(); diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/attribution/AttributionParseTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/attribution/AttributionParseTest.java index f25cf1b7d8..7eacda43c3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/attribution/AttributionParseTest.java +++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/attribution/AttributionParseTest.java @@ -4,6 +4,7 @@ import com.mapbox.mapboxsdk.BuildConfig; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import java.util.Set; @@ -21,6 +22,7 @@ public class AttributionParseTest { public void testParseAttributionStringSatellite() throws Exception { AttributionParser attributionParser = new AttributionParser.Options() .withAttributionData(SATELLITE_ATTRIBUTION) + .withContext(RuntimeEnvironment.application) .build(); Set attributionList = attributionParser.getAttributions(); @@ -54,6 +56,7 @@ public class AttributionParseTest { public void testParseAttributionStringStreets() throws Exception { AttributionParser attributionParser = new AttributionParser.Options() .withAttributionData(STREETS_ATTRIBUTION) + .withContext(RuntimeEnvironment.application) .build(); Set attributionList = attributionParser.getAttributions(); @@ -84,6 +87,7 @@ public class AttributionParseTest { AttributionParser attributionParser = new AttributionParser.Options() .withAttributionData(STREETS_ATTRIBUTION) .withMapboxAttribution(false) + .withContext(RuntimeEnvironment.application) .build(); Set attributionList = attributionParser.getAttributions(); @@ -109,6 +113,7 @@ public class AttributionParseTest { public void testParseAttributionArrayString() throws Exception { AttributionParser attributionParser = new AttributionParser.Options() .withAttributionData(new String[] {STREETS_ATTRIBUTION, "", SATELLITE_ATTRIBUTION}) + .withContext(RuntimeEnvironment.application) .build(); Set attributionList = attributionParser.getAttributions(); assertEquals("Size of list should match", 4, attributionList.size()); @@ -142,6 +147,7 @@ public class AttributionParseTest { AttributionParser attributionParser = new AttributionParser.Options() .withAttributionData(SATELLITE_ATTRIBUTION) .withImproveMap(false) + .withContext(RuntimeEnvironment.application) .build(); Set attributionList = attributionParser.getAttributions(); assertEquals("Size of list should match", 3, attributionList.size()); @@ -171,6 +177,7 @@ public class AttributionParseTest { AttributionParser attributionParser = new AttributionParser.Options() .withAttributionData(STREETS_ATTRIBUTION, "", SATELLITE_ATTRIBUTION) .withCopyrightSign(false) + .withContext(RuntimeEnvironment.application) .build(); Set attributionList = attributionParser.getAttributions(); assertEquals("Size of list should match", 4, attributionList.size()); @@ -205,6 +212,7 @@ public class AttributionParseTest { .withAttributionData(STREETS_ATTRIBUTION) .withCopyrightSign(false) .withImproveMap(false) + .withContext(RuntimeEnvironment.application) .build(); assertEquals( @@ -220,6 +228,7 @@ public class AttributionParseTest { AttributionParser attributionParser = new AttributionParser.Options() .withAttributionData(STREETS_ATTRIBUTION) .withImproveMap(false) + .withContext(RuntimeEnvironment.application) .build(); assertEquals( @@ -236,6 +245,7 @@ public class AttributionParseTest { .withCopyrightSign(false) .withImproveMap(false) .withMapboxAttribution(false) + .withContext(RuntimeEnvironment.application) .build(); assertEquals( @@ -251,6 +261,7 @@ public class AttributionParseTest { .withAttributionData(STREETS_ATTRIBUTION) .withImproveMap(false) .withMapboxAttribution(false) + .withContext(RuntimeEnvironment.application) .build(); assertEquals( @@ -267,6 +278,7 @@ public class AttributionParseTest { .withImproveMap(false) .withCopyrightSign(false) .withMapboxAttribution(false) + .withContext(RuntimeEnvironment.application) .build(); assertEquals( @@ -283,6 +295,7 @@ public class AttributionParseTest { .withImproveMap(false) .withCopyrightSign(false) .withMapboxAttribution(false) + .withContext(RuntimeEnvironment.application) .build(); assertEquals( @@ -298,6 +311,7 @@ public class AttributionParseTest { .withAttributionData(STREETS_ATTRIBUTION, SATELLITE_ATTRIBUTION, "blabla", "") .withImproveMap(false) .withCopyrightSign(false) + .withContext(RuntimeEnvironment.application) .build(); assertEquals( -- cgit v1.2.1