summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore4
-rw-r--r--CMakeLists.txt8
-rw-r--r--INSTALL.md61
-rw-r--r--Makefile5
-rw-r--r--README.md6
-rw-r--r--appveyor.yml2
-rw-r--r--benchmark/util/tilecover.benchmark.cpp96
-rw-r--r--circle.yml4
-rw-r--r--cmake/benchmark-files.cmake1
-rw-r--r--cmake/core-files.cmake4
-rw-r--r--cmake/loop-uv.cmake18
-rw-r--r--cmake/node.cmake22
-rw-r--r--include/mbgl/util/projection.hpp16
m---------mapbox-gl-js0
-rw-r--r--misc/ca-bundle.crt133
-rw-r--r--platform/android/CHANGELOG.md5
-rw-r--r--platform/android/MapboxGLAndroidSDK/.gitignore1
-rw-r--r--platform/android/MapboxGLAndroidSDK/build.gradle1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java227
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java1
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/storage/FileSource.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java20
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java218
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java12
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java39
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java41
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java129
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml8
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java283
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java9
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml2
-rw-r--r--platform/android/README.md11
-rw-r--r--platform/android/gradle/dependencies.gradle5
-rw-r--r--platform/android/gradle/gradle-dependencies-graph.gradle29
-rw-r--r--platform/android/scripts/exclude-activity-gen.json2
-rwxr-xr-xplatform/android/scripts/generate-style-code.js18
-rw-r--r--platform/android/src/file_source.cpp10
-rw-r--r--platform/android/src/file_source.hpp2
-rw-r--r--platform/android/src/geojson/point.cpp2
-rwxr-xr-xplatform/darwin/scripts/generate-style-code.js11
-rw-r--r--platform/darwin/src/MGLAttributionInfo.mm6
-rw-r--r--platform/darwin/src/MGLAttributionInfo_Private.h6
-rw-r--r--platform/darwin/src/MGLCompassDirectionFormatter.m4
-rw-r--r--platform/darwin/src/MGLComputedShapeSource.h4
-rw-r--r--platform/darwin/src/MGLComputedShapeSource.mm6
-rw-r--r--platform/darwin/src/MGLComputedShapeSource_Private.h2
-rw-r--r--platform/darwin/src/MGLFeature.h8
-rw-r--r--platform/darwin/src/MGLFeature.mm6
-rw-r--r--platform/darwin/src/MGLFeature_Private.h4
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.h3
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.h5
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.mm2
-rw-r--r--platform/darwin/src/MGLMultiPoint.mm2
-rw-r--r--platform/darwin/src/MGLOfflineStorage.h2
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm8
-rw-r--r--platform/darwin/src/MGLPolygon.h8
-rw-r--r--platform/darwin/src/MGLPolygon.mm8
-rw-r--r--platform/darwin/src/MGLPolygon_Private.h2
-rw-r--r--platform/darwin/src/MGLPolyline.h4
-rw-r--r--platform/darwin/src/MGLPolyline.mm8
-rw-r--r--platform/darwin/src/MGLPolyline_Private.h2
-rw-r--r--platform/darwin/src/MGLRasterTileSource.h2
-rw-r--r--platform/darwin/src/MGLRasterTileSource.mm2
-rw-r--r--platform/darwin/src/MGLShapeCollection.h4
-rw-r--r--platform/darwin/src/MGLShapeCollection.mm4
-rw-r--r--platform/darwin/src/MGLShapeSource.h10
-rw-r--r--platform/darwin/src/MGLShapeSource.mm12
-rw-r--r--platform/darwin/src/MGLShapeSource_Private.h2
-rw-r--r--platform/darwin/src/MGLStyle.h6
-rw-r--r--platform/darwin/src/MGLStyle.mm24
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm.ejs12
-rw-r--r--platform/darwin/src/MGLStyle_Private.h10
-rw-r--r--platform/darwin/src/MGLTileSource.h15
-rw-r--r--platform/darwin/src/MGLTileSource.mm6
-rw-r--r--platform/darwin/src/MGLTileSource_Private.h4
-rw-r--r--platform/darwin/src/MGLTypes.h20
-rw-r--r--platform/darwin/src/MGLVectorTileSource.h4
-rw-r--r--platform/darwin/src/MGLVectorTileSource.mm8
-rw-r--r--platform/darwin/src/MGLVectorTileSource_Private.h2
-rw-r--r--platform/darwin/src/NSBundle+MGLAdditions.h2
-rw-r--r--platform/darwin/src/NSBundle+MGLAdditions.m2
-rw-r--r--platform/darwin/src/NSExpression+MGLAdditions.mm42
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.h3
-rw-r--r--platform/darwin/src/NSString+MGLAdditions.m33
-rw-r--r--platform/darwin/test/MGLAttributionInfoTests.m6
-rw-r--r--platform/darwin/test/MGLBackgroundStyleLayerTests.mm9
-rw-r--r--platform/darwin/test/MGLCircleStyleLayerTests.mm33
-rw-r--r--platform/darwin/test/MGLCoordinateFormatterTests.m21
-rw-r--r--platform/darwin/test/MGLExpressionTests.mm63
-rw-r--r--platform/darwin/test/MGLFeatureTests.mm6
-rw-r--r--platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm21
-rw-r--r--platform/darwin/test/MGLFillStyleLayerTests.mm21
-rw-r--r--platform/darwin/test/MGLHeatmapStyleLayerTests.mm12
-rw-r--r--platform/darwin/test/MGLHillshadeStyleLayerTests.mm18
-rw-r--r--platform/darwin/test/MGLLineStyleLayerTests.mm42
-rw-r--r--platform/darwin/test/MGLNSStringAdditionsTests.m54
-rw-r--r--platform/darwin/test/MGLRasterStyleLayerTests.mm21
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.h2
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.m4
-rw-r--r--platform/darwin/test/MGLStyleLayerTests.mm.ejs14
-rw-r--r--platform/darwin/test/MGLSymbolStyleLayerTests.mm150
-rw-r--r--platform/default/mbgl/storage/offline.cpp2
-rw-r--r--platform/default/mbgl/storage/offline_database.cpp587
-rw-r--r--platform/default/mbgl/storage/offline_database.hpp21
-rw-r--r--platform/default/sqlite3.cpp370
-rw-r--r--platform/default/sqlite3.hpp107
-rw-r--r--platform/ios/CHANGELOG.md6
-rw-r--r--platform/ios/DEVELOPING.md6
-rw-r--r--platform/ios/INSTALL.md29
-rw-r--r--platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK-static-part.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK-symbols.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK.podspec2
-rw-r--r--platform/ios/app/MBXOfflinePacksTableViewController.m6
-rw-r--r--platform/ios/app/MBXViewController.m11
-rw-r--r--platform/ios/benchmark/MBXBenchViewController.mm4
-rw-r--r--platform/ios/docs/doc-README.md2
-rw-r--r--platform/ios/docs/pod-README.md4
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj16
-rw-r--r--platform/ios/src/MGLAnnotationContainerView.h2
-rw-r--r--platform/ios/src/MGLAnnotationContainerView.m4
-rw-r--r--platform/ios/src/MGLAnnotationContainerView_Private.h2
-rw-r--r--platform/ios/src/MGLMapAccessibilityElement.mm6
-rw-r--r--platform/ios/src/MGLMapView.h38
-rw-r--r--platform/ios/src/MGLMapView.mm118
-rw-r--r--platform/ios/src/MGLMapViewDelegate.h2
-rw-r--r--platform/ios/src/MGLScaleBar.mm7
-rw-r--r--platform/ios/src/MGLUserLocation.m2
-rw-r--r--platform/ios/test/MGLMapAccessibilityElementTests.m6
-rw-r--r--platform/linux/README.md20
-rw-r--r--platform/linux/config.cmake27
-rw-r--r--platform/macos/CHANGELOG.md6
-rw-r--r--platform/macos/DEVELOPING.md16
-rw-r--r--platform/macos/INSTALL.md36
-rw-r--r--platform/macos/Mapbox-macOS-SDK-symbols.podspec2
-rw-r--r--platform/macos/Mapbox-macOS-SDK.podspec2
-rw-r--r--platform/macos/app/AppDelegate.m14
-rw-r--r--platform/macos/app/MGLStyle+MBXAdditions.h2
-rw-r--r--platform/macos/app/MGLStyle+MBXAdditions.m6
-rw-r--r--platform/macos/app/MapDocument.m12
-rw-r--r--platform/macos/config.cmake1
-rw-r--r--platform/macos/docs/doc-README.md2
-rw-r--r--platform/macos/docs/pod-README.md4
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj4
-rw-r--r--platform/macos/src/MGLMapView+IBAdditions.mm14
-rw-r--r--platform/macos/src/MGLMapView.h34
-rw-r--r--platform/macos/src/MGLMapView.mm50
-rw-r--r--platform/node/DEVELOPING.md8
-rw-r--r--platform/node/README.md3
-rw-r--r--platform/node/test/ignores.json34
-rw-r--r--platform/qt/README.md11
-rw-r--r--platform/qt/app/mapwindow.cpp7
-rw-r--r--platform/qt/app/mapwindow.hpp1
-rw-r--r--platform/qt/config.qdocconf2
-rw-r--r--platform/qt/include/qmapbox.hpp10
-rw-r--r--platform/qt/include/qmapboxgl.hpp9
-rw-r--r--platform/qt/qt.cmake1
-rw-r--r--platform/qt/src/qmapbox.cpp14
-rw-r--r--platform/qt/src/qmapboxgl.cpp62
-rw-r--r--platform/qt/src/qmapboxgl_map_observer.cpp29
-rw-r--r--platform/qt/src/qmapboxgl_map_observer.hpp1
-rw-r--r--platform/qt/src/sqlite3.cpp294
-rwxr-xr-xscripts/generate-shaders.js2
-rwxr-xr-xscripts/generate-style-code.js42
-rw-r--r--scripts/style-spec.js1
-rw-r--r--src/mbgl/annotation/render_annotation_source.cpp4
-rw-r--r--src/mbgl/annotation/render_annotation_source.hpp2
-rw-r--r--src/mbgl/geometry/feature_index.cpp94
-rw-r--r--src/mbgl/geometry/feature_index.hpp52
-rw-r--r--src/mbgl/layout/symbol_layout.cpp16
-rw-r--r--src/mbgl/layout/symbol_layout.hpp9
-rw-r--r--src/mbgl/map/map.cpp5
-rw-r--r--src/mbgl/map/transform_state.cpp13
-rw-r--r--src/mbgl/map/transform_state.hpp1
-rw-r--r--src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp4
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp6
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp5
-rw-r--r--src/mbgl/renderer/layers/render_background_layer.cpp1
-rw-r--r--src/mbgl/renderer/layers/render_circle_layer.cpp66
-rw-r--r--src/mbgl/renderer/layers/render_circle_layer.hpp3
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp7
-rw-r--r--src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp3
-rw-r--r--src/mbgl/renderer/layers/render_fill_layer.cpp7
-rw-r--r--src/mbgl/renderer/layers/render_fill_layer.hpp3
-rw-r--r--src/mbgl/renderer/layers/render_heatmap_layer.cpp6
-rw-r--r--src/mbgl/renderer/layers/render_heatmap_layer.hpp3
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.cpp7
-rw-r--r--src/mbgl/renderer/layers/render_line_layer.hpp3
-rw-r--r--src/mbgl/renderer/render_layer.hpp5
-rw-r--r--src/mbgl/renderer/render_source.hpp2
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp58
-rw-r--r--src/mbgl/renderer/renderer_impl.hpp8
-rw-r--r--src/mbgl/renderer/sources/render_custom_geometry_source.cpp4
-rw-r--r--src/mbgl/renderer/sources/render_custom_geometry_source.hpp2
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.cpp4
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.hpp2
-rw-r--r--src/mbgl/renderer/sources/render_image_source.cpp2
-rw-r--r--src/mbgl/renderer/sources/render_image_source.hpp2
-rw-r--r--src/mbgl/renderer/sources/render_raster_dem_source.cpp2
-rw-r--r--src/mbgl/renderer/sources/render_raster_dem_source.hpp2
-rw-r--r--src/mbgl/renderer/sources/render_raster_source.cpp2
-rw-r--r--src/mbgl/renderer/sources/render_raster_source.hpp2
-rw-r--r--src/mbgl/renderer/sources/render_vector_source.cpp4
-rw-r--r--src/mbgl/renderer/sources/render_vector_source.hpp2
-rw-r--r--src/mbgl/renderer/tile_pyramid.cpp13
-rw-r--r--src/mbgl/renderer/tile_pyramid.hpp2
-rw-r--r--src/mbgl/shaders/line.cpp3
-rw-r--r--src/mbgl/style/expression/compound_expression.cpp9
-rw-r--r--src/mbgl/text/collision_index.cpp61
-rw-r--r--src/mbgl/text/collision_index.hpp5
-rw-r--r--src/mbgl/text/cross_tile_symbol_index.cpp4
-rw-r--r--src/mbgl/text/placement.cpp45
-rw-r--r--src/mbgl/text/placement.hpp20
-rw-r--r--src/mbgl/tile/geometry_tile.cpp54
-rw-r--r--src/mbgl/tile/geometry_tile.hpp12
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp3
-rw-r--r--src/mbgl/tile/tile.cpp6
-rw-r--r--src/mbgl/tile/tile.hpp9
-rw-r--r--src/mbgl/util/compression.cpp2
-rw-r--r--src/mbgl/util/i18n.cpp37
-rw-r--r--src/mbgl/util/i18n.hpp2
-rw-r--r--src/mbgl/util/intersection_tests.cpp9
-rw-r--r--src/mbgl/util/intersection_tests.hpp1
-rw-r--r--src/mbgl/util/throttler.cpp36
-rw-r--r--src/mbgl/util/throttler.hpp22
-rw-r--r--src/mbgl/util/tile_cover.cpp104
-rw-r--r--src/mbgl/util/tile_cover.hpp24
-rw-r--r--src/mbgl/util/tile_cover_impl.cpp365
-rw-r--r--src/mbgl/util/tile_cover_impl.hpp90
-rw-r--r--src/mbgl/util/tiny_sdf.cpp2
-rw-r--r--test/fixtures/offline_database/satellite_test.dbbin0 -> 114688 bytes
-rw-r--r--test/gl/bucket.test.cpp3
-rw-r--r--test/storage/offline_database.test.cpp81
-rw-r--r--test/storage/sqlite.test.cpp47
-rw-r--r--test/style/expression/expression.test.cpp8
-rw-r--r--test/text/cross_tile_symbol_index.test.cpp24
-rw-r--r--test/util/tile_cover.test.cpp232
-rw-r--r--test/util/tile_range.test.cpp8
254 files changed, 3742 insertions, 2526 deletions
diff --git a/.gitignore b/.gitignore
index 0f4fa77858..b32baaac09 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,6 +17,8 @@ xcuserdata
/test/fixtures/api/2.png
/test/fixtures/offline_database/offline.db
/test/fixtures/offline_database/offline.db-*
+/test/fixtures/offline_database/satellite.db
+/test/fixtures/offline_database/satellite.db-*
/test/fixtures/offline_database/invalid.db
/test/fixtures/offline_database/invalid.db-*
/test/fixtures/offline_database/migrated.db
@@ -38,4 +40,4 @@ test/fixtures/storage/assets.zip
# Generated list files from code generation
/scripts/generate-cmake-files.list
/scripts/generate-shaders.list
-/scripts/generate-style-code.list \ No newline at end of file
+/scripts/generate-style-code.list
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8307191a3f..46aea73356 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -15,13 +15,9 @@ include(cmake/xcode.cmake)
if(WITH_CXX11ABI)
set(MASON_CXXABI_SUFFIX -cxx11abi)
- if(CMAKE_COMPILER_IS_GNUCXX)
- add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1)
- endif()
+ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1)
else()
- if(CMAKE_COMPILER_IS_GNUCXX)
- add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
- endif()
+ add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
endif()
if(WITH_OSMESA AND WITH_EGL)
diff --git a/INSTALL.md b/INSTALL.md
index a28348d15c..463d199d10 100644
--- a/INSTALL.md
+++ b/INSTALL.md
@@ -1,56 +1,15 @@
-# Building & Developing Mapbox GL Native from Source
+# Building & Developing from Source
-**Just trying to use Mapbox GL Native? You don't need to read this stuff! We
+**Just trying to use one of the Mapbox Maps SDKs? You don't need to read this stuff! We
provide [easy-to-install, prebuilt versions of the Mapbox Maps SDKs for iOS and Android
that you can download instantly and get started with fast](https://www.mapbox.com/install/).**
-Still with us? These are the instructions you'll need to build Mapbox GL Native
-from source on a variety of platforms and set up a development environment.
+If you're certain you need to build from source, rather than using a prebuilt SDK, please
+refer to the installation instructions for the platform of interest:
-Your journey will start with installing dependencies, then getting the source code, and
-then setting up a development environment, which varies depending on your
-operating system and what platform you want to develop for.
-
-## 1: Installing dependencies
-
-### macOS
-
- 1. Install [Xcode](https://developer.apple.com/xcode/)
- 2. Launch Xcode and install any updates
- 3. Install [Homebrew](http://brew.sh)
- 4. Install [Node.js](https://nodejs.org/), [CMake](https://cmake.org/), and [ccache](https://ccache.samba.org) with `brew install nodejs cmake ccache`
- 5. Install [xcpretty](https://github.com/supermarin/xcpretty) with `[sudo] gem install xcpretty` (optional, used for prettifying command line builds)
-
-### Linux
-
-Install the following:
-
- - `clang++` 3.5 or later or `g++` 4.9 or later
- - [git](https://git-scm.com/)
- - [CMake](https://cmake.org/) 3.1 or later
- - [cURL](https://curl.haxx.se)
- - [Node.js](https://nodejs.org/) 4.2.1 or later
- - [`libcurl`](http://curl.haxx.se/libcurl/) (depends on OpenSSL)
- - [ccache](https://ccache.samba.org) (optional, improves recompilation performance)
-
-## 2: Getting the source
-
- Clone the git repository:
-
- git clone https://github.com/mapbox/mapbox-gl-native.git
- cd mapbox-gl-native
-
-## 3: Setting up a development environment & building
-
-See the relevant SDK documentation for next steps:
-
-* [Maps SDK for Android](platform/android/)
-* [Maps SDK for iOS](platform/ios/)
-* [Maps SDK for macOS](platform/macos/)
-* [Mapbox Qt SDK](platform/qt/)
-* [Mapbox GL Native on Linux](platform/linux/)
-* [node-mapbox-gl-native](platform/node/)
-
-## 4: Keeping up to date
-
-This repository uses Git submodules, which should be automatically checked out when you first run a `make` command for one of the above platforms. These submodules are not updated automatically and we recommended that you run `git submodule update` after pulling down new commits to this repository.
+* [Mapbox Maps SDK for Android](platform/android/README.md)
+* [Mapbox Maps SDK for iOS](platform/ios/INSTALL.md)
+* [Mapbox Maps SDK for macOS](platform/macos/INSTALL.md)
+* [Mapbox Maps SDK for Qt](platform/qt/README.md)
+* [Mapbox GL Native on Linux](platform/linux/README.md)
+* [node-mapbox-gl-native](platform/node/DEVELOPING.md)
diff --git a/Makefile b/Makefile
index 5c521d674a..576312cabf 100644
--- a/Makefile
+++ b/Makefile
@@ -687,6 +687,11 @@ endif
android-configuration: platform/android/gradle/configuration.gradle
cat platform/android/gradle/configuration.gradle
+# Creates a dependency graph using Graphviz
+.PHONY: android-graph
+android-graph:
+ cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:generateDependencyGraphMapboxLibraries
+
#### Miscellaneous targets #####################################################
.PHONY: style-code
diff --git a/README.md b/README.md
index 2b24d7d567..0d6e731103 100644
--- a/README.md
+++ b/README.md
@@ -13,15 +13,15 @@ This repository hosts the cross-platform Mapbox GL Native library, plus convenie
| [Mapbox Maps SDK for iOS](platform/ios/) | Objective-C or Swift | [![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) |
| [Mapbox Maps SDK for macOS](platform/macos/) | Objective-C, Swift, or AppleScript | [![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) |
| [node-mapbox-gl-native](platform/node/) | Node.js | [![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) |
-| [Mapbox Qt SDK](platform/qt) | C++03 | [![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) [![AppVeyor CI build status](https://ci.appveyor.com/api/projects/status/3q12kbcooc6df8uc?svg=true)](https://ci.appveyor.com/project/Mapbox/mapbox-gl-native) |
+| [Mapbox Maps SDK for Qt](platform/qt) | C++03 | [![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) [![AppVeyor CI build status](https://ci.appveyor.com/api/projects/status/3q12kbcooc6df8uc?svg=true)](https://ci.appveyor.com/project/Mapbox/mapbox-gl-native) |
Additional Mapbox GL Native–based libraries for **hybrid applications** are developed outside of this repository:
| Toolkit | Android | iOS | Developer |
| ---------------------------------------- | --------|-----|------------ |
-| [React Native](https://github.com/mapbox/react-native-mapbox-gl/) ([npm](https://www.npmjs.com/package/react-native-mapbox-gl)) | :white_check_mark: | :white_check_mark: | Mapbox |
+| [React Native](https://github.com/mapbox/react-native-mapbox-gl/) ([npm](https://www.npmjs.com/package/@mapbox/react-native-mapbox-gl)) | :white_check_mark: | :white_check_mark: | Mapbox |
| [Apache Cordova](http://plugins.telerik.com/cordova/plugin/mapbox/) ([npm](https://www.npmjs.com/package/cordova-plugin-mapbox)) | :white_check_mark: | :white_check_mark: | Telerik |
-| [NativeScript](http://plugins.telerik.com/nativescript/plugin/mapbox/) ([npm](https://www.npmjs.com/package/nativescript-mapbox/)) | :white_check_mark: | :white_check_mark: | Telerik |
+| [NativeScript](https://market.nativescript.org/plugins/nativescript-mapbox/) ([npm](https://www.npmjs.com/package/nativescript-mapbox/)) | :white_check_mark: | :white_check_mark: | Telerik |
| [Xamarin](https://components.xamarin.com/view/mapboxsdk/) | :white_check_mark: | :white_check_mark: | Xamarin |
If your platform or hybrid application framework isn’t listed here, consider embedding [Mapbox GL JS](https://github.com/mapbox/mapbox-gl-js) using the standard Web capabilities on your platform.
diff --git a/appveyor.yml b/appveyor.yml
index d31160261f..eb53ad58bc 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -36,7 +36,7 @@ before_build:
build_script:
- call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64
- - cmake -G "Ninja" -DMBGL_PLATFORM=qt -DWITH_QT_DECODERS=ON -DWITH_QT_I18N=ON -DWITH_NODEJS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=C:\Qt\5.7\msvc2015_64\lib\cmake -DCMAKE_MAKE_PROGRAM="%APPVEYOR_BUILD_FOLDER%\platform\qt\ninja.exe" ..
+ - cmake -G "Ninja" -DMBGL_PLATFORM=qt -DWITH_QT_DECODERS=ON -DWITH_QT_I18N=ON -DWITH_NODEJS=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=C:\Qt\5.6.3\msvc2015_64\lib\cmake -DCMAKE_MAKE_PROGRAM="%APPVEYOR_BUILD_FOLDER%\platform\qt\ninja.exe" ..
- cmake --build . -- -j %NUMBER_OF_PROCESSORS%
after_build:
diff --git a/benchmark/util/tilecover.benchmark.cpp b/benchmark/util/tilecover.benchmark.cpp
new file mode 100644
index 0000000000..186de6f216
--- /dev/null
+++ b/benchmark/util/tilecover.benchmark.cpp
@@ -0,0 +1,96 @@
+#include <benchmark/benchmark.h>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/tile_coordinate.hpp>
+#include <mbgl/util/tile_cover.hpp>
+#include <mbgl/map/transform.hpp>
+
+using namespace mbgl;
+
+static const LatLngBounds sanFrancisco =
+ LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 });
+
+static void TileCountBounds(benchmark::State& state) {
+ std::size_t length = 0;
+ while (state.KeepRunning()) {
+ auto count = util::tileCount(sanFrancisco, 10);
+ length += count;
+ }
+}
+
+static void TileCoverPitchedViewport(benchmark::State& state) {
+ Transform transform;
+ transform.resize({ 512, 512 });
+ // slightly offset center so that tile order is better defined
+ transform.setLatLng({ 0.1, -0.1 });
+ transform.setZoom(8);
+ transform.setAngle(5.0);
+ transform.setPitch(40.0 * M_PI / 180.0);
+
+ std::size_t length = 0;
+ while (state.KeepRunning()) {
+ auto tiles = util::tileCover(transform.getState(), 8);
+ length += tiles.size();
+ }
+}
+
+static void TileCoverBounds(benchmark::State& state) {
+ std::size_t length = 0;
+ while (state.KeepRunning()) {
+ auto tiles = util::tileCover(sanFrancisco, 8);
+ length += tiles.size();
+ }
+}
+
+static const auto geomPolygon = Polygon<double>{
+ {
+ {-122.5143814086914,37.779127216982424},
+ {-122.50811576843262,37.72721239056709},
+ {-122.50313758850099,37.70820178063929},
+ {-122.3938751220703,37.707454835665274},
+ {-122.37567901611328,37.70663997801684},
+ {-122.36297607421874,37.71343018466285},
+ {-122.354736328125,37.727280276860036},
+ {-122.36469268798828,37.73868429065797},
+ {-122.38014221191408,37.75442980295571},
+ {-122.38391876220702,37.78753873820529},
+ {-122.35919952392578,37.8065289741725},
+ {-122.35679626464844,37.820632846207864},
+ {-122.3712158203125,37.835276322922695},
+ {-122.3818588256836,37.82958198283902},
+ {-122.37190246582031,37.80788523279169},
+ {-122.38735198974608,37.791337175930686},
+ {-122.40966796874999,37.812767557570204},
+ {-122.46425628662108,37.807071480609274},
+ {-122.46803283691405,37.810326435534755},
+ {-122.47901916503906,37.81168262440736},
+ {-122.48966217041016,37.78916666399649},
+ {-122.50579833984375,37.78781006166096},
+ {-122.5143814086914,37.779127216982424}
+ }
+};
+
+static void TileCoverPolygon(benchmark::State& state) {
+ std::size_t length = 0;
+
+ while (state.KeepRunning()) {
+ auto tiles = util::tileCover(geomPolygon, 8);
+ length += tiles.size();
+ }
+}
+
+static void TileCountPolygon(benchmark::State& state) {
+ std::size_t length = 0;
+
+ while (state.KeepRunning()) {
+ auto tiles = util::tileCount(geomPolygon, 16);
+ length += tiles;
+ }
+}
+
+BENCHMARK(TileCountBounds);
+BENCHMARK(TileCountPolygon);
+BENCHMARK(TileCoverPitchedViewport);
+BENCHMARK(TileCoverBounds);
+BENCHMARK(TileCoverPolygon);
+
diff --git a/circle.yml b/circle.yml
index 8c0505badc..ca9ceb6636 100644
--- a/circle.yml
+++ b/circle.yml
@@ -422,7 +422,7 @@ jobs:
- deploy:
name: Publish to Maven
command: |
- if [ "${CIRCLE_BRANCH}" == "release-boba" ]; then make run-android-upload-archives ; fi
+ if [ "${CIRCLE_BRANCH}" == "master" ]; then make run-android-upload-archives ; fi
# ------------------------------------------------------------------------------
@@ -866,7 +866,7 @@ jobs:
# ------------------------------------------------------------------------------
macos-debug-qt5:
macos:
- xcode: "9.2.0"
+ xcode: "9.3.0"
environment:
BUILDTYPE: Debug
HOMEBREW_NO_AUTO_UPDATE: 1
diff --git a/cmake/benchmark-files.cmake b/cmake/benchmark-files.cmake
index fdafcf30f9..21547eb9c4 100644
--- a/cmake/benchmark-files.cmake
+++ b/cmake/benchmark-files.cmake
@@ -23,5 +23,6 @@ set(MBGL_BENCHMARK_FILES
# util
benchmark/util/dtoa.benchmark.cpp
+ benchmark/util/tilecover.benchmark.cpp
)
diff --git a/cmake/core-files.cmake b/cmake/core-files.cmake
index 208c598872..7e48b336b4 100644
--- a/cmake/core-files.cmake
+++ b/cmake/core-files.cmake
@@ -746,11 +746,11 @@ set(MBGL_CORE_FILES
src/mbgl/util/stopwatch.hpp
src/mbgl/util/string.cpp
src/mbgl/util/thread_local.hpp
- src/mbgl/util/throttler.cpp
- src/mbgl/util/throttler.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
diff --git a/cmake/loop-uv.cmake b/cmake/loop-uv.cmake
deleted file mode 100644
index f4e7ced00e..0000000000
--- a/cmake/loop-uv.cmake
+++ /dev/null
@@ -1,18 +0,0 @@
-add_library(mbgl-loop-uv STATIC
- platform/default/async_task.cpp
- platform/default/run_loop.cpp
- platform/default/timer.cpp
-)
-
-target_include_directories(mbgl-loop-uv
- PRIVATE include
- PRIVATE src
-)
-
-target_link_libraries(mbgl-loop-uv
- PRIVATE mbgl-core
-)
-
-create_source_groups(mbgl-loop-uv)
-
-xcode_create_scheme(TARGET mbgl-loop-uv) \ No newline at end of file
diff --git a/cmake/node.cmake b/cmake/node.cmake
index 0c2f556b7d..90bec6575c 100644
--- a/cmake/node.cmake
+++ b/cmake/node.cmake
@@ -2,6 +2,22 @@
include(cmake/NodeJS.cmake)
nodejs_init()
+add_library(mbgl-loop-node STATIC
+ platform/default/async_task.cpp
+ platform/default/run_loop.cpp
+ platform/default/timer.cpp
+)
+
+target_include_directories(mbgl-loop-node
+ PRIVATE include
+ PRIVATE src
+)
+
+target_include_directories(mbgl-loop-node PUBLIC ${NODEJS_INCLUDE_DIRS})
+
+create_source_groups(mbgl-loop-node)
+xcode_create_scheme(TARGET mbgl-loop-node)
+
add_nodejs_module(mbgl-node
platform/node/src/node_mapbox_gl_native.cpp
)
@@ -31,13 +47,9 @@ target_include_directories(mbgl-node
PRIVATE platform/default
)
-# Use node-provided uv.h. This is not part of loop-uv.cmake because loop-uv.cmake is also
-# used by linux/config.cmake, where we need to use headers provided by mason's libuv.
-target_include_directories(mbgl-loop-uv PUBLIC ${NODEJS_INCLUDE_DIRS})
-
target_link_libraries(mbgl-node
PRIVATE mbgl-core
- PRIVATE mbgl-loop-uv
+ PRIVATE mbgl-loop-node
)
target_add_mason_package(mbgl-node PRIVATE geojson)
diff --git a/include/mbgl/util/projection.hpp b/include/mbgl/util/projection.hpp
index b4a34521a4..65a84d8dc2 100644
--- a/include/mbgl/util/projection.hpp
+++ b/include/mbgl/util/projection.hpp
@@ -78,8 +78,9 @@ public:
return project_(latLng, worldSize(scale));
}
- static Point<double> project(const LatLng& latLng, uint8_t zoom) {
- return project_(latLng, std::pow(2.0, zoom));
+ //Returns point on tile
+ static Point<double> project(const LatLng& latLng, int32_t zoom) {
+ return project_(latLng, 1 << zoom);
}
static LatLng unproject(const Point<double>& p, double scale, LatLng::WrapMode wrapMode = LatLng::Unwrapped) {
@@ -90,16 +91,7 @@ public:
wrapMode
};
}
-
- // Project lat, lon to point in a zoom-dependent world size
- static Point<double> project(const LatLng& point, uint8_t zoom, uint16_t tileSize) {
- const double t2z = tileSize * std::pow(2, zoom);
- Point<double> pt = project_(point, t2z);
- // Flip y coordinate
- auto x = ::round(std::min(pt.x, t2z));
- auto y = ::round(std::min(t2z - pt.y, t2z));
- return { x, y };
- }
+
private:
static Point<double> project_(const LatLng& latLng, double worldSize) {
return Point<double> {
diff --git a/mapbox-gl-js b/mapbox-gl-js
-Subproject cc3bb6afac758258a559e6ab3f7c22d99f41b3b
+Subproject 5b3af8e1515ee311967661b5aabdab65f1376e3
diff --git a/misc/ca-bundle.crt b/misc/ca-bundle.crt
index 29691b9733..2ec7884afd 100644
--- a/misc/ca-bundle.crt
+++ b/misc/ca-bundle.crt
@@ -1,7 +1,7 @@
##
## Bundle of CA Root Certificates
##
-## Certificate data from Mozilla as of: Wed Jan 17 00:48:54 2018 GMT
+## Certificate data from Mozilla as of: Mon Apr 16 12:40:48 2018 GMT
##
## This is a bundle of X.509 certificates of public Certificate Authorities
## (CA). These were automatically extracted from Mozilla's root certificates
@@ -14,7 +14,7 @@
## Just configure this file as the SSLCACertificateFile.
##
## Conversion done with mk-ca-bundle.pl version 1.27.
-## SHA256: a3ac15b98179dd2f3c5de076d10b1d53048754372f7207c2f327510cdd78fbd8
+## SHA256: 704f02707ec6b4c4a7597a8c6039b020def11e64f3ef0605a9c3543d48038a57
##
@@ -446,60 +446,6 @@ EtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLH
llpwrN9M
-----END CERTIFICATE-----
-Camerfirma Chambers of Commerce Root
-====================================
------BEGIN CERTIFICATE-----
-MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
-QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
-ZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMgb2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAx
-NjEzNDNaFw0zNzA5MzAxNjEzNDRaMH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZp
-cm1hIFNBIENJRiBBODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3Jn
-MSIwIAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0BAQEFAAOC
-AQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtbunXF/KGIJPov7coISjlU
-xFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0dBmpAPrMMhe5cG3nCYsS4No41XQEMIwRH
-NaqbYE6gZj3LJgqcQKH0XZi/caulAGgq7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jW
-DA+wWFjbw2Y3npuRVDM30pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFV
-d9oKDMyXroDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIGA1Ud
-EwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5jaGFtYmVyc2lnbi5v
-cmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p26EpW1eLTXYGduHRooowDgYDVR0P
-AQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hh
-bWJlcnNpZ24ub3JnMCcGA1UdEgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYD
-VR0gBFEwTzBNBgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
-aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEBAAxBl8IahsAi
-fJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZdp0AJPaxJRUXcLo0waLIJuvvD
-L8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wN
-UPf6s+xCX6ndbcj0dc97wXImsQEcXCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/n
-ADydb47kMgkdTXg0eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1
-erfutGWaIZDgqtCYvDi1czyL+Nw=
------END CERTIFICATE-----
-
-Camerfirma Global Chambersign Root
-==================================
------BEGIN CERTIFICATE-----
-MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMe
-QUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1i
-ZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYx
-NDE4WhcNMzcwOTMwMTYxNDE4WjB9MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJt
-YSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEg
-MB4GA1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUAA4IBDQAw
-ggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0Mi+ITaFgCPS3CU6gSS9J
-1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/sQJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8O
-by4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpVeAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl
-6DJWk0aJqCWKZQbua795B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c
-8lCrEqWhz0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0TAQH/
-BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1iZXJzaWduLm9yZy9j
-aGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4wTcbOX60Qq+UDpfqpFDAOBgNVHQ8B
-Af8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAHMCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBj
-aGFtYmVyc2lnbi5vcmcwKgYDVR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9y
-ZzBbBgNVHSAEVDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
-bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0BAQUFAAOCAQEA
-PDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUMbKGKfKX0j//U2K0X1S0E0T9Y
-gOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXiryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJ
-PJ7oKXqJ1/6v/2j1pReQvayZzKWGVwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4
-IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes
-t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
------END CERTIFICATE-----
-
XRamp Global CA Root
====================
-----BEGIN CERTIFICATE-----
@@ -710,30 +656,6 @@ RLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubS
fZGL+T0yjWW06XyxV3bqxbYoOb8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----
-DST ACES CA X6
-==============
------BEGIN CERTIFICATE-----
-MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBbMQswCQYDVQQG
-EwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QxETAPBgNVBAsTCERTVCBBQ0VT
-MRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0wMzExMjAyMTE5NThaFw0xNzExMjAyMTE5NTha
-MFsxCzAJBgNVBAYTAlVTMSAwHgYDVQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UE
-CxMIRFNUIEFDRVMxFzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOC
-AQ8AMIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPuktKe1jzI
-DZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7gLFViYsx+tC3dr5BPTCa
-pCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZHfAjIgrrep4c9oW24MFbCswKBXy314pow
-GCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4aahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPy
-MjwmR/onJALJfh1biEITajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1Ud
-EwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rkc3Qu
-Y29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjtodHRwOi8vd3d3LnRy
-dXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMtaW5kZXguaHRtbDAdBgNVHQ4EFgQU
-CXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZIhvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V2
-5FYrnJmQ6AgwbN99Pe7lv7UkQIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6t
-Fr8hlxCBPeP/h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
-nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpRrscL9yuwNwXs
-vFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf29w4LTJxoeHtxMcfrHuBnQfO3
-oKfN5XozNmr6mis=
------END CERTIFICATE-----
-
SwissSign Gold CA - G2
======================
-----BEGIN CERTIFICATE-----
@@ -976,27 +898,6 @@ FAkK+qDmfQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdvGDeA
U/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
-----END CERTIFICATE-----
-Security Communication EV RootCA1
-=================================
------BEGIN CERTIFICATE-----
-MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
-U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMhU2VjdXJpdHkgQ29tbXVuaWNh
-dGlvbiBFViBSb290Q0ExMB4XDTA3MDYwNjAyMTIzMloXDTM3MDYwNjAyMTIzMlowYDELMAkGA1UE
-BhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKjAoBgNVBAsTIVNl
-Y3VyaXR5IENvbW11bmljYXRpb24gRVYgUm9vdENBMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
-AQoCggEBALx/7FebJOD+nLpCeamIivqA4PUHKUPqjgo0No0c+qe1OXj/l3X3L+SqawSERMqm4miO
-/VVQYg+kcQ7OBzgtQoVQrTyWb4vVog7P3kmJPdZkLjjlHmy1V4qe70gOzXppFodEtZDkBp2uoQSX
-WHnvIEqCa4wiv+wfD+mEce3xDuS4GBPMVjZd0ZoeUWs5bmB2iDQL87PRsJ3KYeJkHcFGB7hj3R4z
-ZbOOCVVSPbW9/wfrrWFVGCypaZhKqkDFMxRldAD5kd6vA0jFQFTcD4SQaCDFkpbcLuUCRarAX1T4
-bepJz11sS6/vmsJWXMY1VkJqMF/Cq/biPT+zyRGPMUzXn0kCAwEAAaNCMEAwHQYDVR0OBBYEFDVK
-9U2vP9eCOKyrcWUXdYydVZPmMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqG
-SIb3DQEBBQUAA4IBAQCoh+ns+EBnXcPBZsdAS5f8hxOQWsTvoMpfi7ent/HWtWS3irO4G8za+6xm
-iEHO6Pzk2x6Ipu0nUBsCMCRGef4Eh3CXQHPRwMFXGZpppSeZq51ihPZRwSzJIxXYKLerJRO1RuGG
-Av8mjMSIkh1W/hln8lXkgKNrnKt34VFxDSDbEJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnW
-mHyojf6GPgcWkuF75x3sM3Z+Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEW
-T1MKZPlO9L9OVL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490
------END CERTIFICATE-----
-
OISTE WISeKey Global Root GA CA
===============================
-----BEGIN CERTIFICATE-----
@@ -2027,36 +1928,6 @@ NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv
w9y4AyHqnxbxLFS1
-----END CERTIFICATE-----
-CA Disig Root R1
-================
------BEGIN CERTIFICATE-----
-MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw
-EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp
-ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx
-EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp
-c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy
-3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8
-u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2
-m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk
-CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa
-YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6
-vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL
-LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX
-ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is
-XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV
-HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ
-04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR
-xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B
-LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM
-CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb
-VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85
-YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS
-ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix
-lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N
-UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ
-a7+h89n07eLw4+1knj0vllJPgFOL
------END CERTIFICATE-----
-
CA Disig Root R2
================
-----BEGIN CERTIFICATE-----
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 6da01aacf3..a25656012b 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -20,7 +20,10 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
- Reduce per-frame render CPU time [#11811](https://github.com/mapbox/mapbox-gl-native/issues/11811)
- Add Korean localization [#11792](https://github.com/mapbox/mapbox-gl-native/pull/11792)
- Add Danish localization; update Hungarian, Russian, Swedish translations [#11136](https://github.com/mapbox/mapbox-gl-native/pull/11136)
-
+
+## 5.5.3 - May 4, 2018
+ - Check if renderer is not destroyed before delivering snapshot [#11800](https://github.com/mapbox/mapbox-gl-native/pull/11800)
+
## 6.0.1 - April 17, 2018
- Bump telemetry version to 3.0.2 [#11710](https://github.com/mapbox/mapbox-gl-native/pull/11710)
diff --git a/platform/android/MapboxGLAndroidSDK/.gitignore b/platform/android/MapboxGLAndroidSDK/.gitignore
new file mode 100644
index 0000000000..c24bd2563a
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/.gitignore
@@ -0,0 +1 @@
+dependency-graph-mapbox-libraries.png
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle
index f82968051d..c43bc9112b 100644
--- a/platform/android/MapboxGLAndroidSDK/build.gradle
+++ b/platform/android/MapboxGLAndroidSDK/build.gradle
@@ -145,3 +145,4 @@ apply from: "${rootDir}/gradle/gradle-javadoc.gradle"
apply from: "${rootDir}/gradle/gradle-publish.gradle"
apply from: "${rootDir}/gradle/gradle-checkstyle.gradle"
apply from: "${rootDir}/gradle/gradle-tests-staticblockremover.gradle"
+apply from: "${rootDir}/gradle/gradle-dependencies-graph.gradle"
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
index 2b56f5b326..c639e49013 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java
@@ -238,6 +238,7 @@ public class LatLngBounds implements Parcelable {
westLon = temp;
}
} else {
+ lonSpan = GeometryConstants.LONGITUDE_SPAN - lonSpan;
if (westLon < eastLon) {
double temp = eastLon;
eastLon = westLon;
@@ -293,6 +294,20 @@ public class LatLngBounds implements Parcelable {
@FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latSouth,
double lonWest) {
+ checkParams(latNorth, lonEast, latSouth, lonWest);
+
+ lonEast = LatLng.wrap(lonEast, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+ lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+
+ return new LatLngBounds(latNorth, lonEast, latSouth, lonWest);
+ }
+
+ private static void checkParams(
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latNorth,
+ double lonEast,
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double latSouth,
+ double lonWest) {
+
if (Double.isNaN(latNorth) || Double.isNaN(latSouth)) {
throw new IllegalArgumentException("latitude must not be NaN");
}
@@ -313,11 +328,6 @@ public class LatLngBounds implements Parcelable {
if (latNorth < latSouth) {
throw new IllegalArgumentException("LatSouth cannot be less than latNorth");
}
-
- lonEast = LatLng.wrap(lonEast, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
- lonWest = LatLng.wrap(lonWest, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
-
- return new LatLngBounds(latNorth, lonEast, latSouth, lonWest);
}
private static double lat_(int z, int y) {
@@ -394,7 +404,7 @@ public class LatLngBounds implements Parcelable {
return (longitude <= eastLon)
&& (longitude >= westLon);
}
- return (longitude < eastLon) || (longitude > westLon);
+ return (longitude <= eastLon) || (longitude >= westLon);
}
/**
@@ -425,36 +435,94 @@ public class LatLngBounds implements Parcelable {
* @param bounds LatLngBounds to add
* @return LatLngBounds
*/
- public LatLngBounds union(LatLngBounds bounds) {
- return union(bounds.getLatNorth(), bounds.getLonEast(), bounds.getLatSouth(), bounds.getLonWest());
+ public @NonNull LatLngBounds union(@NonNull LatLngBounds bounds) {
+ return unionNoParamCheck(bounds.getLatNorth(), bounds.getLonEast(), bounds.getLatSouth(), bounds.getLonWest());
}
/**
* Returns a new LatLngBounds that stretches to include another LatLngBounds,
* given by corner points.
+ * <p>
+ * This values of northLat and southLat should be in the range of [-90, 90],
+ * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE},
+ * otherwise IllegalArgumentException will be thrown.
+ * northLat should be greater or equal southLat, otherwise IllegalArgumentException will be thrown.
+ * <p>
+ * This method doesn't recalculate most east or most west boundaries.
+ * Note that eastLon and westLon will be wrapped to be in the range of [-180, 180],
+ * see {@link GeometryConstants#MIN_LONGITUDE} and {@link GeometryConstants#MAX_LONGITUDE}
*
- * @param latNorth Northern Latitude
- * @param lonEast Eastern Longitude
- * @param latSouth Southern Latitude
- * @param lonWest Western Longitude
- * @return BoundingBox
- */
- public LatLngBounds union(final double latNorth, final double lonEast, final double latSouth, final double lonWest) {
- double north = (this.latitudeNorth < latNorth) ? latNorth : this.latitudeNorth;
- double south = (this.latitudeSouth > latSouth) ? latSouth : this.latitudeSouth;
-
- if (LatLngSpan.getLongitudeSpan(lonEast, this.longitudeWest)
- < LatLngSpan.getLongitudeSpan(this.longitudeEast, lonWest)) {
- return new LatLngBounds(north,
- lonEast,
- south,
+ * @param northLat Northern Latitude corner point
+ * @param eastLon Eastern Longitude corner point
+ * @param southLat Southern Latitude corner point
+ * @param westLon Western Longitude corner point
+ * @return LatLngBounds
+ */
+ public @NonNull LatLngBounds union(
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
+ double eastLon,
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
+ double westLon) {
+
+ checkParams(northLat, eastLon, southLat, westLon);
+
+ return unionNoParamCheck(northLat, eastLon, southLat, westLon);
+ }
+
+ private @NonNull LatLngBounds unionNoParamCheck(
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
+ double eastLon,
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
+ double westLon) {
+
+ northLat = (this.latitudeNorth < northLat) ? northLat : this.latitudeNorth;
+ southLat = (this.latitudeSouth > southLat) ? southLat : this.latitudeSouth;
+
+ eastLon = LatLng.wrap(eastLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+ westLon = LatLng.wrap(westLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+
+ // longitudes match
+ if (this.longitudeEast == eastLon && this.longitudeWest == westLon) {
+ return new LatLngBounds(northLat, eastLon, southLat, westLon);
+ }
+
+ boolean eastInThis = containsLongitude(this.longitudeEast, this.longitudeWest, eastLon);
+ boolean westInThis = containsLongitude(this.longitudeEast, this.longitudeWest, westLon);
+ boolean thisEastInside = containsLongitude(eastLon, westLon, this.longitudeEast);
+ boolean thisWestInside = containsLongitude(eastLon, westLon, this.longitudeWest);
+
+ // two intersections on each end - covers entire longitude
+ if (eastInThis && westInThis && thisEastInside && thisWestInside) {
+ return new LatLngBounds(northLat, GeometryConstants.MAX_LONGITUDE, southLat, GeometryConstants.MIN_LONGITUDE);
+ }
+
+ if (eastInThis) {
+ if (westInThis) {
+ return new LatLngBounds(northLat, this.longitudeEast, southLat, this.longitudeWest);
+ }
+ return new LatLngBounds(northLat, this.longitudeEast, southLat, westLon);
+ }
+
+ if (thisEastInside) {
+ if (thisWestInside) {
+ return new LatLngBounds(northLat, eastLon, southLat, westLon);
+ }
+ return new LatLngBounds(northLat, eastLon, southLat, this.longitudeWest);
+ }
+
+ // bounds do not intersect, find where they will form shortest union
+ if (LatLngSpan.getLongitudeSpan(eastLon, this.longitudeWest)
+ < LatLngSpan.getLongitudeSpan(this.longitudeEast, westLon)) {
+ return new LatLngBounds(northLat,
+ eastLon,
+ southLat,
this.longitudeWest);
}
- return new LatLngBounds(north,
+ return new LatLngBounds(northLat,
this.longitudeEast,
- south,
- lonWest);
+ southLat,
+ westLon);
}
/**
@@ -463,32 +531,89 @@ public class LatLngBounds implements Parcelable {
* @param box LatLngBounds to intersect with
* @return LatLngBounds
*/
- @Nullable
- public LatLngBounds intersect(LatLngBounds box) {
- double minLonWest = Math.max(getLonWest(), box.getLonWest());
- double maxLonEast = Math.min(getLonEast(), box.getLonEast());
- if (maxLonEast > minLonWest) {
- double minLatSouth = Math.max(getLatSouth(), box.getLatSouth());
- double maxLatNorth = Math.min(getLatNorth(), box.getLatNorth());
- if (maxLatNorth > minLatSouth) {
- return new LatLngBounds(maxLatNorth, maxLonEast, minLatSouth, minLonWest);
- }
- }
- return null;
+ public @Nullable LatLngBounds intersect(@NonNull LatLngBounds box) {
+ return intersectNoParamCheck(box.getLatNorth(), box.getLonEast(), box.getLatSouth(), box.getLonWest());
}
/**
* Returns a new LatLngBounds that is the intersection of this with another LatLngBounds
+ * <p>
+ * This values of northLat and southLat should be in the range of [-90, 90],
+ * see {@link GeometryConstants#MIN_LATITUDE} and {@link GeometryConstants#MAX_LATITUDE},
+ * otherwise IllegalArgumentException will be thrown.
+ * northLat should be greater or equal southLat, otherwise IllegalArgumentException will be thrown.
+ * <p>
+ * This method doesn't recalculate most east or most west boundaries.
+ * Note that eastLon and westLon will be wrapped to be in the range of [-180, 180],
+ * see {@link GeometryConstants#MIN_LONGITUDE} and {@link GeometryConstants#MAX_LONGITUDE}
*
- * @param northLatitude Northern Longitude
- * @param eastLongitude Eastern Latitude
- * @param southLatitude Southern Longitude
- * @param westLongitude Western Latitude
+ * @param northLat Northern Latitude corner point
+ * @param eastLon Eastern Longitude corner point
+ * @param southLat Southern Latitude corner point
+ * @param westLon Western Longitude corner point
* @return LatLngBounds
*/
- public LatLngBounds intersect(double northLatitude, double eastLongitude, double southLatitude,
- double westLongitude) {
- return intersect(new LatLngBounds(northLatitude, eastLongitude, southLatitude, westLongitude));
+ public @Nullable LatLngBounds intersect(
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
+ double eastLon,
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
+ double westLon) {
+
+ checkParams(northLat, eastLon, southLat, westLon);
+
+ return intersectNoParamCheck(northLat, eastLon, southLat, westLon);
+ }
+
+ private @Nullable LatLngBounds intersectNoParamCheck(
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE)double northLat,
+ double eastLon,
+ @FloatRange(from = GeometryConstants.MIN_LATITUDE, to = GeometryConstants.MAX_LATITUDE) double southLat,
+ double westLon) {
+
+ double maxsouthLat = Math.max(getLatSouth(), Math.min(GeometryConstants.MAX_LATITUDE, southLat));
+ double minnorthLat = Math.min(getLatNorth(), Math.max(GeometryConstants.MIN_LATITUDE, northLat));
+ if (minnorthLat < maxsouthLat) {
+ return null;
+ }
+
+ eastLon = LatLng.wrap(eastLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+ westLon = LatLng.wrap(westLon, GeometryConstants.MIN_LONGITUDE, GeometryConstants.MAX_LONGITUDE);
+
+ // longitudes match
+ if (this.longitudeEast == eastLon && this.longitudeWest == westLon) {
+ return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, westLon);
+ }
+
+ boolean eastInThis = containsLongitude(this.longitudeEast, this.longitudeWest, eastLon);
+ boolean westInThis = containsLongitude(this.longitudeEast, this.longitudeWest, westLon);
+ boolean thisEastInside = containsLongitude(eastLon, westLon, this.longitudeEast);
+ boolean thisWestInside = containsLongitude(eastLon, westLon, this.longitudeWest);
+
+ // two intersections : find the one that has longest span
+ if (eastInThis && westInThis && thisEastInside && thisWestInside) {
+
+ if (getLongitudeSpan(eastLon, this.longitudeWest) > getLongitudeSpan(this.longitudeEast, westLon)) {
+ return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, this.longitudeWest);
+ }
+
+ return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, westLon);
+ }
+
+ if (eastInThis) {
+ if (westInThis) {
+ return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, westLon);
+ }
+ return new LatLngBounds(minnorthLat, eastLon, maxsouthLat, this.longitudeWest);
+ }
+
+ if (thisEastInside) {
+ if (thisWestInside) {
+ return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, this.longitudeWest);
+ }
+ return new LatLngBounds(minnorthLat, this.longitudeEast, maxsouthLat, westLon);
+ }
+
+ return null;
}
/**
@@ -517,7 +642,7 @@ public class LatLngBounds implements Parcelable {
return (int) ((latitudeNorth + 90)
+ ((latitudeSouth + 90) * 1000)
+ ((longitudeEast + 180) * 1000000)
- + ((longitudeEast + 180) * 1000000000));
+ + ((longitudeWest + 180) * 1000000000));
}
/**
@@ -545,11 +670,11 @@ public class LatLngBounds implements Parcelable {
}
private static LatLngBounds readFromParcel(final Parcel in) {
- final double lonNorth = in.readDouble();
- final double latEast = in.readDouble();
- final double lonSouth = in.readDouble();
- final double latWest = in.readDouble();
- return new LatLngBounds(lonNorth, latEast, lonSouth, latWest);
+ final double northLat = in.readDouble();
+ final double eastLon = in.readDouble();
+ final double southLat = in.readDouble();
+ final double westLon = in.readDouble();
+ return new LatLngBounds(northLat, eastLon, southLat, westLon);
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
index ab1191c0cc..d0e51f941f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java
@@ -1,6 +1,5 @@
package com.mapbox.mapboxsdk.http;
-
import android.content.Context;
import android.content.pm.PackageInfo;
import android.os.Build;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
index c84651da24..d258064908 100755
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java
@@ -779,8 +779,9 @@ final class NativeMapView {
return;
}
- // Determine pixel ratio
- nativeAddImage(name, image, image.getDensity() / DisplayMetrics.DENSITY_DEFAULT);
+ // Determine pixel ratio, cast to float to avoid rounding, see mapbox-gl-native/issues/11809
+ float pixelRatio = (float) image.getDensity() / DisplayMetrics.DENSITY_DEFAULT;
+ nativeAddImage(name, image, pixelRatio);
}
public void addImages(@NonNull HashMap<String, Bitmap> bitmapHashMap) {
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 f0cb8d973a..929e4b4279 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
@@ -6,6 +6,8 @@ import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.os.Environment;
import android.support.annotation.NonNull;
+import android.support.annotation.UiThread;
+
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import timber.log.Timber;
@@ -43,6 +45,7 @@ public class FileSource {
* @param context the context to derive the cache path from
* @return the single instance of FileSource
*/
+ @UiThread
public static synchronized FileSource getInstance(Context context) {
if (INSTANCE == null) {
String cachePath = getCachePath(context);
@@ -122,6 +125,8 @@ public class FileSource {
initialize(Mapbox.getAccessToken(), cachePath, assetManager);
}
+ public native boolean isActivated();
+
public native void activate();
public native void deactivate();
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 4289deeda3..1dd8eddab9 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
@@ -166,7 +166,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param value a String value
* @return property wrapper around String
@@ -176,7 +176,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
@@ -356,7 +356,7 @@ public class PropertyFactory {
}
/**
- * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width.
+ * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width. Note that GeoJSON sources with `lineMetrics: true` specified won't render dashed lines to the expected scale. Also note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param value a Float[] value
* @return property wrapper around Float[]
@@ -366,7 +366,7 @@ public class PropertyFactory {
}
/**
- * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width.
+ * Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to density-independent pixels, multiply the length by the current line width. Note that GeoJSON sources with `lineMetrics: true` specified won't render dashed lines to the expected scale. Also note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
@@ -376,7 +376,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param value a String value
* @return property wrapper around String
@@ -386,7 +386,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
@@ -1156,7 +1156,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param value a String value
* @return property wrapper around String
@@ -1166,7 +1166,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
@@ -1536,7 +1536,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param value a String value
* @return property wrapper around String
@@ -1546,7 +1546,7 @@ public class PropertyFactory {
}
/**
- * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512).
+ * Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.
*
* @param expression an expression statement
* @return property wrapper around an expression statement
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
index c66e4b6fda..789a1b2b37 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
@@ -357,6 +357,58 @@ public class LatLngBoundsTest {
}
@Test
+ public void intersectNorthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ LatLngBounds intersectLatLngBounds =
+ LatLngBounds.from(10, 10, 0, 0)
+ .intersect(200, 200, 0, 0);
+ }
+
+ @Test
+ public void intersectSouthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ LatLngBounds intersectLatLngBounds =
+ LatLngBounds.from(0, 0, -10, -10)
+ .intersect(0, 0, -200, -200);
+ }
+
+ @Test
+ public void intersectSouthLessThanNorthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("LatSouth cannot be less than latNorth");
+
+ LatLngBounds intersectLatLngBounds =
+ LatLngBounds.from(10, 10, 0, 0)
+ .intersect(0, 200, 20, 0);
+ }
+
+
+ @Test
+ public void intersectEastWrapCheck() {
+
+ LatLngBounds latLngBounds1 = LatLngBounds.from(10, -150, 0, 0);
+ LatLngBounds latLngBounds2 = LatLngBounds.from(90, 200, 0, 0);
+
+ LatLngBounds intersectLatLngBounds = LatLngBounds.from(10, -160, 0, 0);
+
+ assertEquals(latLngBounds1.intersect(latLngBounds2), intersectLatLngBounds);
+ assertEquals(latLngBounds2.intersect(latLngBounds1), intersectLatLngBounds);
+ }
+
+ @Test
+ public void intersectWestWrapCheck() {
+ LatLngBounds latLngBounds1 = LatLngBounds.from(0, 0, -10, 150);
+ LatLngBounds latLngBounds2 = LatLngBounds.from(0, 0, -90, -200);
+
+ LatLngBounds intersectLatLngBounds = LatLngBounds.from(0, 0, -10, 160);
+
+ assertEquals(latLngBounds1.intersect(latLngBounds2), intersectLatLngBounds);
+ assertEquals(latLngBounds2.intersect(latLngBounds1), intersectLatLngBounds);
+ }
+
+ @Test
public void innerUnion() {
LatLngBounds latLngBounds = new LatLngBounds.Builder()
.include(new LatLng(1, 1))
@@ -391,14 +443,176 @@ public class LatLngBoundsTest {
.include(new LatLng(-10, -160))
.build();
- assertEquals("outer union should match",
- latLngBounds1.union(latLngBounds2),
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1,
+ new LatLngBounds.Builder()
+ .include(new LatLng(10, 160))
+ .include(new LatLng(-10, -160))
+ .build());
+
+ assertEquals(union1, union2);
+ }
+
+ @Test
+ public void unionOverDateLine2() {
+ LatLngBounds latLngBounds1 = new LatLngBounds.Builder()
+ .include(new LatLng(10, 170))
+ .include(new LatLng(0, 160))
+ .build();
+
+ LatLngBounds latLngBounds2 = new LatLngBounds.Builder()
+ .include(new LatLng(0, 165))
+ .include(new LatLng(-10, -160))
+ .build();
+
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1,
+ new LatLngBounds.Builder()
+ .include(new LatLng(10, 160))
+ .include(new LatLng(-10, -160))
+ .build());
+
+ assertEquals(union1, union2);
+ }
+
+ @Test
+ public void unionOverDateLine3() {
+ LatLngBounds latLngBounds1 = new LatLngBounds.Builder()
+ .include(new LatLng(10, -165))
+ .include(new LatLng(0, 160))
+ .build();
+
+ LatLngBounds latLngBounds2 = new LatLngBounds.Builder()
+ .include(new LatLng(0, -170))
+ .include(new LatLng(-10, -160))
+ .build();
+
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1,
+ new LatLngBounds.Builder()
+ .include(new LatLng(10, 160))
+ .include(new LatLng(-10, -160))
+ .build());
+
+ assertEquals(union1, union2);
+ }
+
+ @Test
+ public void unionOverDateLine4() {
+ LatLngBounds latLngBounds1 = new LatLngBounds.Builder()
+ .include(new LatLng(10, -160))
+ .include(new LatLng(0, 160))
+ .build();
+
+ LatLngBounds latLngBounds2 = new LatLngBounds.Builder()
+ .include(new LatLng(0, -170))
+ .include(new LatLng(-10, -175))
+ .build();
+
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1,
new LatLngBounds.Builder()
.include(new LatLng(10, 160))
.include(new LatLng(-10, -160))
.build());
+
+ assertEquals(union1, union2);
}
+ @Test
+ public void unionOverDateLine5() {
+ LatLngBounds latLngBounds1 = new LatLngBounds.Builder()
+ .include(new LatLng(10, -160))
+ .include(new LatLng(0, 160))
+ .build();
+
+ LatLngBounds latLngBounds2 = new LatLngBounds.Builder()
+ .include(new LatLng(0, 170))
+ .include(new LatLng(-10, 175))
+ .build();
+
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1,
+ new LatLngBounds.Builder()
+ .include(new LatLng(10, 160))
+ .include(new LatLng(-10, -160))
+ .build());
+
+ assertEquals(union1, union2);
+ }
+
+ @Test
+ public void unionOverDateLineReturnWorldLonSpan() {
+ LatLngBounds latLngBounds1 = LatLngBounds.from(10, -160, -10, -10);
+ LatLngBounds latLngBounds2 = LatLngBounds.from(10, 10, -10, 160);
+
+ LatLngBounds union1 = latLngBounds1.union(latLngBounds2);
+ LatLngBounds union2 = latLngBounds2.union(latLngBounds1);
+
+ assertEquals(union1, union2);
+ assertEquals(union1, LatLngBounds.from(10, 180, -10, -180));
+ }
+
+ @Test
+ public void unionNorthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ LatLngBounds unionLatLngBounds =
+ LatLngBounds.from(10, 10, 0, 0)
+ .union(200, 200, 0, 0);
+ }
+
+ @Test
+ public void unionSouthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("latitude must be between -90 and 90");
+ LatLngBounds unionLatLngBounds =
+ LatLngBounds.from(0, 0, -10, -10)
+ .union(0, 0, -200, -200);
+ }
+
+ @Test
+ public void unionSouthLessThanNorthCheck() {
+ exception.expect(IllegalArgumentException.class);
+ exception.expectMessage("LatSouth cannot be less than latNorth");
+
+ LatLngBounds unionLatLngBounds =
+ LatLngBounds.from(10, 10, 0, 0)
+ .union(0, 200, 20, 0);
+ }
+
+
+ @Test
+ public void unionEastWrapCheck() {
+
+ LatLngBounds latLngBounds1 = LatLngBounds.from(10, 10, 0, 0);
+ LatLngBounds latLngBounds2 = LatLngBounds.from(90, 200, 0, 0);
+ LatLngBounds unionLatLngBounds = LatLngBounds.from(90, -160, 0, 0);
+
+ assertEquals(latLngBounds1.union(latLngBounds2), unionLatLngBounds);
+ assertEquals(latLngBounds2.union(latLngBounds1), unionLatLngBounds);
+ }
+
+ @Test
+ public void unionWestWrapCheck() {
+ LatLngBounds latLngBounds1 = LatLngBounds.from(0, 0, -10, -10);
+ LatLngBounds latLngBounds2 = LatLngBounds.from(0, 0, -90, -200);
+
+ LatLngBounds unionLatLngBounds = LatLngBounds.from(0, 0, -90, 160);
+
+ assertEquals(latLngBounds1.union(latLngBounds2), unionLatLngBounds);
+ assertEquals(latLngBounds2.union(latLngBounds1), unionLatLngBounds);
+ }
@Test
public void northWest() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index 30e989c79b..80be26d3ae 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -41,6 +41,7 @@ android {
release {
minifyEnabled true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ signingConfig signingConfigs.debug
}
}
@@ -72,6 +73,7 @@ dependencies {
androidTestImplementation dependenciesList.testRules
androidTestImplementation dependenciesList.testEspressoCore
androidTestImplementation dependenciesList.testEspressoIntents
+ androidTestImplementation dependenciesList.testEspressoContrib
}
apply from: "${rootDir}/gradle/gradle-make.gradle"
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java
index 7a1fcbf5f3..89397c30eb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/OrientationTest.java
@@ -16,17 +16,17 @@ public class OrientationTest extends BaseActivityTest {
@Test
public void testChangeDeviceOrientation() {
onView(isRoot()).perform(orientationLandscape());
- waitLoop(2200);
+ waitAction(2200);
onView(isRoot()).perform(orientationPortrait());
- waitLoop(2500);
+ waitAction(2500);
onView(isRoot()).perform(orientationLandscapeReverse());
- waitLoop(500);
+ waitAction(500);
onView(isRoot()).perform(orientationPortraitReverse());
- waitLoop(1250);
+ waitAction(1250);
onView(isRoot()).perform(orientationLandscape());
- waitLoop(750);
+ waitAction(750);
onView(isRoot()).perform(orientationPortrait());
- waitLoop(950);
+ waitAction(950);
onView(isRoot()).perform(orientationLandscapeReverse());
onView(isRoot()).perform(orientationPortraitReverse());
onView(isRoot()).perform(orientationLandscape());
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java
new file mode 100644
index 0000000000..26a3a2e4ab
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/action/WaitAction.java
@@ -0,0 +1,39 @@
+package com.mapbox.mapboxsdk.testapp.action;
+
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.view.View;
+
+import org.hamcrest.Matcher;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+
+public final class WaitAction implements ViewAction {
+
+ private static final long DEFAULT_LOOP_TIME = 375;
+ private final long loopTime;
+
+ public WaitAction() {
+ this(DEFAULT_LOOP_TIME);
+ }
+
+ public WaitAction(long loopTime) {
+ this.loopTime = loopTime;
+ }
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return getClass().getSimpleName();
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ uiController.loopMainThreadForAtLeast(loopTime);
+ }
+}
+
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
index 3f32443021..6d90c20a46 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/BaseActivityTest.java
@@ -6,18 +6,19 @@ import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.test.espresso.Espresso;
import android.support.test.espresso.IdlingResourceTimeoutException;
-import android.support.test.espresso.UiController;
-import android.support.test.espresso.ViewAction;
import android.support.test.rule.ActivityTestRule;
-import android.view.View;
+
import com.mapbox.mapboxsdk.maps.MapboxMap;
import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.action.WaitAction;
import com.mapbox.mapboxsdk.testapp.utils.OnMapReadyIdlingResource;
+
import junit.framework.Assert;
-import org.hamcrest.Matcher;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
+
import timber.log.Timber;
import static android.support.test.espresso.Espresso.onView;
@@ -67,12 +68,12 @@ public abstract class BaseActivityTest {
onView(withId(id)).check(matches(isDisplayed()));
}
- protected void waitLoop() {
- waitLoop(500);
+ protected void waitAction() {
+ waitAction(500);
}
- protected void waitLoop(long waitTime) {
- onView(withId(R.id.mapView)).perform(new LoopAction(waitTime));
+ protected void waitAction(long waitTime) {
+ onView(withId(R.id.mapView)).perform(new WaitAction(waitTime));
}
static boolean isConnected(Context context) {
@@ -87,29 +88,5 @@ public abstract class BaseActivityTest {
Timber.e("@After test: unregister idle resource");
Espresso.unregisterIdlingResources(idlingResource);
}
-
- private class LoopAction implements ViewAction {
-
- private long loopTime;
-
- public LoopAction(long loopTime) {
- this.loopTime = loopTime;
- }
-
- @Override
- public Matcher<View> getConstraints() {
- return isDisplayed();
- }
-
- @Override
- public String getDescription() {
- return getClass().getSimpleName();
- }
-
- @Override
- public void perform(UiController uiController, View view) {
- uiController.loopMainThreadForAtLeast(loopTime);
- }
- }
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java
index 2a510b4dc5..26aee2de98 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/maps/widgets/CompassViewTest.java
@@ -62,7 +62,7 @@ public class CompassViewTest extends BaseActivityTest {
.build()
)));
onView(withId(R.id.compassView)).perform(click());
- waitLoop();
+ waitAction();
onView(withId(R.id.compassView)).check(matches(not(isDisplayed())));
invoke(mapboxMap, (uiController, mapboxMap) -> {
CameraPosition cameraPosition = mapboxMap.getCameraPosition();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java
new file mode 100644
index 0000000000..554bc988a6
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/storage/FileSourceTest.java
@@ -0,0 +1,129 @@
+package com.mapbox.mapboxsdk.testapp.storage;
+
+import android.os.Looper;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.ViewAction;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.View;
+
+import com.mapbox.mapboxsdk.storage.FileSource;
+import com.mapbox.mapboxsdk.testapp.R;
+import com.mapbox.mapboxsdk.testapp.action.WaitAction;
+import com.mapbox.mapboxsdk.testapp.activity.FeatureOverviewActivity;
+
+import org.hamcrest.Matcher;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.Espresso.pressBack;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.isRoot;
+import static android.support.test.espresso.matcher.ViewMatchers.withId;
+import static android.support.test.espresso.matcher.ViewMatchers.withText;
+import static com.mapbox.mapboxsdk.testapp.action.OrientationChangeAction.orientationLandscape;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+public class FileSourceTest {
+
+ @Rule
+ public ActivityTestRule<FeatureOverviewActivity> rule = new ActivityTestRule<>(FeatureOverviewActivity.class);
+
+ private FileSource fileSource;
+
+ @Before
+ public void setUp() throws Exception {
+ onView(withId(R.id.recyclerView)).perform(new FileSourceCreator());
+ }
+
+ @Test
+ public void testDefault() throws Exception {
+ assertFalse("FileSource should not be active", fileSource.isActivated());
+ }
+
+ @Test
+ public void testActivateDeactivate() throws Exception {
+ assertFalse("1) FileSource should not be active", fileSource.isActivated());
+ onView(withId(R.id.recyclerView)).perform(new FileSourceActivator(true));
+ assertTrue("2) FileSource should be active", fileSource.isActivated());
+ onView(withId(R.id.recyclerView)).perform(new FileSourceActivator(false));
+ assertFalse("3) FileSource should not be active", fileSource.isActivated());
+ }
+
+ @Test
+ public void testOpenCloseMapView() throws Exception {
+ assertFalse("1) FileSource should not be active", fileSource.isActivated());
+ onView(withText("Simple Map")).perform(click());
+ onView(withId(R.id.mapView)).perform(new WaitAction());
+ assertTrue("2) FileSource should be active", fileSource.isActivated());
+ onView(withId(R.id.mapView)).perform(new WaitAction());
+ pressBack();
+ assertFalse("3) FileSource should not be active", fileSource.isActivated());
+ }
+
+ @Test
+ public void testRotateMapView() throws Exception {
+ assertFalse("1) FileSource should not be active", fileSource.isActivated());
+ onView(withText("Simple Map")).perform(click());
+ onView(withId(R.id.mapView)).perform(new WaitAction());
+ onView(isRoot()).perform(orientationLandscape());
+ onView(withId(R.id.mapView)).perform(new WaitAction());
+ assertTrue("2) FileSource should be active", fileSource.isActivated());
+ onView(withId(R.id.mapView)).perform(new WaitAction());
+ pressBack();
+ assertFalse("3) FileSource should not be active", fileSource.isActivated());
+ }
+
+ private class FileSourceCreator implements ViewAction {
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Creates the filesource instance on the UI thread";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ assertTrue(Looper.myLooper() == Looper.getMainLooper());
+ fileSource = FileSource.getInstance(rule.getActivity());
+ }
+ }
+
+ private class FileSourceActivator implements ViewAction {
+
+ private boolean activate;
+
+ FileSourceActivator(boolean activate) {
+ this.activate = activate;
+ }
+
+ @Override
+ public Matcher<View> getConstraints() {
+ return isDisplayed();
+ }
+
+ @Override
+ public String getDescription() {
+ return "Creates the filesource instance on the UI thread";
+ }
+
+ @Override
+ public void perform(UiController uiController, View view) {
+ assertTrue(Looper.myLooper() == Looper.getMainLooper());
+ if (activate) {
+ fileSource.activate();
+ } else {
+ fileSource.deactivate();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java
index 2d16291832..2a8ac36507 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/BackgroundLayerTest.java
@@ -160,4 +160,4 @@ public class BackgroundLayerTest extends BaseActivityTest {
assertEquals((Float) layer.getBackgroundOpacity().getValue(), (Float) 0.3f);
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java
index a851fde6dd..101d22a531 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/CircleLayerTest.java
@@ -518,4 +518,4 @@ public class CircleLayerTest extends BaseActivityTest {
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java
index f22956072d..84b3e7bd68 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillExtrusionLayerTest.java
@@ -354,4 +354,4 @@ public class FillExtrusionLayerTest extends BaseActivityTest {
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java
index bdbd8958d2..3e1cbf666d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/FillLayerTest.java
@@ -353,4 +353,4 @@ public class FillLayerTest extends BaseActivityTest {
assertEquals((String) layer.getFillPattern().getValue(), (String) "pedestrian-polygon");
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java
index 549f309e4f..3a81786df4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HeatmapLayerTest.java
@@ -237,4 +237,4 @@ public class HeatmapLayerTest extends BaseActivityTest {
assertEquals((Float) layer.getHeatmapOpacity().getValue(), (Float) 0.3f);
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java
index 1fdc6d6dab..e0121a704a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/HillshadeLayerTest.java
@@ -252,4 +252,4 @@ public class HillshadeLayerTest extends BaseActivityTest {
assertEquals(layer.getHillshadeAccentColorAsInt(), Color.RED);
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
index 40cf0f2927..e35f0edcc4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
@@ -545,4 +545,4 @@ public class LineLayerTest extends BaseActivityTest {
assertEquals((String) layer.getLinePattern().getValue(), (String) "pedestrian-polygon");
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java
index 0410d09369..6e5afdb479 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/RasterLayerTest.java
@@ -254,4 +254,4 @@ public class RasterLayerTest extends BaseActivityTest {
assertEquals((Float) layer.getRasterFadeDuration().getValue(), (Float) 0.3f);
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
index 62f73b1507..fe38fef253 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/SymbolLayerTest.java
@@ -1392,4 +1392,4 @@ public class SymbolLayerTest extends BaseActivityTest {
assertEquals((String) layer.getTextTranslateAnchor().getValue(), (String) TEXT_TRANSLATE_ANCHOR_MAP);
});
}
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs
index 935813899f..575f64e809 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/layer.junit.ejs
@@ -150,7 +150,7 @@ public class <%- camelize(type) %>LayerTest extends BaseActivityTest {
assertEquals((<%- propertyType(property) %>) layer.get<%- camelize(property.name) %>().getValue(), (<%- propertyType(property) %>) <%- defaultValueJava(property) %>);
});
}
-<% if (isDataDriven(property)) { -%>
+<% if (property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven') { -%>
<% if (!(property.name.endsWith("-font")||property.name.endsWith("-offset"))) { -%>
@Test
@@ -188,4 +188,4 @@ public class <%- camelize(type) %>LayerTest extends BaseActivityTest {
<% } -%>
<% } -%>
<% } -%>
-} \ No newline at end of file
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 442635f909..fb1d0ef8a2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -69,9 +69,9 @@
android:value=".activity.FeatureOverviewActivity" />
</activity>
<activity
- android:name=".activity.annotation.AnimatedMarkerActivity"
- android:description="@string/description_animated_marker"
- android:label="@string/activity_animated_marker">
+ android:name=".activity.annotation.AnimatedSymbolLayerActivity"
+ android:description="@string/description_animated_symbollayer"
+ android:label="@string/activity_animated_symbollayer">
<meta-data
android:name="@string/category"
android:value="@string/category_annotation" />
@@ -794,4 +794,4 @@
<!-- android:value="true" /> -->
</application>
-</manifest> \ No newline at end of file
+</manifest>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
deleted file mode 100644
index e6db071141..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java
+++ /dev/null
@@ -1,283 +0,0 @@
-package com.mapbox.mapboxsdk.testapp.activity.annotation;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.TypeEvaluator;
-import android.animation.ValueAnimator;
-import android.os.Bundle;
-import android.support.annotation.DrawableRes;
-import android.support.v4.content.res.ResourcesCompat;
-import android.support.v7.app.AppCompatActivity;
-import android.view.View;
-import android.view.animation.AccelerateDecelerateInterpolator;
-
-import com.mapbox.geojson.Point;
-import com.mapbox.mapboxsdk.annotations.Icon;
-import com.mapbox.mapboxsdk.annotations.IconFactory;
-import com.mapbox.mapboxsdk.annotations.Marker;
-import com.mapbox.mapboxsdk.annotations.MarkerView;
-import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
-import com.mapbox.mapboxsdk.annotations.MarkerViewOptions;
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.geometry.LatLngBounds;
-import com.mapbox.mapboxsdk.maps.MapView;
-import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.testapp.R;
-import com.mapbox.mapboxsdk.testapp.utils.IconUtils;
-import com.mapbox.turf.TurfMeasurement;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-/**
- * Test activity showcasing animating MarkerViews.
- */
-public class AnimatedMarkerActivity extends AppCompatActivity {
-
- private MapView mapView;
- private MapboxMap mapboxMap;
-
- private LatLng dupontCircle = new LatLng(38.90962, -77.04341);
-
- private Marker passengerMarker = null;
- private MarkerView carMarker = null;
-
- private Runnable animationRunnable;
-
- private List<MarkerView> markerViews = new ArrayList<>();
- private boolean stopped;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_animated_marker);
-
- mapView = (MapView) findViewById(R.id.mapView);
- mapView.onCreate(savedInstanceState);
- mapView.getMapAsync(mapboxMap -> {
- AnimatedMarkerActivity.this.mapboxMap = mapboxMap;
- setupMap();
-
- animationRunnable = () -> {
- for (int i = 0; i < 10; i++) {
- addRandomCar();
- }
- addPassenger();
- addMainCar();
- };
- mapView.post(animationRunnable);
- });
- }
-
- private void setupMap() {
- CameraPosition cameraPosition = new CameraPosition.Builder()
- .target(dupontCircle)
- .zoom(15)
- .build();
- mapboxMap.setCameraPosition(cameraPosition);
- }
-
- private void addPassenger() {
- if (isActivityStopped()) {
- return;
- }
-
- LatLng randomLatLng = getLatLngInBounds();
-
- if (passengerMarker == null) {
- Icon icon = IconUtils.drawableToIcon(this, R.drawable.ic_directions_run_black,
- ResourcesCompat.getColor(getResources(), R.color.blueAccent, getTheme()));
- passengerMarker = mapboxMap.addMarker(new MarkerViewOptions()
- .position(randomLatLng)
- .icon(icon));
- } else {
- passengerMarker.setPosition(randomLatLng);
- }
- }
-
- private void addMainCar() {
- if (isActivityStopped()) {
- return;
- }
-
- LatLng randomLatLng = getLatLngInBounds();
-
- if (carMarker == null) {
- carMarker = createCarMarker(randomLatLng, R.drawable.ic_taxi_top,
- markerView -> {
- // Make sure the car marker is selected so that it's always brought to the front (#5285)
- mapboxMap.selectMarker(carMarker);
- animateMoveToPassenger(carMarker);
- });
- markerViews.add(carMarker);
- } else {
- carMarker.setPosition(randomLatLng);
- }
- }
-
- private void animateMoveToPassenger(final MarkerView car) {
- if (isActivityStopped()) {
- return;
- }
-
- ValueAnimator animator = animateMoveMarker(car, passengerMarker.getPosition());
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- addPassenger();
- animateMoveToPassenger(car);
- }
- });
- }
-
- protected void addRandomCar() {
- markerViews.add(createCarMarker(getLatLngInBounds(), R.drawable.ic_car_top,
- markerView -> randomlyMoveMarker(markerView)));
- }
-
- private void randomlyMoveMarker(final MarkerView marker) {
- if (isActivityStopped()) {
- return;
- }
-
- ValueAnimator animator = animateMoveMarker(marker, getLatLngInBounds());
-
- // Add listener to restart animation on end
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- randomlyMoveMarker(marker);
- }
- });
- }
-
- private ValueAnimator animateMoveMarker(final MarkerView marker, LatLng to) {
- marker.setRotation((float) getBearing(marker.getPosition(), to));
-
- final ValueAnimator markerAnimator = ObjectAnimator.ofObject(
- marker, "position", new LatLngEvaluator(), marker.getPosition(), to);
- markerAnimator.setDuration((long) (10 * marker.getPosition().distanceTo(to)));
- markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
-
- // Start
- markerAnimator.start();
-
- return markerAnimator;
- }
-
- private MarkerView createCarMarker(LatLng start, @DrawableRes int carResource,
- MarkerViewManager.OnMarkerViewAddedListener listener) {
- Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this)
- .fromResource(carResource);
-
- // View Markers
- return mapboxMap.addMarker(new MarkerViewOptions()
- .position(start)
- .icon(icon), listener);
-
- // GL Markers
-// return mapboxMap.addMarker(new MarkerOptions()
-// .position(start)
-// .icon(icon));
-
- }
-
- private LatLng getLatLngInBounds() {
- LatLngBounds bounds = mapboxMap.getProjection().getVisibleRegion().latLngBounds;
- Random generator = new Random();
- double randomLat = bounds.getLatSouth() + generator.nextDouble()
- * (bounds.getLatNorth() - bounds.getLatSouth());
- double randomLon = bounds.getLonWest() + generator.nextDouble()
- * (bounds.getLonEast() - bounds.getLonWest());
- return new LatLng(randomLat, randomLon);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- mapView.onStart();
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- mapView.onResume();
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- mapView.onPause();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
-
- stopped = true;
-
- // Stop ongoing animations, prevent memory leaks
- if (mapboxMap != null) {
- MarkerViewManager markerViewManager = mapboxMap.getMarkerViewManager();
- for (MarkerView markerView : markerViews) {
- View view = markerViewManager.getView(markerView);
- if (view != null) {
- view.animate().cancel();
- }
- }
- }
-
- // onStop
- mapView.onStop();
- mapView.removeCallbacks(animationRunnable);
- }
-
- @Override
- protected void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- mapView.onSaveInstanceState(outState);
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- mapView.onDestroy();
- }
-
- @Override
- public void onLowMemory() {
- super.onLowMemory();
- mapView.onLowMemory();
- }
-
- /**
- * Evaluator for LatLng pairs
- */
- private static class LatLngEvaluator implements TypeEvaluator<LatLng> {
-
- private LatLng latLng = new LatLng();
-
- @Override
- public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
- latLng.setLatitude(startValue.getLatitude()
- + ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
- latLng.setLongitude(startValue.getLongitude()
- + ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
- return latLng;
- }
- }
-
- private double getBearing(LatLng from, LatLng to) {
- return TurfMeasurement.bearing(
- Point.fromLngLat(from.getLongitude(), from.getLatitude()),
- Point.fromLngLat(to.getLongitude(), to.getLatitude())
- );
- }
-
- private boolean isActivityStopped() {
- return stopped;
- }
-}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java
index 6277dffe91..5983fb367a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java
@@ -172,9 +172,12 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
if (mapboxMap == null) {
return false;
}
- findViewById(R.id.fab).setVisibility(View.GONE);
- resetCameraPosition();
- playAnimation(item.getItemId());
+
+ if (item.getItemId() != android.R.id.home) {
+ findViewById(R.id.fab).setVisibility(View.GONE);
+ resetCameraPosition();
+ playAnimation(item.getItemId());
+ }
return super.onOptionsItemSelected(item);
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java
index df06c9c42d..81fd2c6ff8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/ZoomFunctionSymbolLayerActivity.java
@@ -5,7 +5,6 @@ import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Menu;
import android.view.MenuItem;
-
import com.google.gson.JsonObject;
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.FeatureCollection;
@@ -16,16 +15,13 @@ 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 timber.log.Timber;
import java.util.List;
-import timber.log.Timber;
-
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
-import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
-import static com.mapbox.mapboxsdk.style.expressions.Expression.linear;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
+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.switchCase;
import static com.mapbox.mapboxsdk.style.expressions.Expression.zoom;
@@ -44,7 +40,6 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity {
private static final String BUS_MAKI_ICON_ID = "bus-11";
private static final String CAFE_MAKI_ICON_ID = "cafe-11";
private static final String KEY_PROPERTY_SELECTED = "selected";
- private static final float ZOOM_STOP_MIN_VALUE = 7.0f;
private static final float ZOOM_STOP_MAX_VALUE = 12.0f;
private MapView mapView;
@@ -103,11 +98,9 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity {
layer = new SymbolLayer(LAYER_ID, SOURCE_ID);
layer.setProperties(
iconImage(
- interpolate(
- linear(), zoom(),
- stop(ZOOM_STOP_MIN_VALUE, BUS_MAKI_ICON_ID),
- stop(ZOOM_STOP_MAX_VALUE, CAFE_MAKI_ICON_ID)
- )
+ step(zoom(), literal(BUS_MAKI_ICON_ID),
+ stop(ZOOM_STOP_MAX_VALUE, CAFE_MAKI_ICON_ID)
+ )
),
iconSize(
switchCase(
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
index 0566757d58..252af714e7 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml
@@ -10,9 +10,9 @@
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- app:mapbox_cameraTargetLat="51.502615"
- app:mapbox_cameraTargetLng="4.972326"
- app:mapbox_cameraZoom="6"
+ app:mapbox_cameraTargetLat="38.90962"
+ app:mapbox_cameraTargetLng="-77.04341"
+ app:mapbox_cameraZoom="15"
app:mapbox_styleUrl="@string/mapbox_style_light"/>
</LinearLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
index 5238176ce8..17d6ad57c6 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/descriptions.xml
@@ -19,7 +19,7 @@
<string name="description_offline">Offline Map example</string>
<string name="description_update_metadata">Update metadata example</string>
<string name="description_offline_region_delete">Delete region example</string>
- <string name="description_animated_marker">Animate the position change of a marker</string>
+ <string name="description_animated_symbollayer">Animate the position change of a symbol layer</string>
<string name="description_polyline">Add a polyline to a map</string>
<string name="description_polygon">Add a polygon to a map</string>
<string name="description_scroll_by">Scroll with pixels in x,y direction</string>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
index 89ec586950..3f011bd3ed 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/titles.xml
@@ -4,7 +4,7 @@
<string name="activity_map_fragment">Map Fragment</string>
<string name="activity_multimap">Multiple Maps on Screen</string>
<string name="activity_add_bulk_markers">Add Markers In Bulk</string>
- <string name="activity_animated_marker">Animated Markers</string>
+ <string name="activity_animated_symbollayer">Animated SymbolLayer</string>
<string name="activity_dynamic_marker">Dynamic Marker</string>
<string name="activity_polyline">Polyline</string>
<string name="activity_polygon">Polygon</string>
diff --git a/platform/android/README.md b/platform/android/README.md
index 1dbdeee343..31e0a94f2c 100644
--- a/platform/android/README.md
+++ b/platform/android/README.md
@@ -12,7 +12,7 @@ Alright. So, actually, you may be in the wrong place. From here on in, this READ
**To install and use the Mapbox Maps SDK for Android in an application, see the [Mapbox Maps SDK for Android website](https://www.mapbox.com/install/android/).**
-[![](https://www.mapbox.com/android-sdk/images/splash.png)](https://www.mapbox.com/android-sdk/)
+[![](https://www.mapbox.com/android-docs/assets/overview-map-sdk-322-9abe118316efb5910b6101e222a2e57c.png)](https://www.mapbox.com/android-sdk/)
### Setup environment
@@ -89,15 +89,14 @@ More information about building and distributing this project in [DISTRIBUTE.md]
#### Using the SDK snapshot
-Instead of using the latest stable release of the Maps SDK for Android, you can use a "snapshot" or the beta version if there is one available. Our snapshots are built every time a Github pull request adds code to this repository's `master` branch. If you'd like to use a snapshot build, your Android project's gradle file should have -SNAPSHOT appended to the SDK version number. For example `5.2.0-SNAPSHOT` or:
+Instead of using the latest stable release of the Maps SDK for Android, you can use a "snapshot" or the beta version if there is one available. Our snapshots are built every time a Github pull request adds code to this repository's `master` branch. If you'd like to use a snapshot build, your Android project's gradle file should have -SNAPSHOT appended to the SDK version number. For example, the `5.2.0-SNAPSHOT` would look like:
```java
// Mapbox SDK dependency
-compile('com.mapbox.mapboxsdk:mapbox-android-sdk:5.2.0-SNAPSHOT@aar') {
- transitive = true
-}
+implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:5.2.0-SNAPSHOT'
```
-You need to have the section below in your build.gradle root folder to be able to resolve the SNAPSHOT dependencies:
+
+You also need to have the section below in your build.gradle root folder to be able to resolve the SNAPSHOT dependencies:
```
allprojects {
repositories {
diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle
index 7b31cf9e4c..d50f6cef08 100644
--- a/platform/android/gradle/dependencies.gradle
+++ b/platform/android/gradle/dependencies.gradle
@@ -8,7 +8,7 @@ ext {
]
versions = [
- mapboxServices : '3.0.1',
+ mapboxServices : '3.1.0',
mapboxTelemetry: '3.1.0',
mapboxGestures : '0.2.0',
supportLib : '25.4.0',
@@ -40,6 +40,7 @@ ext {
testRules : "com.android.support.test:rules:${versions.testRunner}",
testEspressoCore : "com.android.support.test.espresso:espresso-core:${versions.espresso}",
testEspressoIntents : "com.android.support.test.espresso:espresso-intents:${versions.espresso}",
+ testEspressoContrib : "com.android.support.test.espresso:espresso-contrib:${versions.espresso}",
supportAnnotations : "com.android.support:support-annotations:${versions.supportLib}",
supportAppcompatV7 : "com.android.support:appcompat-v7:${versions.supportLib}",
@@ -54,4 +55,4 @@ ext {
leakCanaryDebug : "com.squareup.leakcanary:leakcanary-android:${versions.leakCanary}",
leakCanaryRelease : "com.squareup.leakcanary:leakcanary-android-no-op:${versions.leakCanary}"
]
-} \ No newline at end of file
+}
diff --git a/platform/android/gradle/gradle-dependencies-graph.gradle b/platform/android/gradle/gradle-dependencies-graph.gradle
new file mode 100644
index 0000000000..5cbc7b974f
--- /dev/null
+++ b/platform/android/gradle/gradle-dependencies-graph.gradle
@@ -0,0 +1,29 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ }
+
+ dependencies {
+ classpath "com.vanniktech:gradle-dependency-graph-generator-plugin:0.3.0"
+ }
+}
+
+import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorPlugin
+import com.vanniktech.dependency.graph.generator.DependencyGraphGeneratorExtension.Generator
+import com.vanniktech.dependency.graph.generator.dot.GraphFormattingOptions
+import com.vanniktech.dependency.graph.generator.dot.Color
+import com.vanniktech.dependency.graph.generator.dot.Shape
+import com.vanniktech.dependency.graph.generator.dot.Style
+
+plugins.apply(DependencyGraphGeneratorPlugin)
+
+def mapboxGenerator = new Generator(
+ "mapboxLibraries", // Suffix for our Gradle task.
+ "", // Root suffix that we don't want in this case.
+ { dependency -> dependency.getModuleGroup().startsWith("com.mapbox.mapboxsdk") }, // Only want Mapbox libs.
+ { dependency -> true }, // Include transitive dependencies.
+)
+
+dependencyGraphGenerator {
+ generators = [mapboxGenerator]
+}
diff --git a/platform/android/scripts/exclude-activity-gen.json b/platform/android/scripts/exclude-activity-gen.json
index eff7fb9cbf..157808aa51 100644
--- a/platform/android/scripts/exclude-activity-gen.json
+++ b/platform/android/scripts/exclude-activity-gen.json
@@ -18,7 +18,7 @@
"LocationPickerActivity",
"GeoJsonClusteringActivity",
"RuntimeStyleTestActivity",
- "AnimatedMarkerActivity",
+ "AnimatedSymbolLayerActivity",
"ViewPagerActivity",
"MapFragmentActivity",
"SupportMapFragmentActivity",
diff --git a/platform/android/scripts/generate-style-code.js b/platform/android/scripts/generate-style-code.js
index 3b0363cc19..05ca957974 100755
--- a/platform/android/scripts/generate-style-code.js
+++ b/platform/android/scripts/generate-style-code.js
@@ -267,19 +267,17 @@ global.propertyValueDoc = function (property, value) {
return doc;
};
-global.isDataDriven = function (property) {
- return property['property-function'] === true;
-};
-
global.isLightProperty = function (property) {
return property['light-property'] === true;
};
global.propertyValueType = function (property) {
- if (isDataDriven(property)) {
- return `DataDrivenPropertyValue<${evaluatedType(property)}>`;
- } else {
- return `PropertyValue<${evaluatedType(property)}>`;
+ switch (property['property-type']) {
+ case 'data-driven':
+ case 'cross-faded-data-driven':
+ return `DataDrivenPropertyValue<${evaluatedType(property)}>`;
+ default:
+ return `PropertyValue<${evaluatedType(property)}>`;
}
};
@@ -318,11 +316,11 @@ global.evaluatedType = function (property) {
};
global.supportsZoomFunction = function (property) {
- return property['zoom-function'] === true;
+ return property.expression && property.expression.parameters.indexOf('zoom') > -1;
};
global.supportsPropertyFunction = function (property) {
- return property['property-function'] === true;
+ return property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven';
};
// Template processing //
diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp
index d8d715dbd3..58a91f6cf0 100644
--- a/platform/android/src/file_source.cpp
+++ b/platform/android/src/file_source.cpp
@@ -83,6 +83,13 @@ void FileSource::pause(jni::JNIEnv&) {
}
}
+jni::jboolean FileSource::isResumed(jni::JNIEnv&) {
+ if (activationCounter) {
+ return (jboolean) (activationCounter > 0);
+ }
+ return (jboolean) false;
+}
+
jni::Class<FileSource> FileSource::javaClass;
FileSource* FileSource::getNativePeer(jni::JNIEnv& env, jni::Object<FileSource> jFileSource) {
@@ -114,7 +121,8 @@ void FileSource::registerNative(jni::JNIEnv& env) {
METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"),
METHOD(&FileSource::setResourceTransform, "setResourceTransform"),
METHOD(&FileSource::resume, "activate"),
- METHOD(&FileSource::pause, "deactivate")
+ METHOD(&FileSource::pause, "deactivate"),
+ METHOD(&FileSource::isResumed, "isActivated")
);
}
diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp
index 194f784622..e4295e1b84 100644
--- a/platform/android/src/file_source.hpp
+++ b/platform/android/src/file_source.hpp
@@ -45,6 +45,8 @@ public:
void pause(jni::JNIEnv&);
+ jni::jboolean isResumed(jni::JNIEnv&);
+
static jni::Class<FileSource> javaClass;
static FileSource* getNativePeer(jni::JNIEnv&, jni::Object<FileSource>);
diff --git a/platform/android/src/geojson/point.cpp b/platform/android/src/geojson/point.cpp
index aa9dc1a7f6..8a9656ea14 100644
--- a/platform/android/src/geojson/point.cpp
+++ b/platform/android/src/geojson/point.cpp
@@ -59,4 +59,4 @@ jni::Class<Point> Point::javaClass;
} // namespace geojson
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/darwin/scripts/generate-style-code.js b/platform/darwin/scripts/generate-style-code.js
index e4e4d3dcc1..9089e57ad5 100755
--- a/platform/darwin/scripts/generate-style-code.js
+++ b/platform/darwin/scripts/generate-style-code.js
@@ -318,10 +318,11 @@ global.propertyDoc = function (propertyName, property, layerType, kind) {
doc += '* Predefined functions, including mathematical and string operators\n' +
'* Conditional expressions\n' +
'* Variable assignments and references to assigned variables\n';
- const inputVariable = property.name === 'heatmap-color' ? '$heatmapDensity' : '$zoomLevel';
- if (property["property-function"]) {
+ const inputVariable = property.expression && property['property-type'] === 'color-ramp' ?
+ '$' + camelizeWithLeadingLowercase(property.expression.parameters[0]) : '$zoomLevel';
+ if (isDataDriven(property)) {
doc += `* Interpolation and step functions applied to the \`${inputVariable}\` variable and/or feature attributes\n`;
- } else if (property.function === "interpolated") {
+ } else if (property.expression && property.expression.interpolated) {
doc += `* Interpolation and step functions applied to the \`${inputVariable}\` variable\n\n` +
'This property does not support applying interpolation or step functions to feature attributes.';
} else {
@@ -332,6 +333,10 @@ global.propertyDoc = function (propertyName, property, layerType, kind) {
return doc;
};
+global.isDataDriven = function (property) {
+ return property['property-type'] === 'data-driven' || property['property-type'] === 'cross-faded-data-driven';
+};
+
global.propertyReqs = function (property, propertiesByName, type) {
return 'This property is only applied to the style if ' + property.requires.map(function (req) {
if (typeof req === 'string') {
diff --git a/platform/darwin/src/MGLAttributionInfo.mm b/platform/darwin/src/MGLAttributionInfo.mm
index 07d10e852b..e8d6a203d0 100644
--- a/platform/darwin/src/MGLAttributionInfo.mm
+++ b/platform/darwin/src/MGLAttributionInfo.mm
@@ -16,7 +16,7 @@
@implementation MGLAttributionInfo
-+ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
++ (NSArray<MGLAttributionInfo *> *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
if (!htmlString) {
return @[];
}
@@ -112,7 +112,7 @@
return infos;
}
-+ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos {
++ (NSAttributedString *)attributedStringForAttributionInfos:(NSArray<MGLAttributionInfo *> *)attributionInfos {
NSMutableArray *titles = [NSMutableArray arrayWithCapacity:attributionInfos.count];
for (MGLAttributionInfo *info in attributionInfos) {
NSMutableAttributedString *title = info.title.mutableCopy;
@@ -259,7 +259,7 @@
}
}
-- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos {
+- (void)growArrayByAddingAttributionInfosFromArray:(NSArray<MGLAttributionInfo *> *)infos {
for (MGLAttributionInfo *info in infos) {
[self growArrayByAddingAttributionInfo:info];
}
diff --git a/platform/darwin/src/MGLAttributionInfo_Private.h b/platform/darwin/src/MGLAttributionInfo_Private.h
index c639752ac3..85c9ed796f 100644
--- a/platform/darwin/src/MGLAttributionInfo_Private.h
+++ b/platform/darwin/src/MGLAttributionInfo_Private.h
@@ -16,9 +16,9 @@ NS_ASSUME_NONNULL_BEGIN
@param fontSize The default text size in points.
@param linkColor The default link color.
*/
-+ (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
++ (NSArray<MGLAttributionInfo *> *)attributionInfosFromHTMLString:(nullable NSString *)htmlString fontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
-+ (NSAttributedString *)attributedStringForAttributionInfos:(NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos;
++ (NSAttributedString *)attributedStringForAttributionInfos:(NSArray<MGLAttributionInfo *> *)attributionInfos;
/**
Returns a copy of the `URL` property modified to account for the given style
@@ -58,7 +58,7 @@ NS_ASSUME_NONNULL_BEGIN
@param infos An array of info objects to add to the receiver.
*/
-- (void)growArrayByAddingAttributionInfosFromArray:(NS_ARRAY_OF(MGLAttributionInfo *) *)infos;
+- (void)growArrayByAddingAttributionInfosFromArray:(NSArray<MGLAttributionInfo *> *)infos;
@end
diff --git a/platform/darwin/src/MGLCompassDirectionFormatter.m b/platform/darwin/src/MGLCompassDirectionFormatter.m
index 5f0cfae6f7..1ac6a82162 100644
--- a/platform/darwin/src/MGLCompassDirectionFormatter.m
+++ b/platform/darwin/src/MGLCompassDirectionFormatter.m
@@ -15,8 +15,8 @@
}
- (NSString *)stringFromDirection:(CLLocationDirection)direction {
- static NS_ARRAY_OF(NSString *) *shortStrings;
- static NS_ARRAY_OF(NSString *) *longStrings;
+ static NSArray<NSString *> *shortStrings;
+ static NSArray<NSString *> *longStrings;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
shortStrings = @[
diff --git a/platform/darwin/src/MGLComputedShapeSource.h b/platform/darwin/src/MGLComputedShapeSource.h
index 068c49245c..7e0037df89 100644
--- a/platform/darwin/src/MGLComputedShapeSource.h
+++ b/platform/darwin/src/MGLComputedShapeSource.h
@@ -101,7 +101,7 @@ MGL_EXPORT
@param identifier A string that uniquely identifies the source.
@param options An `NSDictionary` of options for this source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
/**
Returns a custom shape data source initialized with an identifier, data source, and a
@@ -120,7 +120,7 @@ MGL_EXPORT
@param identifier A string that uniquely identifies the source.
@param options An `NSDictionary` of options for this source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options;
/**
Invalidates all the features and properties intersecting with or contained in
diff --git a/platform/darwin/src/MGLComputedShapeSource.mm b/platform/darwin/src/MGLComputedShapeSource.mm
index fb25eb8eb4..04734d0ef5 100644
--- a/platform/darwin/src/MGLComputedShapeSource.mm
+++ b/platform/darwin/src/MGLComputedShapeSource.mm
@@ -13,7 +13,7 @@
const MGLShapeSourceOption MGLShapeSourceOptionWrapsCoordinates = @"MGLShapeSourceOptionWrapsCoordinates";
const MGLShapeSourceOption MGLShapeSourceOptionClipsCoordinates = @"MGLShapeSourceOptionClipsCoordinates";
-mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) {
+mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NSDictionary<MGLShapeSourceOption, id> *options) {
mbgl::style::CustomGeometrySource::Options sourceOptions;
if (NSNumber *value = options[MGLShapeSourceOptionMinimumZoomLevel]) {
@@ -148,7 +148,7 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi
@implementation MGLComputedShapeSource
-- (instancetype)initWithIdentifier:(NSString *)identifier options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier options:(NSDictionary<MGLShapeSourceOption, id> *)options {
NSOperationQueue *requestQueue = [[NSOperationQueue alloc] init];
requestQueue.name = [NSString stringWithFormat:@"mgl.MGLComputedShapeSource.%@", identifier];
requestQueue.qualityOfService = NSQualityOfServiceUtility;
@@ -176,7 +176,7 @@ mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDi
return self;
}
-- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier dataSource:(id<MGLComputedShapeSourceDataSource>)dataSource options:(NSDictionary<MGLShapeSourceOption, id> *)options {
if (self = [self initWithIdentifier:identifier options:options]) {
[self setDataSource:dataSource];
}
diff --git a/platform/darwin/src/MGLComputedShapeSource_Private.h b/platform/darwin/src/MGLComputedShapeSource_Private.h
index e1887caf8d..ec075e4bd7 100644
--- a/platform/darwin/src/MGLComputedShapeSource_Private.h
+++ b/platform/darwin/src/MGLComputedShapeSource_Private.h
@@ -7,6 +7,6 @@
NS_ASSUME_NONNULL_BEGIN
MGL_EXPORT
-mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options);
+mbgl::style::CustomGeometrySource::Options MBGLCustomGeometrySourceOptionsFromDictionary(NSDictionary<MGLShapeSourceOption, id> *options);
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLFeature.h b/platform/darwin/src/MGLFeature.h
index d0c9e26062..62471abb16 100644
--- a/platform/darwin/src/MGLFeature.h
+++ b/platform/darwin/src/MGLFeature.h
@@ -148,7 +148,7 @@ NS_ASSUME_NONNULL_BEGIN
when the feature instance is used to initialize an `MGLShapeSource` and that
source is added to the map and styled.
*/
-@property (nonatomic, copy) NS_DICTIONARY_OF(NSString *, id) *attributes;
+@property (nonatomic, copy) NSDictionary<NSString *, id> *attributes;
/**
Returns the feature attribute for the given attribute name.
@@ -167,7 +167,7 @@ NS_ASSUME_NONNULL_BEGIN
`attributes` property, and an `id` key corresponding to the receiver’s
`identifier` property.
*/
-- (NS_DICTIONARY_OF(NSString *, id) *)geoJSONDictionary;
+- (NSDictionary<NSString *, id> *)geoJSONDictionary;
@end
@@ -252,9 +252,9 @@ MGL_EXPORT
MGL_EXPORT
@interface MGLShapeCollectionFeature : MGLShapeCollection <MGLFeature>
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLShape<MGLFeature> *) *shapes;
+@property (nonatomic, copy, readonly) NSArray<MGLShape<MGLFeature> *> *shapes;
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)shapes;
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape<MGLFeature> *> *)shapes;
@end
diff --git a/platform/darwin/src/MGLFeature.mm b/platform/darwin/src/MGLFeature.mm
index ee2c71be21..02f67dca6e 100644
--- a/platform/darwin/src/MGLFeature.mm
+++ b/platform/darwin/src/MGLFeature.mm
@@ -233,7 +233,7 @@ MGL_DEFINE_FEATURE_IS_EQUAL();
@dynamic shapes;
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)shapes {
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape<MGLFeature> *> *)shapes {
return [super shapeCollectionWithShapes:shapes];
}
@@ -373,7 +373,7 @@ public:
}
};
-NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) {
+NSArray<MGLShape <MGLFeature> *> *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features) {
NSMutableArray *shapes = [NSMutableArray arrayWithCapacity:features.size()];
for (const auto &feature : features) {
[shapes addObject:MGLFeatureFromMBGLFeature(feature)];
@@ -414,7 +414,7 @@ mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *at
return feature;
}
-NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier) {
+NSDictionary<NSString *, id> *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier) {
NSMutableDictionary *feature = [@{@"type": @"Feature",
@"properties": (attributes) ?: [NSNull null],
@"geometry": geometry} mutableCopy];
diff --git a/platform/darwin/src/MGLFeature_Private.h b/platform/darwin/src/MGLFeature_Private.h
index 4137200b98..d4074b53ed 100644
--- a/platform/darwin/src/MGLFeature_Private.h
+++ b/platform/darwin/src/MGLFeature_Private.h
@@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN
vector tile features.
*/
MGL_EXPORT
-NS_ARRAY_OF(MGLShape <MGLFeature> *) *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features);
+NSArray<MGLShape <MGLFeature> *> *MGLFeaturesFromMBGLFeatures(const std::vector<mbgl::Feature> &features);
/**
Returns an `MGLFeature` object converted from the given mbgl::Feature
@@ -36,7 +36,7 @@ mbgl::Feature mbglFeature(mbgl::Feature feature, id identifier, NSDictionary *at
/**
Returns an `NSDictionary` representation of an `MGLFeature`.
*/
-NS_DICTIONARY_OF(NSString *, id) *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier);
+NSDictionary<NSString *, id> *NSDictionaryFeatureForGeometry(NSDictionary *geometry, NSDictionary *attributes, id identifier);
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h
index ea19cf13cc..af82482c62 100644
--- a/platform/darwin/src/MGLFillStyleLayer.h
+++ b/platform/darwin/src/MGLFillStyleLayer.h
@@ -218,7 +218,8 @@ MGL_EXPORT
/**
Name of image in sprite to use for drawing image fills. For seamless patterns,
- image width and height must be a factor of two (2, 4, 8, ..., 512).
+ image width and height must be a factor of two (2, 4, 8, ..., 512). Note that
+ zoom-dependent expressions will be evaluated only at integer zoom levels.
You can set this property to an expression containing any of the following:
diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h
index 9620ec438e..1080244bdb 100644
--- a/platform/darwin/src/MGLLineStyleLayer.h
+++ b/platform/darwin/src/MGLLineStyleLayer.h
@@ -302,7 +302,10 @@ MGL_EXPORT
/**
Specifies the lengths of the alternating dashes and gaps that form the dash
pattern. The lengths are later scaled by the line width. To convert a dash
- length to points, multiply the length by the current line width.
+ length to points, multiply the length by the current line width. Note that
+ GeoJSON sources with `lineMetrics: true` specified won't render dashed lines to
+ the expected scale. Also note that zoom-dependent expressions will be evaluated
+ only at integer zoom levels.
This property is measured in line widths.
diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm
index 6449a7fd4f..923c8fb2a1 100644
--- a/platform/darwin/src/MGLMapSnapshotter.mm
+++ b/platform/darwin/src/MGLMapSnapshotter.mm
@@ -89,7 +89,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
std::shared_ptr<mbgl::ThreadPool> _mbglThreadPool;
std::unique_ptr<mbgl::MapSnapshotter> _mbglMapSnapshotter;
std::unique_ptr<mbgl::Actor<mbgl::MapSnapshotter::Callback>> _snapshotCallback;
- NS_ARRAY_OF(MGLAttributionInfo *) *_attributionInfo;
+ NSArray<MGLAttributionInfo *> *_attributionInfo;
}
diff --git a/platform/darwin/src/MGLMultiPoint.mm b/platform/darwin/src/MGLMultiPoint.mm
index 75638fec97..d4518e3d8f 100644
--- a/platform/darwin/src/MGLMultiPoint.mm
+++ b/platform/darwin/src/MGLMultiPoint.mm
@@ -70,7 +70,7 @@
return _coordinates.size();
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingPointCount
++ (NSSet<NSString *> *)keyPathsForValuesAffectingPointCount
{
return [NSSet setWithObjects:@"coordinates", nil];
}
diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h
index a1f3e686c2..ab36592634 100644
--- a/platform/darwin/src/MGLOfflineStorage.h
+++ b/platform/darwin/src/MGLOfflineStorage.h
@@ -199,7 +199,7 @@ MGL_EXPORT
`packs` property, observe KVO change notifications on the `packs` key path.
The initial load results in an `NSKeyValueChangeSetting` change.
*/
-@property (nonatomic, strong, readonly, nullable) NS_ARRAY_OF(MGLOfflinePack *) *packs;
+@property (nonatomic, strong, readonly, nullable) NSArray<MGLOfflinePack *> *packs;
/**
Creates and registers an offline pack that downloads the resources needed to
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 4d999144e8..f4e454534d 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -32,7 +32,7 @@ const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"Maximu
@interface MGLOfflineStorage ()
-@property (nonatomic, strong, readwrite) NS_MUTABLE_ARRAY_OF(MGLOfflinePack *) *packs;
+@property (nonatomic, strong, readwrite) NSMutableArray<MGLOfflinePack *> *packs;
@property (nonatomic) mbgl::DefaultFileSource *mbglFileSource;
@property (nonatomic, getter=isPaused) BOOL paused;
@@ -243,7 +243,7 @@ const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"Maximu
_mbglFileSource = nullptr;
}
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NS_DICTIONARY_OF(NSString *, id) *)change context:(void *)context {
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context {
// Synchronize the file source’s access token with the global one in MGLAccountManager.
if ([keyPath isEqualToString:@"accessToken"] && object == [MGLAccountManager sharedManager]) {
NSString *accessToken = change[NSKeyValueChangeNewKey];
@@ -336,7 +336,7 @@ const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"Maximu
}
- (void)reloadPacks {
- [self getPacksWithCompletionHandler:^(NS_ARRAY_OF(MGLOfflinePack *) *packs, __unused NSError * _Nullable error) {
+ [self getPacksWithCompletionHandler:^(NSArray<MGLOfflinePack *> *packs, __unused NSError * _Nullable error) {
for (MGLOfflinePack *pack in self.packs) {
[pack invalidate];
}
@@ -344,7 +344,7 @@ const MGLOfflinePackUserInfoKey MGLOfflinePackUserInfoKeyMaximumCount = @"Maximu
}];
}
-- (void)getPacksWithCompletionHandler:(void (^)(NS_ARRAY_OF(MGLOfflinePack *) *packs, NSError * _Nullable error))completion {
+- (void)getPacksWithCompletionHandler:(void (^)(NSArray<MGLOfflinePack *> *packs, NSError * _Nullable error))completion {
self.mbglFileSource->listOfflineRegions([&, completion](std::exception_ptr exception, mbgl::optional<std::vector<mbgl::OfflineRegion>> regions) {
NSError *error;
if (exception) {
diff --git a/platform/darwin/src/MGLPolygon.h b/platform/darwin/src/MGLPolygon.h
index 190b6df9c5..810a8b78ae 100644
--- a/platform/darwin/src/MGLPolygon.h
+++ b/platform/darwin/src/MGLPolygon.h
@@ -57,7 +57,7 @@ MGL_EXPORT
If there are no interior polygons, the value of this property is `nil`.
*/
-@property (nonatomic, nullable, readonly) NS_ARRAY_OF(MGLPolygon *) *interiorPolygons;
+@property (nonatomic, nullable, readonly) NSArray<MGLPolygon *> *interiorPolygons;
/**
Creates and returns an `MGLPolygon` object from the specified set of
@@ -82,7 +82,7 @@ MGL_EXPORT
is considered to have no interior polygons.
@return A new polygon object.
*/
-+ (instancetype)polygonWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(nullable NS_ARRAY_OF(MGLPolygon *) *)interiorPolygons;
++ (instancetype)polygonWithCoordinates:(const CLLocationCoordinate2D *)coords count:(NSUInteger)count interiorPolygons:(nullable NSArray<MGLPolygon *> *)interiorPolygons;
@end
@@ -109,7 +109,7 @@ MGL_EXPORT
/**
An array of polygons forming the multipolygon.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLPolygon *) *polygons;
+@property (nonatomic, copy, readonly) NSArray<MGLPolygon *> *polygons;
/**
Creates and returns a multipolygon object consisting of the given polygons.
@@ -117,7 +117,7 @@ MGL_EXPORT
@param polygons The array of polygons defining the shape.
@return A new multipolygon object.
*/
-+ (instancetype)multiPolygonWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons;
++ (instancetype)multiPolygonWithPolygons:(NSArray<MGLPolygon *> *)polygons;
@end
diff --git a/platform/darwin/src/MGLPolygon.mm b/platform/darwin/src/MGLPolygon.mm
index 2af768d514..b80504707b 100644
--- a/platform/darwin/src/MGLPolygon.mm
+++ b/platform/darwin/src/MGLPolygon.mm
@@ -102,7 +102,7 @@
@"coordinates": self.mgl_coordinates};
}
-- (NS_ARRAY_OF(id) *)mgl_coordinates {
+- (NSArray<id> *)mgl_coordinates {
NSMutableArray *coordinates = [NSMutableArray array];
NSMutableArray *exteriorRing = [NSMutableArray array];
@@ -128,7 +128,7 @@
@interface MGLMultiPolygon ()
-@property (nonatomic, copy, readwrite) NS_ARRAY_OF(MGLPolygon *) *polygons;
+@property (nonatomic, copy, readwrite) NSArray<MGLPolygon *> *polygons;
@end
@@ -138,11 +138,11 @@
@synthesize overlayBounds = _overlayBounds;
-+ (instancetype)multiPolygonWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons {
++ (instancetype)multiPolygonWithPolygons:(NSArray<MGLPolygon *> *)polygons {
return [[self alloc] initWithPolygons:polygons];
}
-- (instancetype)initWithPolygons:(NS_ARRAY_OF(MGLPolygon *) *)polygons {
+- (instancetype)initWithPolygons:(NSArray<MGLPolygon *> *)polygons {
if (self = [super init]) {
_polygons = polygons;
diff --git a/platform/darwin/src/MGLPolygon_Private.h b/platform/darwin/src/MGLPolygon_Private.h
index 75afcd61f6..b006f2d77f 100644
--- a/platform/darwin/src/MGLPolygon_Private.h
+++ b/platform/darwin/src/MGLPolygon_Private.h
@@ -4,7 +4,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLPolygon (Private)
-- (NS_ARRAY_OF(id) *)mgl_coordinates;
+- (NSArray<id> *)mgl_coordinates;
@end
diff --git a/platform/darwin/src/MGLPolyline.h b/platform/darwin/src/MGLPolyline.h
index b1fca5bf28..8e9007686b 100644
--- a/platform/darwin/src/MGLPolyline.h
+++ b/platform/darwin/src/MGLPolyline.h
@@ -92,7 +92,7 @@ MGL_EXPORT
/**
An array of polygons forming the multipolyline.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLPolyline *) *polylines;
+@property (nonatomic, copy, readonly) NSArray<MGLPolyline *> *polylines;
/**
Creates and returns a multipolyline object consisting of the given polylines.
@@ -100,7 +100,7 @@ MGL_EXPORT
@param polylines The array of polylines defining the shape.
@return A new multipolyline object.
*/
-+ (instancetype)multiPolylineWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines;
++ (instancetype)multiPolylineWithPolylines:(NSArray<MGLPolyline *> *)polylines;
@end
diff --git a/platform/darwin/src/MGLPolyline.mm b/platform/darwin/src/MGLPolyline.mm
index 26e3518cd8..a028db8176 100644
--- a/platform/darwin/src/MGLPolyline.mm
+++ b/platform/darwin/src/MGLPolyline.mm
@@ -49,7 +49,7 @@
@"coordinates": self.mgl_coordinates};
}
-- (NS_ARRAY_OF(id) *)mgl_coordinates {
+- (NSArray<id> *)mgl_coordinates {
NSMutableArray *coordinates = [[NSMutableArray alloc] initWithCapacity:self.pointCount];
for (NSUInteger index = 0; index < self.pointCount; index++) {
CLLocationCoordinate2D coordinate = self.coordinates[index];
@@ -123,7 +123,7 @@
@interface MGLMultiPolyline ()
-@property (nonatomic, copy, readwrite) NS_ARRAY_OF(MGLPolyline *) *polylines;
+@property (nonatomic, copy, readwrite) NSArray<MGLPolyline *> *polylines;
@end
@@ -133,11 +133,11 @@
@synthesize overlayBounds = _overlayBounds;
-+ (instancetype)multiPolylineWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines {
++ (instancetype)multiPolylineWithPolylines:(NSArray<MGLPolyline *> *)polylines {
return [[self alloc] initWithPolylines:polylines];
}
-- (instancetype)initWithPolylines:(NS_ARRAY_OF(MGLPolyline *) *)polylines {
+- (instancetype)initWithPolylines:(NSArray<MGLPolyline *> *)polylines {
if (self = [super init]) {
_polylines = polylines;
diff --git a/platform/darwin/src/MGLPolyline_Private.h b/platform/darwin/src/MGLPolyline_Private.h
index 405a0c5bc9..ff4fabaa78 100644
--- a/platform/darwin/src/MGLPolyline_Private.h
+++ b/platform/darwin/src/MGLPolyline_Private.h
@@ -4,7 +4,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLPolyline (Private)
-- (NS_ARRAY_OF(id) *)mgl_coordinates;
+- (NSArray<id> *)mgl_coordinates;
@end
diff --git a/platform/darwin/src/MGLRasterTileSource.h b/platform/darwin/src/MGLRasterTileSource.h
index 59b256d5e5..f27cbc285f 100644
--- a/platform/darwin/src/MGLRasterTileSource.h
+++ b/platform/darwin/src/MGLRasterTileSource.h
@@ -127,7 +127,7 @@ MGL_EXPORT
the default values.
@return An initialized tile source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
@end
diff --git a/platform/darwin/src/MGLRasterTileSource.mm b/platform/darwin/src/MGLRasterTileSource.mm
index 02cfef4ae8..61e9ef97fd 100644
--- a/platform/darwin/src/MGLRasterTileSource.mm
+++ b/platform/darwin/src/MGLRasterTileSource.mm
@@ -44,7 +44,7 @@ static const CGFloat MGLRasterTileSourceRetinaTileSize = 512;
uint16_t(round(tileSize)));
}
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options {
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
uint16_t tileSize = MGLRasterTileSourceRetinaTileSize;
diff --git a/platform/darwin/src/MGLShapeCollection.h b/platform/darwin/src/MGLShapeCollection.h
index bec482ca61..08f3276496 100644
--- a/platform/darwin/src/MGLShapeCollection.h
+++ b/platform/darwin/src/MGLShapeCollection.h
@@ -40,7 +40,7 @@ MGL_EXPORT
/**
An array of shapes forming the shape collection.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLShape *) *shapes;
+@property (nonatomic, copy, readonly) NSArray<MGLShape *> *shapes;
/**
Creates and returns a shape collection consisting of the given shapes.
@@ -49,7 +49,7 @@ MGL_EXPORT
this array is copied to the new object.
@return A new shape collection object.
*/
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes;
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape *> *)shapes;
@end
diff --git a/platform/darwin/src/MGLShapeCollection.mm b/platform/darwin/src/MGLShapeCollection.mm
index 03cab0043f..74e78a764a 100644
--- a/platform/darwin/src/MGLShapeCollection.mm
+++ b/platform/darwin/src/MGLShapeCollection.mm
@@ -6,11 +6,11 @@
@implementation MGLShapeCollection
-+ (instancetype)shapeCollectionWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes {
++ (instancetype)shapeCollectionWithShapes:(NSArray<MGLShape *> *)shapes {
return [[self alloc] initWithShapes:shapes];
}
-- (instancetype)initWithShapes:(NS_ARRAY_OF(MGLShape *) *)shapes {
+- (instancetype)initWithShapes:(NSArray<MGLShape *> *)shapes {
if (self = [super init]) {
_shapes = shapes.copy;
}
diff --git a/platform/darwin/src/MGLShapeSource.h b/platform/darwin/src/MGLShapeSource.h
index 6fa93476be..1fc00d4de0 100644
--- a/platform/darwin/src/MGLShapeSource.h
+++ b/platform/darwin/src/MGLShapeSource.h
@@ -154,7 +154,7 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
/**
Returns a shape source with an identifier, a shape, and dictionary of options
@@ -183,7 +183,7 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
/**
Returns a shape source with an identifier, an array of features, and a dictionary
@@ -210,7 +210,7 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<MGLShape<MGLFeature> *> *)features options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options;
/**
Returns a shape source with an identifier, an array of shapes, and a dictionary of
@@ -238,7 +238,7 @@ MGL_EXPORT
@param options An `NSDictionary` of options for this source.
@return An initialized shape source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options;
+- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NSArray<MGLShape *> *)shapes options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options;
#pragma mark Accessing a Source’s Content
@@ -291,7 +291,7 @@ MGL_EXPORT
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the source that match the predicate.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresMatchingPredicate:(nullable NSPredicate *)predicate;
+- (NSArray<id <MGLFeature>> *)featuresMatchingPredicate:(nullable NSPredicate *)predicate;
@end
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index af26b7ea13..1425269012 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -21,7 +21,7 @@ const MGLShapeSourceOption MGLShapeSourceOptionMaximumZoomLevelForClustering = @
const MGLShapeSourceOption MGLShapeSourceOptionMinimumZoomLevel = @"MGLShapeSourceOptionMinimumZoomLevel";
const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLShapeSourceOptionSimplificationTolerance";
-mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options) {
+mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary<MGLShapeSourceOption, id> *options) {
auto geoJSONOptions = mbgl::style::GeoJSONOptions();
if (NSNumber *value = options[MGLShapeSourceOptionMinimumZoomLevel]) {
@@ -92,7 +92,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGL
@implementation MGLShapeSource
-- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NS_DICTIONARY_OF(NSString *, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier URL:(NSURL *)url options:(NSDictionary<NSString *, id> *)options {
auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
if (self = [super initWithPendingSource:std::move(source)]) {
@@ -101,7 +101,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGL
return self;
}
-- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier shape:(nullable MGLShape *)shape options:(NSDictionary<MGLShapeSourceOption, id> *)options {
auto geoJSONOptions = MGLGeoJSONOptionsFromDictionary(options);
auto source = std::make_unique<mbgl::style::GeoJSONSource>(identifier.UTF8String, geoJSONOptions);
if (self = [super initWithPendingSource:std::move(source)]) {
@@ -110,7 +110,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGL
return self;
}
-- (instancetype)initWithIdentifier:(NSString *)identifier features:(NS_ARRAY_OF(MGLShape<MGLFeature> *) *)features options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier features:(NSArray<MGLShape<MGLFeature> *> *)features options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options {
for (id <MGLFeature> feature in features) {
if (![feature conformsToProtocol:@protocol(MGLFeature)]) {
[NSException raise:NSInvalidArgumentException format:@"The object %@ included in the features argument does not conform to the MGLFeature protocol.", feature];
@@ -120,7 +120,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGL
return [self initWithIdentifier:identifier shape:shapeCollectionFeature options:options];
}
-- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NS_ARRAY_OF(MGLShape *) *)shapes options:(nullable NS_DICTIONARY_OF(MGLShapeSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier shapes:(NSArray<MGLShape *> *)shapes options:(nullable NSDictionary<MGLShapeSourceOption, id> *)options {
MGLShapeCollection *shapeCollection = [MGLShapeCollection shapeCollectionWithShapes:shapes];
return [self initWithIdentifier:identifier shape:shapeCollection options:options];
}
@@ -153,7 +153,7 @@ mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGL
NSStringFromClass([self class]), (void *)self, self.identifier, self.URL, self.shape];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresMatchingPredicate:(nullable NSPredicate *)predicate {
+- (NSArray<id <MGLFeature>> *)featuresMatchingPredicate:(nullable NSPredicate *)predicate {
mbgl::optional<mbgl::style::Filter> optionalFilter;
if (predicate) {
diff --git a/platform/darwin/src/MGLShapeSource_Private.h b/platform/darwin/src/MGLShapeSource_Private.h
index 0720074d1d..83872afcbc 100644
--- a/platform/darwin/src/MGLShapeSource_Private.h
+++ b/platform/darwin/src/MGLShapeSource_Private.h
@@ -10,6 +10,6 @@ namespace mbgl {
}
MGL_EXPORT
-mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NS_DICTIONARY_OF(MGLShapeSourceOption, id) *options);
+mbgl::style::GeoJSONOptions MGLGeoJSONOptionsFromDictionary(NSDictionary<MGLShapeSourceOption, id> *options);
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index 6df627d7af..814a09ed21 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -241,7 +241,7 @@ MGL_EXPORT
/**
A set containing the style’s sources.
*/
-@property (nonatomic, strong) NS_SET_OF(__kindof MGLSource *) *sources;
+@property (nonatomic, strong) NSSet<__kindof MGLSource *> *sources;
/**
Values describing animated transitions to changes on a style's individual
@@ -303,7 +303,7 @@ MGL_EXPORT
The layers included in the style, arranged according to their back-to-front
ordering on the screen.
*/
-@property (nonatomic, strong) NS_ARRAY_OF(__kindof MGLStyleLayer *) *layers;
+@property (nonatomic, strong) NSArray<__kindof MGLStyleLayer *> *layers;
/**
Returns a style layer with the given identifier in the current style.
@@ -417,7 +417,7 @@ MGL_EXPORT
#pragma mark Managing Style Classes
-@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((unavailable("Support for style classes has been removed.")));
+@property (nonatomic) NSArray<NSString *> *styleClasses __attribute__((unavailable("Support for style classes has been removed.")));
- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((unavailable("Support for style classes has been removed.")));
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index 867ac6c451..3f9bfbf8ca 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -82,8 +82,8 @@
@property (nonatomic, readonly, weak) MGLMapView *mapView;
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
@property (readonly, copy, nullable) NSURL *URL;
-@property (nonatomic, readwrite, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers;
-@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, NS_DICTIONARY_OF(NSObject *, MGLTextLanguage *) *) *localizedLayersByIdentifier;
+@property (nonatomic, readwrite, strong) NSMutableDictionary<NSString *, MGLOpenGLStyleLayer *> *openGLLayers;
+@property (nonatomic) NSMutableDictionary<NSString *, NSDictionary<NSObject *, MGLTextLanguage *> *> *localizedLayersByIdentifier;
@end
@@ -142,9 +142,9 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
#pragma mark Sources
-- (NS_SET_OF(__kindof MGLSource *) *)sources {
+- (NSSet<__kindof MGLSource *> *)sources {
auto rawSources = self.rawStyle->getSources();
- NS_MUTABLE_SET_OF(__kindof MGLSource *) *sources = [NSMutableSet setWithCapacity:rawSources.size()];
+ NSMutableSet<__kindof MGLSource *> *sources = [NSMutableSet setWithCapacity:rawSources.size()];
for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) {
MGLSource *source = [self sourceFromMBGLSource:*rawSource];
[sources addObject:source];
@@ -152,7 +152,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
return sources;
}
-- (void)setSources:(NS_SET_OF(__kindof MGLSource *) *)sources {
+- (void)setSources:(NSSet<__kindof MGLSource *> *)sources {
for (MGLSource *source in self.sources) {
[self removeSource:source];
}
@@ -225,7 +225,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
[source removeFromMapView:self.mapView];
}
-- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
+- (nullable NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
// It’d be incredibly convenient to use -sources here, but this operation
// depends on the sources being sorted in ascending order by creation, as
// with the std::vector used in mbgl.
@@ -245,10 +245,10 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
#pragma mark Style layers
-- (NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers
+- (NSArray<__kindof MGLStyleLayer *> *)layers
{
auto layers = self.rawStyle->getLayers();
- NS_MUTABLE_ARRAY_OF(__kindof MGLStyleLayer *) *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
+ NSMutableArray<__kindof MGLStyleLayer *> *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
for (auto layer : layers) {
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
[styleLayers addObject:styleLayer];
@@ -256,7 +256,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
return styleLayers;
}
-- (void)setLayers:(NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers {
+- (void)setLayers:(NSArray<__kindof MGLStyleLayer *> *)layers {
for (MGLStyleLayer *layer in self.layers) {
[self removeLayer:layer];
}
@@ -594,13 +594,13 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
}
}
-- (NS_SET_OF(MGLVectorTileSource *) *)mapboxStreetsSources {
+- (NSSet<MGLVectorTileSource *> *)mapboxStreetsSources {
return [self.sources objectsPassingTest:^BOOL (__kindof MGLVectorTileSource * _Nonnull source, BOOL * _Nonnull stop) {
return [source isKindOfClass:[MGLVectorTileSource class]] && source.mapboxStreets;
}];
}
-- (NS_ARRAY_OF(MGLStyleLayer *) *)placeStyleLayers {
+- (NSArray<MGLStyleLayer *> *)placeStyleLayers {
NSSet *streetsSourceIdentifiers = [self.mapboxStreetsSources valueForKey:@"identifier"];
NSSet *placeSourceLayerIdentifiers = [NSSet setWithObjects:@"marine_label", @"country_label", @"state_label", @"place_label", @"water_label", @"poi_label", @"rail_station_label", @"mountain_peak_label", nil];
@@ -610,7 +610,7 @@ static_assert(6 == mbgl::util::default_styles::numOrderedStyles,
return [self.layers filteredArrayUsingPredicate:isPlacePredicate];
}
-- (NS_ARRAY_OF(MGLStyleLayer *) *)roadStyleLayers {
+- (NSArray<MGLStyleLayer *> *)roadStyleLayers {
NSSet *streetsSourceIdentifiers = [self.mapboxStreetsSources valueForKey:@"identifier"];
NSPredicate *isPlacePredicate = [NSPredicate predicateWithBlock:^BOOL (MGLVectorStyleLayer * _Nullable layer, NSDictionary<NSString *, id> * _Nullable bindings) {
diff --git a/platform/darwin/src/MGLStyleLayer.mm.ejs b/platform/darwin/src/MGLStyleLayer.mm.ejs
index e7589c1f62..f3e75b492c 100644
--- a/platform/darwin/src/MGLStyleLayer.mm.ejs
+++ b/platform/darwin/src/MGLStyleLayer.mm.ejs
@@ -121,7 +121,7 @@ namespace mbgl {
- (void)set<%- camelize(property.name) %>:(NSExpression *)<%- objCName(property) %> {
MGLAssertStyleLayerIsValid();
-<% if (property["property-function"]) { -%>
+<% if (isDataDriven(property)) { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
<% } else { -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::PropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
@@ -162,11 +162,15 @@ namespace mbgl {
- (void)set<%- camelize(property.name) %>:(NSExpression *)<%- objCName(property) %> {
MGLAssertStyleLayerIsValid();
-<% if (property.name === 'heatmap-color') { -%>
+<% switch (property['property-type']) {
+ case 'color-ramp': -%>
auto mbglValue = MGLStyleValueTransformer<mbgl::Color, MGLColor *>().toPropertyValue<mbgl::style::HeatmapColorPropertyValue>(heatmapColor);
-<% } else if (property["property-function"]) { -%>
+<% break
+ case 'data-driven':
+ case 'cross-faded-data-driven': -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::DataDrivenPropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
-<% } else { -%>
+<% break
+ default: -%>
auto mbglValue = MGLStyleValueTransformer<<%- valueTransformerArguments(property).join(', ') %>>().toPropertyValue<mbgl::style::PropertyValue<<%- valueTransformerArguments(property)[0] %>>>(<%- objCName(property) %>);
<% } -%>
self.rawLayer->set<%- camelize(originalPropertyName(property)) %>(mbglValue);
diff --git a/platform/darwin/src/MGLStyle_Private.h b/platform/darwin/src/MGLStyle_Private.h
index 24466b8018..1294b9ad1c 100644
--- a/platform/darwin/src/MGLStyle_Private.h
+++ b/platform/darwin/src/MGLStyle_Private.h
@@ -24,16 +24,16 @@ namespace mbgl {
@property (nonatomic, readonly, weak) MGLMapView *mapView;
@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
-- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
-@property (nonatomic, readonly, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers;
-- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration;
+- (nullable NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
+@property (nonatomic, readonly, strong) NSMutableDictionary<NSString *, MGLOpenGLStyleLayer *> *openGLLayers;
+- (void)setStyleClasses:(NSArray<NSString *> *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration;
@end
@interface MGLStyle (MGLStreetsAdditions)
-@property (nonatomic, readonly, copy) NS_ARRAY_OF(MGLVectorStyleLayer *) *placeStyleLayers;
-@property (nonatomic, readonly, copy) NS_ARRAY_OF(MGLVectorStyleLayer *) *roadStyleLayers;
+@property (nonatomic, readonly, copy) NSArray<MGLVectorStyleLayer *> *placeStyleLayers;
+@property (nonatomic, readonly, copy) NSArray<MGLVectorStyleLayer *> *roadStyleLayers;
@end
diff --git a/platform/darwin/src/MGLTileSource.h b/platform/darwin/src/MGLTileSource.h
index b0020e4a19..667e1e66ca 100644
--- a/platform/darwin/src/MGLTileSource.h
+++ b/platform/darwin/src/MGLTileSource.h
@@ -117,6 +117,7 @@ extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionAttributionInfos;
*/
extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionTileCoordinateSystem;
+
/**
Tile coordinate systems that determine how tile coordinates in tile URLs are
interpreted.
@@ -141,6 +142,18 @@ typedef NS_ENUM(NSUInteger, MGLTileCoordinateSystem) {
MGLTileCoordinateSystemTMS
};
+
+/**
+ An `NSNumber` object containing an unsigned integer that specifies the encoding
+ formula for raster-dem tilesets. The integer corresponds to one of
+ the constants described in `MGLDEMEncoding`.
+
+ The default value for this option is `MGLDEMEncodingMapbox`.
+
+ This option is not supported by the TileJSON spec.
+ */
+extern MGL_EXPORT const MGLTileSourceOption MGLTileSourceOptionDEMEncoding;
+
/**
The encoding formula used to generate the raster-dem tileset
*/
@@ -199,7 +212,7 @@ MGL_EXPORT
configuration URL, this array is also empty until the configuration JSON file
is loaded.
*/
-@property (nonatomic, copy, readonly) NS_ARRAY_OF(MGLAttributionInfo *) *attributionInfos;
+@property (nonatomic, copy, readonly) NSArray<MGLAttributionInfo *> *attributionInfos;
@end
diff --git a/platform/darwin/src/MGLTileSource.mm b/platform/darwin/src/MGLTileSource.mm
index 87ac5be9c2..2fafc6fb51 100644
--- a/platform/darwin/src/MGLTileSource.mm
+++ b/platform/darwin/src/MGLTileSource.mm
@@ -30,11 +30,11 @@ const MGLTileSourceOption MGLTileSourceOptionDEMEncoding = @"MGLTileSourceOption
return nil;
}
-- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfos {
+- (NSArray<MGLAttributionInfo *> *)attributionInfos {
return [self attributionInfosWithFontSize:0 linkColor:nil];
}
-- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
+- (NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
return [MGLAttributionInfo attributionInfosFromHTMLString:self.attributionHTMLString
fontSize:fontSize
linkColor:linkColor];
@@ -48,7 +48,7 @@ const MGLTileSourceOption MGLTileSourceOptionDEMEncoding = @"MGLTileSourceOption
@end
-mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTemplates, NS_DICTIONARY_OF(MGLTileSourceOption, id) * _Nullable options) {
+mbgl::Tileset MGLTileSetFromTileURLTemplates(NSArray<NSString *> *tileURLTemplates, NSDictionary<MGLTileSourceOption, id> * _Nullable options) {
mbgl::Tileset tileSet;
for (NSString *tileURLTemplate in tileURLTemplates) {
diff --git a/platform/darwin/src/MGLTileSource_Private.h b/platform/darwin/src/MGLTileSource_Private.h
index 0d9876d412..1b260ca86a 100644
--- a/platform/darwin/src/MGLTileSource_Private.h
+++ b/platform/darwin/src/MGLTileSource_Private.h
@@ -28,11 +28,11 @@ namespace mbgl {
@param fontSize The default text size in points, or 0 to use the default.
@param linkColor The default link color, or `nil` to use the default.
*/
-- (NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
+- (NSArray<MGLAttributionInfo *> *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
@end
MGL_EXPORT
-mbgl::Tileset MGLTileSetFromTileURLTemplates(NS_ARRAY_OF(NSString *) *tileURLTemplates, NS_DICTIONARY_OF(MGLTileSourceOption, id) * _Nullable options);
+mbgl::Tileset MGLTileSetFromTileURLTemplates(NSArray<NSString *> *tileURLTemplates, NSDictionary<MGLTileSourceOption, id> * _Nullable options);
NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLTypes.h b/platform/darwin/src/MGLTypes.h
index 5c32791c2f..fbc3a43ea2 100644
--- a/platform/darwin/src/MGLTypes.h
+++ b/platform/darwin/src/MGLTypes.h
@@ -111,23 +111,3 @@ NS_INLINE MGLTransition MGLTransitionMake(NSTimeInterval duration, NSTimeInterva
}
NS_ASSUME_NONNULL_END
-
-#ifndef NS_ARRAY_OF
- // Foundation collection classes adopted lightweight generics in iOS 9.0 and OS X 10.11 SDKs.
- #if __has_feature(objc_generics) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 90000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101100)
- /** Inserts a type specifier for a pointer to a lightweight generic with the given collection and object classes. Use a `*` for any non-`id` object classes but no `*` for the collection class. */
- #define NS_ARRAY_OF(ObjectClass...) NSArray <ObjectClass>
- #define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray <ObjectClass>
- #define NS_SET_OF(ObjectClass...) NSSet <ObjectClass>
- #define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet <ObjectClass>
- #define NS_DICTIONARY_OF(ObjectClass...) NSDictionary <ObjectClass>
- #define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary <ObjectClass>
- #else
- #define NS_ARRAY_OF(ObjectClass...) NSArray
- #define NS_MUTABLE_ARRAY_OF(ObjectClass...) NSMutableArray
- #define NS_SET_OF(ObjectClass...) NSSet
- #define NS_MUTABLE_SET_OF(ObjectClass...) NSMutableSet
- #define NS_DICTIONARY_OF(ObjectClass...) NSDictionary
- #define NS_MUTABLE_DICTIONARY_OF(ObjectClass...) NSMutableDictionary
- #endif
-#endif
diff --git a/platform/darwin/src/MGLVectorTileSource.h b/platform/darwin/src/MGLVectorTileSource.h
index 790c9d4d42..70d2f6e8ec 100644
--- a/platform/darwin/src/MGLVectorTileSource.h
+++ b/platform/darwin/src/MGLVectorTileSource.h
@@ -99,7 +99,7 @@ MGL_EXPORT
the default values.
@return An initialized tile source.
*/
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options NS_DESIGNATED_INITIALIZER;
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options NS_DESIGNATED_INITIALIZER;
#pragma mark Accessing a Source’s Content
@@ -138,7 +138,7 @@ MGL_EXPORT
@return An array of objects conforming to the `MGLFeature` protocol that
represent features loaded by the source that match the predicate.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresInSourceLayersWithIdentifiers:(NS_SET_OF(NSString *) *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(features(sourceLayerIdentifiers:predicate:));
+- (NSArray<id <MGLFeature>> *)featuresInSourceLayersWithIdentifiers:(NSSet<NSString *> *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(features(sourceLayerIdentifiers:predicate:));
@end
diff --git a/platform/darwin/src/MGLVectorTileSource.mm b/platform/darwin/src/MGLVectorTileSource.mm
index 6b9d857ad2..e55ed13060 100644
--- a/platform/darwin/src/MGLVectorTileSource.mm
+++ b/platform/darwin/src/MGLVectorTileSource.mm
@@ -27,7 +27,7 @@
return self = [super initWithPendingSource:std::move(source)];
}
-- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NS_ARRAY_OF(NSString *) *)tileURLTemplates options:(nullable NS_DICTIONARY_OF(MGLTileSourceOption, id) *)options {
+- (instancetype)initWithIdentifier:(NSString *)identifier tileURLTemplates:(NSArray<NSString *> *)tileURLTemplates options:(nullable NSDictionary<MGLTileSourceOption, id> *)options {
mbgl::Tileset tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, options);
auto source = std::make_unique<mbgl::style::VectorSource>(identifier.UTF8String, tileSet);
return self = [super initWithPendingSource:std::move(source)];
@@ -47,7 +47,7 @@
return attribution ? @(attribution->c_str()) : nil;
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)featuresInSourceLayersWithIdentifiers:(NS_SET_OF(NSString *) *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate {
+- (NSArray<id <MGLFeature>> *)featuresInSourceLayersWithIdentifiers:(NSSet<NSString *> *)sourceLayerIdentifiers predicate:(nullable NSPredicate *)predicate {
mbgl::optional<std::vector<std::string>> optionalSourceLayerIDs;
if (sourceLayerIdentifiers) {
@@ -93,9 +93,9 @@ static NSArray * const MGLMapboxStreetsAlternativeLanguages = @[
@"mul", @"ar", @"de", @"es", @"fr", @"pt", @"ru", @"zh", @"zh-Hans",
];
-+ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages {
++ (NSSet<NSString *> *)mapboxStreetsLanguages {
static dispatch_once_t onceToken;
- static NS_SET_OF(NSString *) *mapboxStreetsLanguages;
+ static NSSet<NSString *> *mapboxStreetsLanguages;
dispatch_once(&onceToken, ^{
mapboxStreetsLanguages = [NSSet setWithArray:MGLMapboxStreetsLanguages];
});
diff --git a/platform/darwin/src/MGLVectorTileSource_Private.h b/platform/darwin/src/MGLVectorTileSource_Private.h
index 109f66a432..8d287ae4c4 100644
--- a/platform/darwin/src/MGLVectorTileSource_Private.h
+++ b/platform/darwin/src/MGLVectorTileSource_Private.h
@@ -6,7 +6,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly, getter=isMapboxStreets) BOOL mapboxStreets;
-+ (NS_SET_OF(NSString *) *)mapboxStreetsLanguages;
++ (NSSet<NSString *> *)mapboxStreetsLanguages;
+ (nullable NSString *)preferredMapboxStreetsLanguage;
+ (nullable NSString *)preferredMapboxStreetsLanguageForPreferences:(NSArray<NSString *> *)preferencesArray;
diff --git a/platform/darwin/src/NSBundle+MGLAdditions.h b/platform/darwin/src/NSBundle+MGLAdditions.h
index ad5e9d5369..86dc27f22c 100644
--- a/platform/darwin/src/NSBundle+MGLAdditions.h
+++ b/platform/darwin/src/NSBundle+MGLAdditions.h
@@ -34,7 +34,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (nullable NSString *)mgl_frameworkBundleIdentifier;
-+ (nullable NS_DICTIONARY_OF(NSString *, id) *)mgl_frameworkInfoDictionary;
++ (nullable NSDictionary<NSString *, id> *)mgl_frameworkInfoDictionary;
+ (nullable NSString *)mgl_applicationBundleIdentifier;
diff --git a/platform/darwin/src/NSBundle+MGLAdditions.m b/platform/darwin/src/NSBundle+MGLAdditions.m
index f55059324e..37f78963d3 100644
--- a/platform/darwin/src/NSBundle+MGLAdditions.m
+++ b/platform/darwin/src/NSBundle+MGLAdditions.m
@@ -26,7 +26,7 @@
return self.mgl_frameworkInfoDictionary[@"CFBundleIdentifier"];
}
-+ (nullable NS_DICTIONARY_OF(NSString *, id) *)mgl_frameworkInfoDictionary {
++ (nullable NSDictionary<NSString *, id> *)mgl_frameworkInfoDictionary {
NSBundle *bundle = self.mgl_frameworkBundle;
return bundle.infoDictionary;
}
diff --git a/platform/darwin/src/NSExpression+MGLAdditions.mm b/platform/darwin/src/NSExpression+MGLAdditions.mm
index 6dde705d3c..be93b13f3c 100644
--- a/platform/darwin/src/NSExpression+MGLAdditions.mm
+++ b/platform/darwin/src/NSExpression+MGLAdditions.mm
@@ -403,7 +403,7 @@ static NSArray * const MGLTokenizedFunctions = @[
If no replacements take place, this method returns the original collection.
*/
-NS_ARRAY_OF(NSExpression *) *MGLCollectionByReplacingTokensWithKeyPaths(NS_ARRAY_OF(NSExpression *) *collection) {
+NSArray<NSExpression *> *MGLCollectionByReplacingTokensWithKeyPaths(NSArray<NSExpression *> *collection) {
__block NSMutableArray *upgradedCollection;
[collection enumerateObjectsUsingBlock:^(NSExpression * _Nonnull item, NSUInteger idx, BOOL * _Nonnull stop) {
NSExpression *upgradedItem = item.mgl_expressionByReplacingTokensWithKeyPaths;
@@ -424,7 +424,7 @@ NS_ARRAY_OF(NSExpression *) *MGLCollectionByReplacingTokensWithKeyPaths(NS_ARRAY
If no replacements take place, this method returns the original stop
dictionary.
*/
-NS_DICTIONARY_OF(NSNumber *, NSExpression *) *MGLStopDictionaryByReplacingTokensWithKeyPaths(NS_DICTIONARY_OF(NSNumber *, NSExpression *) *stops) {
+NSDictionary<NSNumber *, NSExpression *> *MGLStopDictionaryByReplacingTokensWithKeyPaths(NSDictionary<NSNumber *, NSExpression *> *stops) {
__block NSMutableDictionary *upgradedStops;
[stops enumerateKeysAndObjectsUsingBlock:^(id _Nonnull zoomLevel, NSExpression * _Nonnull value, BOOL * _Nonnull stop) {
if (![value isKindOfClass:[NSExpression class]]) {
@@ -665,11 +665,7 @@ NS_DICTIONARY_OF(NSNumber *, NSExpression *) *MGLStopDictionaryByReplacingTokens
}
+ (instancetype)mgl_expressionForConditional:(nonnull NSPredicate *)conditionPredicate trueExpression:(nonnull NSExpression *)trueExpression falseExpresssion:(nonnull NSExpression *)falseExpression {
- if (@available(iOS 9.0, *)) {
- return [NSExpression expressionForConditional:conditionPredicate trueExpression:trueExpression falseExpression:falseExpression];
- } else {
- return [NSExpression expressionForFunction:@"MGL_IF" arguments:@[[NSExpression expressionWithFormat:@"%@", conditionPredicate], trueExpression, falseExpression]];
- }
+ return [NSExpression expressionForConditional:conditionPredicate trueExpression:trueExpression falseExpression:falseExpression];
}
+ (instancetype)mgl_expressionForSteppingExpression:(nonnull NSExpression *)steppingExpression fromExpression:(nonnull NSExpression *)minimumExpression stops:(nonnull NSExpression *)stops {
@@ -936,12 +932,10 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
[arguments addObject:[NSExpression expressionWithMGLJSONObject:argumentObjects[index]]];
}
}
-
- if (@available(iOS 9.0, *)) {
- if (arguments.count == 3) {
- NSPredicate *conditional = [arguments.firstObject constantValue];
- return [NSExpression expressionForConditional:conditional trueExpression:arguments[1] falseExpression:arguments[2]];
- }
+
+ if (arguments.count == 3) {
+ NSPredicate *conditional = [arguments.firstObject constantValue];
+ return [NSExpression expressionForConditional:conditional trueExpression:arguments[1] falseExpression:arguments[2]];
}
return [NSExpression expressionForFunction:@"MGL_IF" arguments:arguments];
} else if ([op isEqualToString:@"match"]) {
@@ -1422,7 +1416,7 @@ NSArray *MGLSubexpressionsWithJSONObjects(NSArray *objects) {
If no localization takes place, this method returns the original collection.
*/
-NS_ARRAY_OF(NSExpression *) *MGLLocalizedCollection(NS_ARRAY_OF(NSExpression *) *collection, NSLocale * _Nullable locale) {
+NSArray<NSExpression *> *MGLLocalizedCollection(NSArray<NSExpression *> *collection, NSLocale * _Nullable locale) {
__block NSMutableArray *localizedCollection;
[collection enumerateObjectsUsingBlock:^(NSExpression * _Nonnull item, NSUInteger idx, BOOL * _Nonnull stop) {
NSExpression *localizedItem = [item mgl_expressionLocalizedIntoLocale:locale];
@@ -1442,7 +1436,7 @@ NS_ARRAY_OF(NSExpression *) *MGLLocalizedCollection(NS_ARRAY_OF(NSExpression *)
If no localization takes place, this method returns the original stop
dictionary.
*/
-NS_DICTIONARY_OF(NSNumber *, NSExpression *) *MGLLocalizedStopDictionary(NS_DICTIONARY_OF(NSNumber *, NSExpression *) *stops, NSLocale * _Nullable locale) {
+NSDictionary<NSNumber *, NSExpression *> *MGLLocalizedStopDictionary(NSDictionary<NSNumber *, NSExpression *> *stops, NSLocale * _Nullable locale) {
__block NSMutableDictionary *localizedStops;
[stops enumerateKeysAndObjectsUsingBlock:^(id _Nonnull zoomLevel, NSExpression * _Nonnull value, BOOL * _Nonnull stop) {
if (![value isKindOfClass:[NSExpression class]]) {
@@ -1507,16 +1501,14 @@ NS_DICTIONARY_OF(NSNumber *, NSExpression *) *MGLLocalizedStopDictionary(NS_DICT
}
case NSConditionalExpressionType: {
- if (@available(iOS 9.0, *)) {
- NSExpression *trueExpression = self.trueExpression;
- NSExpression *localizedTrueExpression = [trueExpression mgl_expressionLocalizedIntoLocale:locale];
- NSExpression *falseExpression = self.falseExpression;
- NSExpression *localizedFalseExpression = [falseExpression mgl_expressionLocalizedIntoLocale:locale];
- if (localizedTrueExpression != trueExpression || localizedFalseExpression != falseExpression) {
- return [NSExpression expressionForConditional:self.predicate
- trueExpression:localizedTrueExpression
- falseExpression:localizedFalseExpression];
- }
+ NSExpression *trueExpression = self.trueExpression;
+ NSExpression *localizedTrueExpression = [trueExpression mgl_expressionLocalizedIntoLocale:locale];
+ NSExpression *falseExpression = self.falseExpression;
+ NSExpression *localizedFalseExpression = [falseExpression mgl_expressionLocalizedIntoLocale:locale];
+ if (localizedTrueExpression != trueExpression || localizedFalseExpression != falseExpression) {
+ return [NSExpression expressionForConditional:self.predicate
+ trueExpression:localizedTrueExpression
+ falseExpression:localizedFalseExpression];
}
return self;
}
diff --git a/platform/darwin/src/NSString+MGLAdditions.h b/platform/darwin/src/NSString+MGLAdditions.h
index 75c593c10b..4888c7a00f 100644
--- a/platform/darwin/src/NSString+MGLAdditions.h
+++ b/platform/darwin/src/NSString+MGLAdditions.h
@@ -26,9 +26,6 @@ NS_ASSUME_NONNULL_BEGIN
Only supports scripts for languages used by Mapbox Streets.
- On iOS 8 or older, this will method will always return the untransliterated
- receiver.
-
@param script The four-letter code representing the name of the script, as
specified by ISO 15924.
*/
diff --git a/platform/darwin/src/NSString+MGLAdditions.m b/platform/darwin/src/NSString+MGLAdditions.m
index a61f229511..d645490eb3 100644
--- a/platform/darwin/src/NSString+MGLAdditions.m
+++ b/platform/darwin/src/NSString+MGLAdditions.m
@@ -17,14 +17,9 @@
- (NSString *)mgl_titleCasedStringWithLocale:(NSLocale *)locale {
NSMutableString *string = self.mutableCopy;
NSOrthography *orthography;
-#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000 || __MAC_OS_X_VERSION_MAX_ALLOWED >= 101300
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunguarded-availability-new"
- if ([NSOrthography respondsToSelector:@selector(defaultOrthographyForLanguage:)]) {
+ if (@available(iOS 11.0, macOS 10.13.0, *)) {
orthography = [NSOrthography defaultOrthographyForLanguage:locale.localeIdentifier];
}
-#pragma clang diagnostic pop
-#endif
[string enumerateLinguisticTagsInRange:string.mgl_wholeRange scheme:NSLinguisticTagSchemeLexicalClass options:0 orthography:orthography usingBlock:^(NSString * _Nonnull tag, NSRange tokenRange, NSRange sentenceRange, BOOL * _Nonnull stop) {
NSString *word = [string substringWithRange:tokenRange];
if (word.length > 3
@@ -46,22 +41,18 @@
}
- (NSString *)mgl_stringByTransliteratingIntoScript:(NSString *)script {
- if (@available(iOS 9.0, *)) {
- NSMutableString *string = self.mutableCopy;
- NSStringTransform transform;
- if ([script isEqualToString:@"Latn"]) {
- transform = NSStringTransformToLatin;
- } else if ([script isEqualToString:@"Hans"]) {
- // No transform available.
- } else if ([script isEqualToString:@"Cyrl"]) {
- transform = @"Any-Latin; Latin-Cyrillic";
- } else if ([script isEqualToString:@"Arab"]) {
- transform = @"Any-Latin; Latin-Arabic";
- }
- return transform ? [string stringByApplyingTransform:transform reverse:NO] : string;
- } else {
- return self;
+ NSMutableString *string = self.mutableCopy;
+ NSStringTransform transform;
+ if ([script isEqualToString:@"Latn"]) {
+ transform = NSStringTransformToLatin;
+ } else if ([script isEqualToString:@"Hans"]) {
+ // No transform available.
+ } else if ([script isEqualToString:@"Cyrl"]) {
+ transform = @"Any-Latin; Latin-Cyrillic";
+ } else if ([script isEqualToString:@"Arab"]) {
+ transform = @"Any-Latin; Latin-Arabic";
}
+ return transform ? [string stringByApplyingTransform:transform reverse:NO] : string;
}
@end
diff --git a/platform/darwin/test/MGLAttributionInfoTests.m b/platform/darwin/test/MGLAttributionInfoTests.m
index eccc6ceece..5961b61133 100644
--- a/platform/darwin/test/MGLAttributionInfoTests.m
+++ b/platform/darwin/test/MGLAttributionInfoTests.m
@@ -17,7 +17,7 @@
@"<a class=\"mapbox-improve-map\" href=\"https://www.mapbox.com/map-feedback/\" target=\"_blank\">Improve this map</a>",
};
- NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
+ NSMutableArray<MGLAttributionInfo *> *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:0
@@ -67,7 +67,7 @@
CGFloat fontSize = 72;
MGLColor *color = [MGLColor redColor];
- NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
+ NSMutableArray<MGLAttributionInfo *> *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:72
@@ -109,7 +109,7 @@
@"Hello World",
};
- NS_MUTABLE_ARRAY_OF(MGLAttributionInfo *) *infos = [NSMutableArray array];
+ NSMutableArray<MGLAttributionInfo *> *infos = [NSMutableArray array];
for (NSUInteger i = 0; i < sizeof(htmlStrings) / sizeof(htmlStrings[0]); i++) {
NSArray *subinfos = [MGLAttributionInfo attributionInfosFromHTMLString:htmlStrings[i]
fontSize:0
diff --git a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
index de8080f425..bf18b2d30e 100644
--- a/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
+++ b/platform/darwin/test/MGLBackgroundStyleLayerTests.mm
@@ -50,13 +50,12 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getBackgroundColor(), propertyValue,
@"Setting backgroundColor to a camera expression should update background-color.");
XCTAssertEqualObjects(layer.backgroundColor, functionExpression,
@"backgroundColor should round-trip camera expressions.");
-
layer.backgroundColor = nil;
XCTAssertTrue(rawLayer->getBackgroundColor().isUndefined(),
@@ -103,13 +102,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getBackgroundOpacity(), propertyValue,
@"Setting backgroundOpacity to a camera expression should update background-opacity.");
XCTAssertEqualObjects(layer.backgroundOpacity, functionExpression,
@"backgroundOpacity should round-trip camera expressions.");
-
layer.backgroundOpacity = nil;
XCTAssertTrue(rawLayer->getBackgroundOpacity().isUndefined(),
@@ -156,13 +154,12 @@
{ 18, "Background Pattern" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getBackgroundPattern(), propertyValue,
@"Setting backgroundPattern to a camera expression should update background-pattern.");
XCTAssertEqualObjects(layer.backgroundPattern, functionExpression,
@"backgroundPattern should round-trip camera expressions.");
-
layer.backgroundPattern = nil;
XCTAssertTrue(rawLayer->getBackgroundPattern().isUndefined(),
diff --git a/platform/darwin/test/MGLCircleStyleLayerTests.mm b/platform/darwin/test/MGLCircleStyleLayerTests.mm
index d7bf2a5afd..41f7238da2 100644
--- a/platform/darwin/test/MGLCircleStyleLayerTests.mm
+++ b/platform/darwin/test/MGLCircleStyleLayerTests.mm
@@ -71,7 +71,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleBlur(), propertyValue,
@"Setting circleBlur to a camera expression should update circle-blur.");
XCTAssertEqualObjects(layer.circleBlur, functionExpression,
@@ -102,7 +102,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleBlur, pedanticFunctionExpression,
@"circleBlur should round-trip camera-data expressions.");
-
layer.circleBlur = nil;
XCTAssertTrue(rawLayer->getCircleBlur().isUndefined(),
@@ -143,7 +142,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleColor(), propertyValue,
@"Setting circleColor to a camera expression should update circle-color.");
XCTAssertEqualObjects(layer.circleColor, functionExpression,
@@ -174,7 +173,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleColor, pedanticFunctionExpression,
@"circleColor should round-trip camera-data expressions.");
-
layer.circleColor = nil;
XCTAssertTrue(rawLayer->getCircleColor().isUndefined(),
@@ -215,7 +213,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleOpacity(), propertyValue,
@"Setting circleOpacity to a camera expression should update circle-opacity.");
XCTAssertEqualObjects(layer.circleOpacity, functionExpression,
@@ -246,7 +244,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleOpacity, pedanticFunctionExpression,
@"circleOpacity should round-trip camera-data expressions.");
-
layer.circleOpacity = nil;
XCTAssertTrue(rawLayer->getCircleOpacity().isUndefined(),
@@ -287,13 +284,12 @@
{ 18, mbgl::style::AlignmentType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCirclePitchAlignment(), propertyValue,
@"Setting circlePitchAlignment to a camera expression should update circle-pitch-alignment.");
XCTAssertEqualObjects(layer.circlePitchAlignment, functionExpression,
@"circlePitchAlignment should round-trip camera expressions.");
-
layer.circlePitchAlignment = nil;
XCTAssertTrue(rawLayer->getCirclePitchAlignment().isUndefined(),
@@ -331,7 +327,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleRadius(), propertyValue,
@"Setting circleRadius to a camera expression should update circle-radius.");
XCTAssertEqualObjects(layer.circleRadius, functionExpression,
@@ -362,7 +358,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleRadius, pedanticFunctionExpression,
@"circleRadius should round-trip camera-data expressions.");
-
layer.circleRadius = nil;
XCTAssertTrue(rawLayer->getCircleRadius().isUndefined(),
@@ -403,13 +398,12 @@
{ 18, mbgl::style::CirclePitchScaleType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::CirclePitchScaleType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCirclePitchScale(), propertyValue,
@"Setting circleScaleAlignment to a camera expression should update circle-pitch-scale.");
XCTAssertEqualObjects(layer.circleScaleAlignment, functionExpression,
@"circleScaleAlignment should round-trip camera expressions.");
-
layer.circleScaleAlignment = nil;
XCTAssertTrue(rawLayer->getCirclePitchScale().isUndefined(),
@@ -447,7 +441,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleStrokeColor(), propertyValue,
@"Setting circleStrokeColor to a camera expression should update circle-stroke-color.");
XCTAssertEqualObjects(layer.circleStrokeColor, functionExpression,
@@ -478,7 +472,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleStrokeColor, pedanticFunctionExpression,
@"circleStrokeColor should round-trip camera-data expressions.");
-
layer.circleStrokeColor = nil;
XCTAssertTrue(rawLayer->getCircleStrokeColor().isUndefined(),
@@ -519,7 +512,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleStrokeOpacity(), propertyValue,
@"Setting circleStrokeOpacity to a camera expression should update circle-stroke-opacity.");
XCTAssertEqualObjects(layer.circleStrokeOpacity, functionExpression,
@@ -550,7 +543,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleStrokeOpacity, pedanticFunctionExpression,
@"circleStrokeOpacity should round-trip camera-data expressions.");
-
layer.circleStrokeOpacity = nil;
XCTAssertTrue(rawLayer->getCircleStrokeOpacity().isUndefined(),
@@ -591,7 +583,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleStrokeWidth(), propertyValue,
@"Setting circleStrokeWidth to a camera expression should update circle-stroke-width.");
XCTAssertEqualObjects(layer.circleStrokeWidth, functionExpression,
@@ -622,7 +614,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.circleStrokeWidth, pedanticFunctionExpression,
@"circleStrokeWidth should round-trip camera-data expressions.");
-
layer.circleStrokeWidth = nil;
XCTAssertTrue(rawLayer->getCircleStrokeWidth().isUndefined(),
@@ -669,13 +660,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleTranslate(), propertyValue,
@"Setting circleTranslation to a camera expression should update circle-translate.");
XCTAssertEqualObjects(layer.circleTranslation, functionExpression,
@"circleTranslation should round-trip camera expressions.");
-
layer.circleTranslation = nil;
XCTAssertTrue(rawLayer->getCircleTranslate().isUndefined(),
@@ -713,13 +703,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getCircleTranslateAnchor(), propertyValue,
@"Setting circleTranslationAnchor to a camera expression should update circle-translate-anchor.");
XCTAssertEqualObjects(layer.circleTranslationAnchor, functionExpression,
@"circleTranslationAnchor should round-trip camera expressions.");
-
layer.circleTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getCircleTranslateAnchor().isUndefined(),
diff --git a/platform/darwin/test/MGLCoordinateFormatterTests.m b/platform/darwin/test/MGLCoordinateFormatterTests.m
index d693f739ec..ac083fa103 100644
--- a/platform/darwin/test/MGLCoordinateFormatterTests.m
+++ b/platform/darwin/test/MGLCoordinateFormatterTests.m
@@ -24,12 +24,7 @@
coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239);
XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"38°54′48″N, 77°1′57″W");
XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"38°54′48″ north, 77°1′57″ west");
- if (@available(iOS 9.0, *)) {
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees, 54 minutes, and 48 seconds north by 77 degrees, 1 minute, and 57 seconds west");
- } else {
- // Foundation in iOS 8 does not know how to pluralize coordinates.
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degree(s), 54 minute(s), and 48 second(s) north by 77 degree(s), 1 minute(s), and 57 second(s) west");
- }
+ XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees, 54 minutes, and 48 seconds north by 77 degrees, 1 minute, and 57 seconds west");
shortFormatter.allowsSeconds = NO;
mediumFormatter.allowsSeconds = NO;
@@ -38,12 +33,7 @@
coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239);
XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"38°55′N, 77°2′W");
XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"38°55′ north, 77°2′ west");
- if (@available(iOS 9.0, *)) {
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees and 55 minutes north by 77 degrees and 2 minutes west");
- } else {
- // Foundation in iOS 8 does not know how to pluralize coordinates.
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degree(s) and 55 minute(s) north by 77 degree(s) and 2 minute(s) west");
- }
+ XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"38 degrees and 55 minutes north by 77 degrees and 2 minutes west");
shortFormatter.allowsMinutes = NO;
mediumFormatter.allowsMinutes = NO;
@@ -52,12 +42,7 @@
coordinate = CLLocationCoordinate2DMake(38.9131982, -77.0325453144239);
XCTAssertEqualObjects([shortFormatter stringFromCoordinate:coordinate], @"39°N, 77°W");
XCTAssertEqualObjects([mediumFormatter stringFromCoordinate:coordinate], @"39° north, 77° west");
- if (@available(iOS 9.0, *)) {
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degrees north by 77 degrees west");
- } else {
- // Foundation in iOS 8 does not know how to pluralize coordinates.
- XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degree(s) north by 77 degree(s) west");
- }
+ XCTAssertEqualObjects([longFormatter stringFromCoordinate:coordinate], @"39 degrees north by 77 degrees west");
}
@end
diff --git a/platform/darwin/test/MGLExpressionTests.mm b/platform/darwin/test/MGLExpressionTests.mm
index 4ed1f61eb1..e514ec22a7 100644
--- a/platform/darwin/test/MGLExpressionTests.mm
+++ b/platform/darwin/test/MGLExpressionTests.mm
@@ -799,30 +799,26 @@ using namespace std::string_literals;
}
- (void)testConditionalExpressionObject {
- // This test crashes on iOS 8, which doesn't have `+[NSExpression expressionForConditional:trueExpression:falseExpression:]`.
- // https://github.com/mapbox/mapbox-gl-native/issues/11007
- if (@available(iOS 9.0, *)) {
- {
- NSPredicate *conditional = [NSPredicate predicateWithFormat:@"1 = 2"];
- NSExpression *trueExpression = [NSExpression expressionForConstantValue:@YES];
- NSExpression *falseExpression = [NSExpression expressionForConstantValue:@NO];
- NSExpression *expression = [NSExpression expressionForConditional:conditional trueExpression:trueExpression falseExpression:falseExpression];
- NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
- XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
- XCTAssertEqualObjects([NSExpression expressionWithFormat:@"TERNARY(1 = 2, TRUE, FALSE)"].mgl_jsonExpressionObject, jsonExpression);
- XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
- XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
- }
- {
- NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"];
- NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO];
- XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
- XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
- expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, TRUE, %@, TRUE, FALSE)",
- MGLConstantExpression([NSPredicate predicateWithFormat:@"0 = 1"]),
- MGLConstantExpression([NSPredicate predicateWithFormat:@"1 = 2"])];
- XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
- }
+ {
+ NSPredicate *conditional = [NSPredicate predicateWithFormat:@"1 = 2"];
+ NSExpression *trueExpression = [NSExpression expressionForConstantValue:@YES];
+ NSExpression *falseExpression = [NSExpression expressionForConstantValue:@NO];
+ NSExpression *expression = [NSExpression expressionForConditional:conditional trueExpression:trueExpression falseExpression:falseExpression];
+ NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([NSExpression expressionWithFormat:@"TERNARY(1 = 2, TRUE, FALSE)"].mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
+ }
+ {
+ NSExpression *expression = [NSExpression expressionWithFormat:@"TERNARY(0 = 1, TRUE, TERNARY(1 = 2, TRUE, FALSE))"];
+ NSArray *jsonExpression = @[@"case", @[@"==", @0, @1], @YES, @[@"==", @1, @2], @YES, @NO];
+ XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
+ XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
+ expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, TRUE, %@, TRUE, FALSE)",
+ MGLConstantExpression([NSPredicate predicateWithFormat:@"0 = 1"]),
+ MGLConstantExpression([NSPredicate predicateWithFormat:@"1 = 2"])];
+ XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
}
{
NSExpression *expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, %@, %@)",
@@ -833,9 +829,7 @@ using namespace std::string_literals;
NSArray *jsonExpression = @[@"case", @[@"==", @1, @2], @YES, @NO];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects(compatibilityExpression.mgl_jsonExpressionObject, jsonExpression);
- if (@available(iOS 9.0, *)) {
- expression = [NSExpression expressionWithFormat:@"TERNARY(1 = 2, YES, NO)"];
- }
+ expression = [NSExpression expressionWithFormat:@"TERNARY(1 = 2, YES, NO)"];
XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
XCTAssertEqualObjects([expression expressionValueWithObject:nil context:nil], @NO);
}
@@ -944,12 +938,7 @@ using namespace std::string_literals;
}
{
NSExpression *expression;
- if (@available(iOS 9.0, *)) {
- expression = [NSExpression expressionWithFormat:@"TERNARY(key != nil, 1, 0)"];
- } else {
- expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, 1, 0)",
- MGLConstantExpression([NSPredicate predicateWithFormat:@"key != nil"])];
- }
+ expression = [NSExpression expressionWithFormat:@"TERNARY(key != nil, 1, 0)"];
NSArray *jsonExpression = @[@"case", @[@"!=", @[@"get", @"key"], [NSNull null]], @1, @0];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
XCTAssertEqualObjects([NSExpression expressionWithMGLJSONObject:jsonExpression], expression);
@@ -959,13 +948,7 @@ using namespace std::string_literals;
{
NSDictionary *dictionary = @{@"key": @"🔑"};
NSExpression *expression;
- if (@available(iOS 9.0, *)) {
- expression = [NSExpression expressionWithFormat:@"TERNARY(%@.key != nil, 1, 0)", dictionary];
- } else {
- NSPredicate *conditional = [NSPredicate predicateWithFormat:@"%@.key != nil", dictionary];
- expression = [NSExpression expressionWithFormat:@"MGL_IF(%@, 1, 0)",
- MGLConstantExpression(conditional)];
- }
+ expression = [NSExpression expressionWithFormat:@"TERNARY(%@.key != nil, 1, 0)", dictionary];
NSArray *jsonExpression = @[@"case", @[@"!=", @[@"get", @"key", @[@"literal", dictionary]], [NSNull null]], @1, @0];
XCTAssertEqualObjects(expression.mgl_jsonExpressionObject, jsonExpression);
// The dictionary isn’t equal enough.
diff --git a/platform/darwin/test/MGLFeatureTests.mm b/platform/darwin/test/MGLFeatureTests.mm
index 14b64be854..d135b018f4 100644
--- a/platform/darwin/test/MGLFeatureTests.mm
+++ b/platform/darwin/test/MGLFeatureTests.mm
@@ -38,7 +38,7 @@
};
features.push_back(mbgl::Feature { polygon });
- NS_ARRAY_OF(MGLShape <MGLFeature> *) *shapes = MGLFeaturesFromMBGLFeatures(features);
+ NSArray<MGLShape <MGLFeature> *> *shapes = MGLFeaturesFromMBGLFeatures(features);
XCTAssertEqual(shapes.count, 3, @"All features should be converted into shapes");
MGLPointFeature *pointShape = (MGLPointFeature *)shapes[0];
@@ -69,7 +69,7 @@
[NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(4, 4)]);
XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:polygonCoordinates[3]],
[NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(4, 1)]);
- NS_ARRAY_OF(MGLPolygon *) *interiorPolygons = polygonShape.interiorPolygons;
+ NSArray<MGLPolygon *> *interiorPolygons = polygonShape.interiorPolygons;
XCTAssertEqual(interiorPolygons.count, 1);
MGLPolygon *interiorPolygon = interiorPolygons.firstObject;
XCTAssertEqual(interiorPolygon.pointCount, 4);
@@ -103,7 +103,7 @@
vector.push_back(true);
features.push_back(pointFeature);
- NS_ARRAY_OF(MGLShape <MGLFeature> *) *shapes = MGLFeaturesFromMBGLFeatures(features);
+ NSArray<MGLShape <MGLFeature> *> *shapes = MGLFeaturesFromMBGLFeatures(features);
XCTAssertEqual(shapes.count, 1, @"All features should be converted into shapes");
MGLShape <MGLFeature> *shape = shapes.firstObject;
diff --git a/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm b/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm
index 6081d104e1..ac858d0edc 100644
--- a/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm
+++ b/platform/darwin/test/MGLFillExtrusionStyleLayerTests.mm
@@ -71,7 +71,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionBase(), propertyValue,
@"Setting fillExtrusionBase to a camera expression should update fill-extrusion-base.");
XCTAssertEqualObjects(layer.fillExtrusionBase, functionExpression,
@@ -102,7 +102,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillExtrusionBase, pedanticFunctionExpression,
@"fillExtrusionBase should round-trip camera-data expressions.");
-
layer.fillExtrusionBase = nil;
XCTAssertTrue(rawLayer->getFillExtrusionBase().isUndefined(),
@@ -143,7 +142,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionColor(), propertyValue,
@"Setting fillExtrusionColor to a camera expression should update fill-extrusion-color.");
XCTAssertEqualObjects(layer.fillExtrusionColor, functionExpression,
@@ -174,7 +173,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillExtrusionColor, pedanticFunctionExpression,
@"fillExtrusionColor should round-trip camera-data expressions.");
-
layer.fillExtrusionColor = nil;
XCTAssertTrue(rawLayer->getFillExtrusionColor().isUndefined(),
@@ -215,7 +213,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionHeight(), propertyValue,
@"Setting fillExtrusionHeight to a camera expression should update fill-extrusion-height.");
XCTAssertEqualObjects(layer.fillExtrusionHeight, functionExpression,
@@ -246,7 +244,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillExtrusionHeight, pedanticFunctionExpression,
@"fillExtrusionHeight should round-trip camera-data expressions.");
-
layer.fillExtrusionHeight = nil;
XCTAssertTrue(rawLayer->getFillExtrusionHeight().isUndefined(),
@@ -287,13 +284,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionOpacity(), propertyValue,
@"Setting fillExtrusionOpacity to a camera expression should update fill-extrusion-opacity.");
XCTAssertEqualObjects(layer.fillExtrusionOpacity, functionExpression,
@"fillExtrusionOpacity should round-trip camera expressions.");
-
layer.fillExtrusionOpacity = nil;
XCTAssertTrue(rawLayer->getFillExtrusionOpacity().isUndefined(),
@@ -340,13 +336,12 @@
{ 18, "Fill Extrusion Pattern" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionPattern(), propertyValue,
@"Setting fillExtrusionPattern to a camera expression should update fill-extrusion-pattern.");
XCTAssertEqualObjects(layer.fillExtrusionPattern, functionExpression,
@"fillExtrusionPattern should round-trip camera expressions.");
-
layer.fillExtrusionPattern = nil;
XCTAssertTrue(rawLayer->getFillExtrusionPattern().isUndefined(),
@@ -399,13 +394,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionTranslate(), propertyValue,
@"Setting fillExtrusionTranslation to a camera expression should update fill-extrusion-translate.");
XCTAssertEqualObjects(layer.fillExtrusionTranslation, functionExpression,
@"fillExtrusionTranslation should round-trip camera expressions.");
-
layer.fillExtrusionTranslation = nil;
XCTAssertTrue(rawLayer->getFillExtrusionTranslate().isUndefined(),
@@ -443,13 +437,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillExtrusionTranslateAnchor(), propertyValue,
@"Setting fillExtrusionTranslationAnchor to a camera expression should update fill-extrusion-translate-anchor.");
XCTAssertEqualObjects(layer.fillExtrusionTranslationAnchor, functionExpression,
@"fillExtrusionTranslationAnchor should round-trip camera expressions.");
-
layer.fillExtrusionTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getFillExtrusionTranslateAnchor().isUndefined(),
diff --git a/platform/darwin/test/MGLFillStyleLayerTests.mm b/platform/darwin/test/MGLFillStyleLayerTests.mm
index a5019f1032..45bae07f43 100644
--- a/platform/darwin/test/MGLFillStyleLayerTests.mm
+++ b/platform/darwin/test/MGLFillStyleLayerTests.mm
@@ -71,13 +71,12 @@
{ 18, false },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillAntialias(), propertyValue,
@"Setting fillAntialiased to a camera expression should update fill-antialias.");
XCTAssertEqualObjects(layer.fillAntialiased, functionExpression,
@"fillAntialiased should round-trip camera expressions.");
-
layer.fillAntialiased = nil;
XCTAssertTrue(rawLayer->getFillAntialias().isUndefined(),
@@ -115,7 +114,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillColor(), propertyValue,
@"Setting fillColor to a camera expression should update fill-color.");
XCTAssertEqualObjects(layer.fillColor, functionExpression,
@@ -146,7 +145,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillColor, pedanticFunctionExpression,
@"fillColor should round-trip camera-data expressions.");
-
layer.fillColor = nil;
XCTAssertTrue(rawLayer->getFillColor().isUndefined(),
@@ -187,7 +185,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillOpacity(), propertyValue,
@"Setting fillOpacity to a camera expression should update fill-opacity.");
XCTAssertEqualObjects(layer.fillOpacity, functionExpression,
@@ -218,7 +216,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillOpacity, pedanticFunctionExpression,
@"fillOpacity should round-trip camera-data expressions.");
-
layer.fillOpacity = nil;
XCTAssertTrue(rawLayer->getFillOpacity().isUndefined(),
@@ -259,7 +256,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillOutlineColor(), propertyValue,
@"Setting fillOutlineColor to a camera expression should update fill-outline-color.");
XCTAssertEqualObjects(layer.fillOutlineColor, functionExpression,
@@ -290,7 +287,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.fillOutlineColor, pedanticFunctionExpression,
@"fillOutlineColor should round-trip camera-data expressions.");
-
layer.fillOutlineColor = nil;
XCTAssertTrue(rawLayer->getFillOutlineColor().isUndefined(),
@@ -331,13 +327,12 @@
{ 18, "Fill Pattern" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillPattern(), propertyValue,
@"Setting fillPattern to a camera expression should update fill-pattern.");
XCTAssertEqualObjects(layer.fillPattern, functionExpression,
@"fillPattern should round-trip camera expressions.");
-
layer.fillPattern = nil;
XCTAssertTrue(rawLayer->getFillPattern().isUndefined(),
@@ -390,13 +385,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillTranslate(), propertyValue,
@"Setting fillTranslation to a camera expression should update fill-translate.");
XCTAssertEqualObjects(layer.fillTranslation, functionExpression,
@"fillTranslation should round-trip camera expressions.");
-
layer.fillTranslation = nil;
XCTAssertTrue(rawLayer->getFillTranslate().isUndefined(),
@@ -434,13 +428,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getFillTranslateAnchor(), propertyValue,
@"Setting fillTranslationAnchor to a camera expression should update fill-translate-anchor.");
XCTAssertEqualObjects(layer.fillTranslationAnchor, functionExpression,
@"fillTranslationAnchor should round-trip camera expressions.");
-
layer.fillTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getFillTranslateAnchor().isUndefined(),
diff --git a/platform/darwin/test/MGLHeatmapStyleLayerTests.mm b/platform/darwin/test/MGLHeatmapStyleLayerTests.mm
index e4b1917257..db15778872 100644
--- a/platform/darwin/test/MGLHeatmapStyleLayerTests.mm
+++ b/platform/darwin/test/MGLHeatmapStyleLayerTests.mm
@@ -71,13 +71,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHeatmapIntensity(), propertyValue,
@"Setting heatmapIntensity to a camera expression should update heatmap-intensity.");
XCTAssertEqualObjects(layer.heatmapIntensity, functionExpression,
@"heatmapIntensity should round-trip camera expressions.");
-
layer.heatmapIntensity = nil;
XCTAssertTrue(rawLayer->getHeatmapIntensity().isUndefined(),
@@ -124,13 +123,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHeatmapOpacity(), propertyValue,
@"Setting heatmapOpacity to a camera expression should update heatmap-opacity.");
XCTAssertEqualObjects(layer.heatmapOpacity, functionExpression,
@"heatmapOpacity should round-trip camera expressions.");
-
layer.heatmapOpacity = nil;
XCTAssertTrue(rawLayer->getHeatmapOpacity().isUndefined(),
@@ -177,7 +175,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHeatmapRadius(), propertyValue,
@"Setting heatmapRadius to a camera expression should update heatmap-radius.");
XCTAssertEqualObjects(layer.heatmapRadius, functionExpression,
@@ -208,7 +206,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.heatmapRadius, pedanticFunctionExpression,
@"heatmapRadius should round-trip camera-data expressions.");
-
layer.heatmapRadius = nil;
XCTAssertTrue(rawLayer->getHeatmapRadius().isUndefined(),
@@ -249,7 +246,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHeatmapWeight(), propertyValue,
@"Setting heatmapWeight to a camera expression should update heatmap-weight.");
XCTAssertEqualObjects(layer.heatmapWeight, functionExpression,
@@ -280,7 +277,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.heatmapWeight, pedanticFunctionExpression,
@"heatmapWeight should round-trip camera-data expressions.");
-
layer.heatmapWeight = nil;
XCTAssertTrue(rawLayer->getHeatmapWeight().isUndefined(),
diff --git a/platform/darwin/test/MGLHillshadeStyleLayerTests.mm b/platform/darwin/test/MGLHillshadeStyleLayerTests.mm
index 34937d1674..2495b32d97 100644
--- a/platform/darwin/test/MGLHillshadeStyleLayerTests.mm
+++ b/platform/darwin/test/MGLHillshadeStyleLayerTests.mm
@@ -53,13 +53,12 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeAccentColor(), propertyValue,
@"Setting hillshadeAccentColor to a camera expression should update hillshade-accent-color.");
XCTAssertEqualObjects(layer.hillshadeAccentColor, functionExpression,
@"hillshadeAccentColor should round-trip camera expressions.");
-
layer.hillshadeAccentColor = nil;
XCTAssertTrue(rawLayer->getHillshadeAccentColor().isUndefined(),
@@ -106,13 +105,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeExaggeration(), propertyValue,
@"Setting hillshadeExaggeration to a camera expression should update hillshade-exaggeration.");
XCTAssertEqualObjects(layer.hillshadeExaggeration, functionExpression,
@"hillshadeExaggeration should round-trip camera expressions.");
-
layer.hillshadeExaggeration = nil;
XCTAssertTrue(rawLayer->getHillshadeExaggeration().isUndefined(),
@@ -159,13 +157,12 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeHighlightColor(), propertyValue,
@"Setting hillshadeHighlightColor to a camera expression should update hillshade-highlight-color.");
XCTAssertEqualObjects(layer.hillshadeHighlightColor, functionExpression,
@"hillshadeHighlightColor should round-trip camera expressions.");
-
layer.hillshadeHighlightColor = nil;
XCTAssertTrue(rawLayer->getHillshadeHighlightColor().isUndefined(),
@@ -212,13 +209,12 @@
{ 18, mbgl::style::HillshadeIlluminationAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::HillshadeIlluminationAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeIlluminationAnchor(), propertyValue,
@"Setting hillshadeIlluminationAnchor to a camera expression should update hillshade-illumination-anchor.");
XCTAssertEqualObjects(layer.hillshadeIlluminationAnchor, functionExpression,
@"hillshadeIlluminationAnchor should round-trip camera expressions.");
-
layer.hillshadeIlluminationAnchor = nil;
XCTAssertTrue(rawLayer->getHillshadeIlluminationAnchor().isUndefined(),
@@ -256,13 +252,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeIlluminationDirection(), propertyValue,
@"Setting hillshadeIlluminationDirection to a camera expression should update hillshade-illumination-direction.");
XCTAssertEqualObjects(layer.hillshadeIlluminationDirection, functionExpression,
@"hillshadeIlluminationDirection should round-trip camera expressions.");
-
layer.hillshadeIlluminationDirection = nil;
XCTAssertTrue(rawLayer->getHillshadeIlluminationDirection().isUndefined(),
@@ -300,13 +295,12 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getHillshadeShadowColor(), propertyValue,
@"Setting hillshadeShadowColor to a camera expression should update hillshade-shadow-color.");
XCTAssertEqualObjects(layer.hillshadeShadowColor, functionExpression,
@"hillshadeShadowColor should round-trip camera expressions.");
-
layer.hillshadeShadowColor = nil;
XCTAssertTrue(rawLayer->getHillshadeShadowColor().isUndefined(),
diff --git a/platform/darwin/test/MGLLineStyleLayerTests.mm b/platform/darwin/test/MGLLineStyleLayerTests.mm
index 5490278e98..aa24bc8c15 100644
--- a/platform/darwin/test/MGLLineStyleLayerTests.mm
+++ b/platform/darwin/test/MGLLineStyleLayerTests.mm
@@ -71,13 +71,12 @@
{ 18, mbgl::style::LineCapType::Square },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::LineCapType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineCap(), propertyValue,
@"Setting lineCap to a camera expression should update line-cap.");
XCTAssertEqualObjects(layer.lineCap, functionExpression,
@"lineCap should round-trip camera expressions.");
-
layer.lineCap = nil;
XCTAssertTrue(rawLayer->getLineCap().isUndefined(),
@@ -115,13 +114,12 @@
{ 18, mbgl::style::LineJoinType::Miter },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::LineJoinType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineJoin(), propertyValue,
@"Setting lineJoin to a camera expression should update line-join.");
XCTAssertEqualObjects(layer.lineJoin, functionExpression,
@"lineJoin should round-trip camera expressions.");
-
layer.lineJoin = nil;
XCTAssertTrue(rawLayer->getLineJoin().isUndefined(),
@@ -153,13 +151,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineMiterLimit(), propertyValue,
@"Setting lineMiterLimit to a camera expression should update line-miter-limit.");
XCTAssertEqualObjects(layer.lineMiterLimit, functionExpression,
@"lineMiterLimit should round-trip camera expressions.");
-
layer.lineMiterLimit = nil;
XCTAssertTrue(rawLayer->getLineMiterLimit().isUndefined(),
@@ -197,13 +194,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineRoundLimit(), propertyValue,
@"Setting lineRoundLimit to a camera expression should update line-round-limit.");
XCTAssertEqualObjects(layer.lineRoundLimit, functionExpression,
@"lineRoundLimit should round-trip camera expressions.");
-
layer.lineRoundLimit = nil;
XCTAssertTrue(rawLayer->getLineRoundLimit().isUndefined(),
@@ -241,7 +237,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineBlur(), propertyValue,
@"Setting lineBlur to a camera expression should update line-blur.");
XCTAssertEqualObjects(layer.lineBlur, functionExpression,
@@ -272,7 +268,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineBlur, pedanticFunctionExpression,
@"lineBlur should round-trip camera-data expressions.");
-
layer.lineBlur = nil;
XCTAssertTrue(rawLayer->getLineBlur().isUndefined(),
@@ -313,7 +308,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineColor(), propertyValue,
@"Setting lineColor to a camera expression should update line-color.");
XCTAssertEqualObjects(layer.lineColor, functionExpression,
@@ -344,7 +339,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineColor, pedanticFunctionExpression,
@"lineColor should round-trip camera-data expressions.");
-
layer.lineColor = nil;
XCTAssertTrue(rawLayer->getLineColor().isUndefined(),
@@ -385,13 +379,12 @@
{ 18, {1, 2} },
}};
propertyValue = mbgl::style::CameraFunction<std::vector<float>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineDasharray(), propertyValue,
@"Setting lineDashPattern to a camera expression should update line-dasharray.");
XCTAssertEqualObjects(layer.lineDashPattern, functionExpression,
@"lineDashPattern should round-trip camera expressions.");
-
layer.lineDashPattern = nil;
XCTAssertTrue(rawLayer->getLineDasharray().isUndefined(),
@@ -429,7 +422,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineGapWidth(), propertyValue,
@"Setting lineGapWidth to a camera expression should update line-gap-width.");
XCTAssertEqualObjects(layer.lineGapWidth, functionExpression,
@@ -460,7 +453,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineGapWidth, pedanticFunctionExpression,
@"lineGapWidth should round-trip camera-data expressions.");
-
layer.lineGapWidth = nil;
XCTAssertTrue(rawLayer->getLineGapWidth().isUndefined(),
@@ -501,7 +493,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineOffset(), propertyValue,
@"Setting lineOffset to a camera expression should update line-offset.");
XCTAssertEqualObjects(layer.lineOffset, functionExpression,
@@ -532,7 +524,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineOffset, pedanticFunctionExpression,
@"lineOffset should round-trip camera-data expressions.");
-
layer.lineOffset = nil;
XCTAssertTrue(rawLayer->getLineOffset().isUndefined(),
@@ -573,7 +564,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineOpacity(), propertyValue,
@"Setting lineOpacity to a camera expression should update line-opacity.");
XCTAssertEqualObjects(layer.lineOpacity, functionExpression,
@@ -604,7 +595,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineOpacity, pedanticFunctionExpression,
@"lineOpacity should round-trip camera-data expressions.");
-
layer.lineOpacity = nil;
XCTAssertTrue(rawLayer->getLineOpacity().isUndefined(),
@@ -645,13 +635,12 @@
{ 18, "Line Pattern" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLinePattern(), propertyValue,
@"Setting linePattern to a camera expression should update line-pattern.");
XCTAssertEqualObjects(layer.linePattern, functionExpression,
@"linePattern should round-trip camera expressions.");
-
layer.linePattern = nil;
XCTAssertTrue(rawLayer->getLinePattern().isUndefined(),
@@ -704,13 +693,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineTranslate(), propertyValue,
@"Setting lineTranslation to a camera expression should update line-translate.");
XCTAssertEqualObjects(layer.lineTranslation, functionExpression,
@"lineTranslation should round-trip camera expressions.");
-
layer.lineTranslation = nil;
XCTAssertTrue(rawLayer->getLineTranslate().isUndefined(),
@@ -748,13 +736,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineTranslateAnchor(), propertyValue,
@"Setting lineTranslationAnchor to a camera expression should update line-translate-anchor.");
XCTAssertEqualObjects(layer.lineTranslationAnchor, functionExpression,
@"lineTranslationAnchor should round-trip camera expressions.");
-
layer.lineTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getLineTranslateAnchor().isUndefined(),
@@ -792,7 +779,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
@"Setting lineWidth to a camera expression should update line-width.");
XCTAssertEqualObjects(layer.lineWidth, functionExpression,
@@ -823,7 +810,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.lineWidth, pedanticFunctionExpression,
@"lineWidth should round-trip camera-data expressions.");
-
layer.lineWidth = nil;
XCTAssertTrue(rawLayer->getLineWidth().isUndefined(),
diff --git a/platform/darwin/test/MGLNSStringAdditionsTests.m b/platform/darwin/test/MGLNSStringAdditionsTests.m
index 2a8715d991..a3ee7e3433 100644
--- a/platform/darwin/test/MGLNSStringAdditionsTests.m
+++ b/platform/darwin/test/MGLNSStringAdditionsTests.m
@@ -40,37 +40,29 @@
}
- (void)testTransliteratedString {
- if (@available(iOS 9.0, *)) {
- XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Portland");
- XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Portland");
- XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Портланд");
- XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Arab"], @"پُرتلَند");
- XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Portland");
-
- XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Latn"], @"běi jīng");
- XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Hans"], @"北京");
- XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"бе̌и йӣнг");
- XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Arab"], @"بِِ̌ جِينگ");
- XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Fake"], @"北京");
-
- XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Moskva");
- XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Mосква");
- XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Москва");
- XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Arab"], @"مُسكڤَ");
- XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Mосква");
-
- XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Latn"], @"rondon");
- XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Hans"], @"ロンドン");
- XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"рондон");
- XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Arab"], @"رُندُن");
- XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Fake"], @"ロンドン");
- } else {
- XCTAssertEqualObjects([@"Made-up Place" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Made-up Place");
- XCTAssertEqualObjects([@"Made-up Place" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Made-up Place");
- XCTAssertEqualObjects([@"Made-up Place" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Made-up Place");
- XCTAssertEqualObjects([@"Made-up Place" mgl_stringByTransliteratingIntoScript:@"Arab"], @"Made-up Place");
- XCTAssertEqualObjects([@"Made-up Place" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Made-up Place");
- }
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Portland");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Portland");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Портланд");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Arab"], @"پُرتلَند");
+ XCTAssertEqualObjects([@"Portland" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Portland");
+
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Latn"], @"běi jīng");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Hans"], @"北京");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"бе̌и йӣнг");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Arab"], @"بِِ̌ جِينگ");
+ XCTAssertEqualObjects([@"北京" mgl_stringByTransliteratingIntoScript:@"Fake"], @"北京");
+
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Latn"], @"Moskva");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Hans"], @"Mосква");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"Москва");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Arab"], @"مُسكڤَ");
+ XCTAssertEqualObjects([@"Mосква" mgl_stringByTransliteratingIntoScript:@"Fake"], @"Mосква");
+
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Latn"], @"rondon");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Hans"], @"ロンドン");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Cyrl"], @"рондон");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Arab"], @"رُندُن");
+ XCTAssertEqualObjects([@"ロンドン" mgl_stringByTransliteratingIntoScript:@"Fake"], @"ロンドン");
}
@end
diff --git a/platform/darwin/test/MGLRasterStyleLayerTests.mm b/platform/darwin/test/MGLRasterStyleLayerTests.mm
index c8e454743e..cf5175812e 100644
--- a/platform/darwin/test/MGLRasterStyleLayerTests.mm
+++ b/platform/darwin/test/MGLRasterStyleLayerTests.mm
@@ -53,13 +53,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterBrightnessMax(), propertyValue,
@"Setting maximumRasterBrightness to a camera expression should update raster-brightness-max.");
XCTAssertEqualObjects(layer.maximumRasterBrightness, functionExpression,
@"maximumRasterBrightness should round-trip camera expressions.");
-
layer.maximumRasterBrightness = nil;
XCTAssertTrue(rawLayer->getRasterBrightnessMax().isUndefined(),
@@ -97,13 +96,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterBrightnessMin(), propertyValue,
@"Setting minimumRasterBrightness to a camera expression should update raster-brightness-min.");
XCTAssertEqualObjects(layer.minimumRasterBrightness, functionExpression,
@"minimumRasterBrightness should round-trip camera expressions.");
-
layer.minimumRasterBrightness = nil;
XCTAssertTrue(rawLayer->getRasterBrightnessMin().isUndefined(),
@@ -141,13 +139,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterContrast(), propertyValue,
@"Setting rasterContrast to a camera expression should update raster-contrast.");
XCTAssertEqualObjects(layer.rasterContrast, functionExpression,
@"rasterContrast should round-trip camera expressions.");
-
layer.rasterContrast = nil;
XCTAssertTrue(rawLayer->getRasterContrast().isUndefined(),
@@ -194,13 +191,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterFadeDuration(), propertyValue,
@"Setting rasterFadeDuration to a camera expression should update raster-fade-duration.");
XCTAssertEqualObjects(layer.rasterFadeDuration, functionExpression,
@"rasterFadeDuration should round-trip camera expressions.");
-
layer.rasterFadeDuration = nil;
XCTAssertTrue(rawLayer->getRasterFadeDuration().isUndefined(),
@@ -238,13 +234,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterHueRotate(), propertyValue,
@"Setting rasterHueRotation to a camera expression should update raster-hue-rotate.");
XCTAssertEqualObjects(layer.rasterHueRotation, functionExpression,
@"rasterHueRotation should round-trip camera expressions.");
-
layer.rasterHueRotation = nil;
XCTAssertTrue(rawLayer->getRasterHueRotate().isUndefined(),
@@ -282,13 +277,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterOpacity(), propertyValue,
@"Setting rasterOpacity to a camera expression should update raster-opacity.");
XCTAssertEqualObjects(layer.rasterOpacity, functionExpression,
@"rasterOpacity should round-trip camera expressions.");
-
layer.rasterOpacity = nil;
XCTAssertTrue(rawLayer->getRasterOpacity().isUndefined(),
@@ -335,13 +329,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getRasterSaturation(), propertyValue,
@"Setting rasterSaturation to a camera expression should update raster-saturation.");
XCTAssertEqualObjects(layer.rasterSaturation, functionExpression,
@"rasterSaturation should round-trip camera expressions.");
-
layer.rasterSaturation = nil;
XCTAssertTrue(rawLayer->getRasterSaturation().isUndefined(),
diff --git a/platform/darwin/test/MGLStyleLayerTests.h b/platform/darwin/test/MGLStyleLayerTests.h
index 28c316c8ba..c7577819b8 100644
--- a/platform/darwin/test/MGLStyleLayerTests.h
+++ b/platform/darwin/test/MGLStyleLayerTests.h
@@ -14,7 +14,7 @@
@interface NSString (MGLStyleLayerTestAdditions)
-@property (nonatomic, readonly, copy) NS_ARRAY_OF(NSString *) *lexicalClasses;
+@property (nonatomic, readonly, copy) NSArray<NSString *> *lexicalClasses;
@property (nonatomic, readonly, copy) NSString *lemma;
@end
diff --git a/platform/darwin/test/MGLStyleLayerTests.m b/platform/darwin/test/MGLStyleLayerTests.m
index b51fa02af4..52b36dba00 100644
--- a/platform/darwin/test/MGLStyleLayerTests.m
+++ b/platform/darwin/test/MGLStyleLayerTests.m
@@ -33,7 +33,7 @@
}
- (void)testPropertyName:(NSString *)name isBoolean:(BOOL)isBoolean {
- NS_MUTABLE_ARRAY_OF(NSString *) *components = [name componentsSeparatedByString:@"-"].mutableCopy;
+ NSMutableArray<NSString *> *components = [name componentsSeparatedByString:@"-"].mutableCopy;
if (isBoolean) {
if ([components.firstObject isEqualToString:@"is"]) {
[components removeObjectAtIndex:0];
@@ -67,7 +67,7 @@
@implementation NSString (MGLStyleLayerTestAdditions)
-- (NS_ARRAY_OF(NSString *) *)lexicalClasses {
+- (NSArray<NSString *> *)lexicalClasses {
NSOrthography *orthography = [NSOrthography orthographyWithDominantScript:@"Latn"
languageMap:@{@"Latn": @[@"en"]}];
NSLinguisticTaggerOptions options = (NSLinguisticTaggerOmitPunctuation
diff --git a/platform/darwin/test/MGLStyleLayerTests.mm.ejs b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
index f70f0bba23..57e5fce533 100644
--- a/platform/darwin/test/MGLStyleLayerTests.mm.ejs
+++ b/platform/darwin/test/MGLStyleLayerTests.mm.ejs
@@ -59,7 +59,7 @@
MGLTransition transitionTest = MGLTransitionMake(5, 4);
<% for (const property of properties) { -%>
-<% if (property.name === 'heatmap-color') continue; -%>
+<% if (property['property-type'] === 'color-ramp') continue; -%>
// <%- originalPropertyName(property) %>
{
@@ -69,7 +69,7 @@
NSExpression *constantExpression = [NSExpression expressionWithFormat:<%- objCTestValue(property, type, true, 3) %>];
layer.<%- objCName(property) %> = constantExpression;
-<% if (property["property-function"]) { -%>
+<% if (isDataDriven(property)) { -%>
mbgl::style::DataDrivenPropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> };
<% } else { -%>
mbgl::style::PropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> };
@@ -88,13 +88,13 @@
{ 18, <%- mbglTestValue(property, type) %> },
}};
propertyValue = mbgl::style::CameraFunction<<%- mbglType(property) %>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->get<%- camelize(originalPropertyName(property)) %>(), propertyValue,
@"Setting <%- objCName(property) %> to a camera expression should update <%- originalPropertyName(property) %>.");
XCTAssertEqualObjects(layer.<%- objCName(property) %>, functionExpression,
@"<%- objCName(property) %> should round-trip camera expressions.");
-<% if (property["property-function"] && isInterpolatable(property)) { -%>
+<% if (isDataDriven(property) && isInterpolatable(property)) { -%>
functionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:(keyName, 'linear', nil, %@)", @{@18: constantExpression}];
layer.<%- objCName(property) %> = functionExpression;
@@ -120,7 +120,7 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.<%- objCName(property) %>, pedanticFunctionExpression,
@"<%- objCName(property) %> should round-trip camera-data expressions.");
-<% } -%>
+<% } -%>
<% if (!property.required) { -%>
layer.<%- objCName(property) %> = nil;
@@ -129,7 +129,7 @@
XCTAssertEqualObjects(layer.<%- objCName(property) %>, defaultExpression,
@"<%- objCName(property) %> should return the default value after being unset.");
<% } -%>
-<% if (!property["property-function"]) { -%>
+<% if (!isDataDriven(property)) { -%>
functionExpression = [NSExpression expressionForKeyPath:@"bogus"];
XCTAssertThrowsSpecificNamed(layer.<%- objCName(property) %> = functionExpression, NSException, NSInvalidArgumentException, @"MGL<%- camelize(type) %>Layer should raise an exception if a camera-data expression is applied to a property that does not support key paths to feature attributes.");
@@ -154,7 +154,7 @@
- (void)testPropertyNames {
<% for (const property of properties) { -%>
-<% if (property.name === 'heatmap-color') continue; -%>
+<% if (property['property-type'] === 'color-ramp') continue; -%>
[self testPropertyName:@"<%- property.getter || property.name %>" isBoolean:<%- property.type === 'boolean' ? 'YES' : 'NO' %>];
<% } -%>
}
diff --git a/platform/darwin/test/MGLSymbolStyleLayerTests.mm b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
index cf2f80125a..e1a7ee4e0e 100644
--- a/platform/darwin/test/MGLSymbolStyleLayerTests.mm
+++ b/platform/darwin/test/MGLSymbolStyleLayerTests.mm
@@ -71,13 +71,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconAllowOverlap(), propertyValue,
@"Setting iconAllowsOverlap to a camera expression should update icon-allow-overlap.");
XCTAssertEqualObjects(layer.iconAllowsOverlap, functionExpression,
@"iconAllowsOverlap should round-trip camera expressions.");
-
layer.iconAllowsOverlap = nil;
XCTAssertTrue(rawLayer->getIconAllowOverlap().isUndefined(),
@@ -115,13 +114,12 @@
{ 18, mbgl::style::SymbolAnchorType::BottomRight },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconAnchor(), propertyValue,
@"Setting iconAnchor to a camera expression should update icon-anchor.");
XCTAssertEqualObjects(layer.iconAnchor, functionExpression,
@"iconAnchor should round-trip camera expressions.");
-
layer.iconAnchor = nil;
XCTAssertTrue(rawLayer->getIconAnchor().isUndefined(),
@@ -153,13 +151,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconIgnorePlacement(), propertyValue,
@"Setting iconIgnoresPlacement to a camera expression should update icon-ignore-placement.");
XCTAssertEqualObjects(layer.iconIgnoresPlacement, functionExpression,
@"iconIgnoresPlacement should round-trip camera expressions.");
-
layer.iconIgnoresPlacement = nil;
XCTAssertTrue(rawLayer->getIconIgnorePlacement().isUndefined(),
@@ -197,13 +194,12 @@
{ 18, "Icon Image" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconImage(), propertyValue,
@"Setting iconImageName to a camera expression should update icon-image.");
XCTAssertEqualObjects(layer.iconImageName, functionExpression,
@"iconImageName should round-trip camera expressions.");
-
layer.iconImageName = nil;
XCTAssertTrue(rawLayer->getIconImage().isUndefined(),
@@ -241,7 +237,7 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconOffset(), propertyValue,
@"Setting iconOffset to a camera expression should update icon-offset.");
XCTAssertEqualObjects(layer.iconOffset, functionExpression,
@@ -272,7 +268,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconOffset, pedanticFunctionExpression,
@"iconOffset should round-trip camera-data expressions.");
-
layer.iconOffset = nil;
XCTAssertTrue(rawLayer->getIconOffset().isUndefined(),
@@ -304,13 +299,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconOptional(), propertyValue,
@"Setting iconOptional to a camera expression should update icon-optional.");
XCTAssertEqualObjects(layer.iconOptional, functionExpression,
@"iconOptional should round-trip camera expressions.");
-
layer.iconOptional = nil;
XCTAssertTrue(rawLayer->getIconOptional().isUndefined(),
@@ -348,13 +342,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconPadding(), propertyValue,
@"Setting iconPadding to a camera expression should update icon-padding.");
XCTAssertEqualObjects(layer.iconPadding, functionExpression,
@"iconPadding should round-trip camera expressions.");
-
layer.iconPadding = nil;
XCTAssertTrue(rawLayer->getIconPadding().isUndefined(),
@@ -392,13 +385,12 @@
{ 18, mbgl::style::AlignmentType::Auto },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconPitchAlignment(), propertyValue,
@"Setting iconPitchAlignment to a camera expression should update icon-pitch-alignment.");
XCTAssertEqualObjects(layer.iconPitchAlignment, functionExpression,
@"iconPitchAlignment should round-trip camera expressions.");
-
layer.iconPitchAlignment = nil;
XCTAssertTrue(rawLayer->getIconPitchAlignment().isUndefined(),
@@ -436,7 +428,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconRotate(), propertyValue,
@"Setting iconRotation to a camera expression should update icon-rotate.");
XCTAssertEqualObjects(layer.iconRotation, functionExpression,
@@ -467,7 +459,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconRotation, pedanticFunctionExpression,
@"iconRotation should round-trip camera-data expressions.");
-
layer.iconRotation = nil;
XCTAssertTrue(rawLayer->getIconRotate().isUndefined(),
@@ -499,13 +490,12 @@
{ 18, mbgl::style::AlignmentType::Auto },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconRotationAlignment(), propertyValue,
@"Setting iconRotationAlignment to a camera expression should update icon-rotation-alignment.");
XCTAssertEqualObjects(layer.iconRotationAlignment, functionExpression,
@"iconRotationAlignment should round-trip camera expressions.");
-
layer.iconRotationAlignment = nil;
XCTAssertTrue(rawLayer->getIconRotationAlignment().isUndefined(),
@@ -543,7 +533,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconSize(), propertyValue,
@"Setting iconScale to a camera expression should update icon-size.");
XCTAssertEqualObjects(layer.iconScale, functionExpression,
@@ -574,7 +564,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconScale, pedanticFunctionExpression,
@"iconScale should round-trip camera-data expressions.");
-
layer.iconScale = nil;
XCTAssertTrue(rawLayer->getIconSize().isUndefined(),
@@ -606,13 +595,12 @@
{ 18, mbgl::style::IconTextFitType::Both },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::IconTextFitType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconTextFit(), propertyValue,
@"Setting iconTextFit to a camera expression should update icon-text-fit.");
XCTAssertEqualObjects(layer.iconTextFit, functionExpression,
@"iconTextFit should round-trip camera expressions.");
-
layer.iconTextFit = nil;
XCTAssertTrue(rawLayer->getIconTextFit().isUndefined(),
@@ -656,13 +644,12 @@
{ 18, { 1, 1, 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 4>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconTextFitPadding(), propertyValue,
@"Setting iconTextFitPadding to a camera expression should update icon-text-fit-padding.");
XCTAssertEqualObjects(layer.iconTextFitPadding, functionExpression,
@"iconTextFitPadding should round-trip camera expressions.");
-
layer.iconTextFitPadding = nil;
XCTAssertTrue(rawLayer->getIconTextFitPadding().isUndefined(),
@@ -700,13 +687,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconKeepUpright(), propertyValue,
@"Setting keepsIconUpright to a camera expression should update icon-keep-upright.");
XCTAssertEqualObjects(layer.keepsIconUpright, functionExpression,
@"keepsIconUpright should round-trip camera expressions.");
-
layer.keepsIconUpright = nil;
XCTAssertTrue(rawLayer->getIconKeepUpright().isUndefined(),
@@ -744,13 +730,12 @@
{ 18, false },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextKeepUpright(), propertyValue,
@"Setting keepsTextUpright to a camera expression should update text-keep-upright.");
XCTAssertEqualObjects(layer.keepsTextUpright, functionExpression,
@"keepsTextUpright should round-trip camera expressions.");
-
layer.keepsTextUpright = nil;
XCTAssertTrue(rawLayer->getTextKeepUpright().isUndefined(),
@@ -788,13 +773,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextMaxAngle(), propertyValue,
@"Setting maximumTextAngle to a camera expression should update text-max-angle.");
XCTAssertEqualObjects(layer.maximumTextAngle, functionExpression,
@"maximumTextAngle should round-trip camera expressions.");
-
layer.maximumTextAngle = nil;
XCTAssertTrue(rawLayer->getTextMaxAngle().isUndefined(),
@@ -832,7 +816,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextMaxWidth(), propertyValue,
@"Setting maximumTextWidth to a camera expression should update text-max-width.");
XCTAssertEqualObjects(layer.maximumTextWidth, functionExpression,
@@ -863,7 +847,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.maximumTextWidth, pedanticFunctionExpression,
@"maximumTextWidth should round-trip camera-data expressions.");
-
layer.maximumTextWidth = nil;
XCTAssertTrue(rawLayer->getTextMaxWidth().isUndefined(),
@@ -895,13 +878,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getSymbolAvoidEdges(), propertyValue,
@"Setting symbolAvoidsEdges to a camera expression should update symbol-avoid-edges.");
XCTAssertEqualObjects(layer.symbolAvoidsEdges, functionExpression,
@"symbolAvoidsEdges should round-trip camera expressions.");
-
layer.symbolAvoidsEdges = nil;
XCTAssertTrue(rawLayer->getSymbolAvoidEdges().isUndefined(),
@@ -939,13 +921,12 @@
{ 18, mbgl::style::SymbolPlacementType::Line },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolPlacementType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getSymbolPlacement(), propertyValue,
@"Setting symbolPlacement to a camera expression should update symbol-placement.");
XCTAssertEqualObjects(layer.symbolPlacement, functionExpression,
@"symbolPlacement should round-trip camera expressions.");
-
layer.symbolPlacement = nil;
XCTAssertTrue(rawLayer->getSymbolPlacement().isUndefined(),
@@ -983,13 +964,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getSymbolSpacing(), propertyValue,
@"Setting symbolSpacing to a camera expression should update symbol-spacing.");
XCTAssertEqualObjects(layer.symbolSpacing, functionExpression,
@"symbolSpacing should round-trip camera expressions.");
-
layer.symbolSpacing = nil;
XCTAssertTrue(rawLayer->getSymbolSpacing().isUndefined(),
@@ -1027,13 +1007,12 @@
{ 18, "Text Field" },
}};
propertyValue = mbgl::style::CameraFunction<std::string> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextField(), propertyValue,
@"Setting text to a camera expression should update text-field.");
XCTAssertEqualObjects(layer.text, functionExpression,
@"text should round-trip camera expressions.");
-
layer.text = nil;
XCTAssertTrue(rawLayer->getTextField().isUndefined(),
@@ -1065,13 +1044,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextAllowOverlap(), propertyValue,
@"Setting textAllowsOverlap to a camera expression should update text-allow-overlap.");
XCTAssertEqualObjects(layer.textAllowsOverlap, functionExpression,
@"textAllowsOverlap should round-trip camera expressions.");
-
layer.textAllowsOverlap = nil;
XCTAssertTrue(rawLayer->getTextAllowOverlap().isUndefined(),
@@ -1109,13 +1087,12 @@
{ 18, mbgl::style::SymbolAnchorType::BottomRight },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::SymbolAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextAnchor(), propertyValue,
@"Setting textAnchor to a camera expression should update text-anchor.");
XCTAssertEqualObjects(layer.textAnchor, functionExpression,
@"textAnchor should round-trip camera expressions.");
-
layer.textAnchor = nil;
XCTAssertTrue(rawLayer->getTextAnchor().isUndefined(),
@@ -1147,13 +1124,12 @@
{ 18, { "Text Font", "Tnof Txet" } },
}};
propertyValue = mbgl::style::CameraFunction<std::vector<std::string>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextFont(), propertyValue,
@"Setting textFontNames to a camera expression should update text-font.");
XCTAssertEqualObjects(layer.textFontNames, functionExpression,
@"textFontNames should round-trip camera expressions.");
-
layer.textFontNames = nil;
XCTAssertTrue(rawLayer->getTextFont().isUndefined(),
@@ -1185,7 +1161,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextSize(), propertyValue,
@"Setting textFontSize to a camera expression should update text-size.");
XCTAssertEqualObjects(layer.textFontSize, functionExpression,
@@ -1216,7 +1192,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textFontSize, pedanticFunctionExpression,
@"textFontSize should round-trip camera-data expressions.");
-
layer.textFontSize = nil;
XCTAssertTrue(rawLayer->getTextSize().isUndefined(),
@@ -1248,13 +1223,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextIgnorePlacement(), propertyValue,
@"Setting textIgnoresPlacement to a camera expression should update text-ignore-placement.");
XCTAssertEqualObjects(layer.textIgnoresPlacement, functionExpression,
@"textIgnoresPlacement should round-trip camera expressions.");
-
layer.textIgnoresPlacement = nil;
XCTAssertTrue(rawLayer->getTextIgnorePlacement().isUndefined(),
@@ -1292,13 +1266,12 @@
{ 18, mbgl::style::TextJustifyType::Right },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TextJustifyType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextJustify(), propertyValue,
@"Setting textJustification to a camera expression should update text-justify.");
XCTAssertEqualObjects(layer.textJustification, functionExpression,
@"textJustification should round-trip camera expressions.");
-
layer.textJustification = nil;
XCTAssertTrue(rawLayer->getTextJustify().isUndefined(),
@@ -1330,7 +1303,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextLetterSpacing(), propertyValue,
@"Setting textLetterSpacing to a camera expression should update text-letter-spacing.");
XCTAssertEqualObjects(layer.textLetterSpacing, functionExpression,
@@ -1361,7 +1334,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textLetterSpacing, pedanticFunctionExpression,
@"textLetterSpacing should round-trip camera-data expressions.");
-
layer.textLetterSpacing = nil;
XCTAssertTrue(rawLayer->getTextLetterSpacing().isUndefined(),
@@ -1393,13 +1365,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextLineHeight(), propertyValue,
@"Setting textLineHeight to a camera expression should update text-line-height.");
XCTAssertEqualObjects(layer.textLineHeight, functionExpression,
@"textLineHeight should round-trip camera expressions.");
-
layer.textLineHeight = nil;
XCTAssertTrue(rawLayer->getTextLineHeight().isUndefined(),
@@ -1443,7 +1414,7 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextOffset(), propertyValue,
@"Setting textOffset to a camera expression should update text-offset.");
XCTAssertEqualObjects(layer.textOffset, functionExpression,
@@ -1474,7 +1445,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textOffset, pedanticFunctionExpression,
@"textOffset should round-trip camera-data expressions.");
-
layer.textOffset = nil;
XCTAssertTrue(rawLayer->getTextOffset().isUndefined(),
@@ -1506,13 +1476,12 @@
{ 18, true },
}};
propertyValue = mbgl::style::CameraFunction<bool> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextOptional(), propertyValue,
@"Setting textOptional to a camera expression should update text-optional.");
XCTAssertEqualObjects(layer.textOptional, functionExpression,
@"textOptional should round-trip camera expressions.");
-
layer.textOptional = nil;
XCTAssertTrue(rawLayer->getTextOptional().isUndefined(),
@@ -1550,13 +1519,12 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextPadding(), propertyValue,
@"Setting textPadding to a camera expression should update text-padding.");
XCTAssertEqualObjects(layer.textPadding, functionExpression,
@"textPadding should round-trip camera expressions.");
-
layer.textPadding = nil;
XCTAssertTrue(rawLayer->getTextPadding().isUndefined(),
@@ -1594,13 +1562,12 @@
{ 18, mbgl::style::AlignmentType::Auto },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextPitchAlignment(), propertyValue,
@"Setting textPitchAlignment to a camera expression should update text-pitch-alignment.");
XCTAssertEqualObjects(layer.textPitchAlignment, functionExpression,
@"textPitchAlignment should round-trip camera expressions.");
-
layer.textPitchAlignment = nil;
XCTAssertTrue(rawLayer->getTextPitchAlignment().isUndefined(),
@@ -1638,7 +1605,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextRotate(), propertyValue,
@"Setting textRotation to a camera expression should update text-rotate.");
XCTAssertEqualObjects(layer.textRotation, functionExpression,
@@ -1669,7 +1636,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textRotation, pedanticFunctionExpression,
@"textRotation should round-trip camera-data expressions.");
-
layer.textRotation = nil;
XCTAssertTrue(rawLayer->getTextRotate().isUndefined(),
@@ -1701,13 +1667,12 @@
{ 18, mbgl::style::AlignmentType::Auto },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::AlignmentType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextRotationAlignment(), propertyValue,
@"Setting textRotationAlignment to a camera expression should update text-rotation-alignment.");
XCTAssertEqualObjects(layer.textRotationAlignment, functionExpression,
@"textRotationAlignment should round-trip camera expressions.");
-
layer.textRotationAlignment = nil;
XCTAssertTrue(rawLayer->getTextRotationAlignment().isUndefined(),
@@ -1745,13 +1710,12 @@
{ 18, mbgl::style::TextTransformType::Lowercase },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TextTransformType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextTransform(), propertyValue,
@"Setting textTransform to a camera expression should update text-transform.");
XCTAssertEqualObjects(layer.textTransform, functionExpression,
@"textTransform should round-trip camera expressions.");
-
layer.textTransform = nil;
XCTAssertTrue(rawLayer->getTextTransform().isUndefined(),
@@ -1783,7 +1747,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconColor(), propertyValue,
@"Setting iconColor to a camera expression should update icon-color.");
XCTAssertEqualObjects(layer.iconColor, functionExpression,
@@ -1814,7 +1778,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconColor, pedanticFunctionExpression,
@"iconColor should round-trip camera-data expressions.");
-
layer.iconColor = nil;
XCTAssertTrue(rawLayer->getIconColor().isUndefined(),
@@ -1855,7 +1818,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconHaloBlur(), propertyValue,
@"Setting iconHaloBlur to a camera expression should update icon-halo-blur.");
XCTAssertEqualObjects(layer.iconHaloBlur, functionExpression,
@@ -1886,7 +1849,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconHaloBlur, pedanticFunctionExpression,
@"iconHaloBlur should round-trip camera-data expressions.");
-
layer.iconHaloBlur = nil;
XCTAssertTrue(rawLayer->getIconHaloBlur().isUndefined(),
@@ -1927,7 +1889,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconHaloColor(), propertyValue,
@"Setting iconHaloColor to a camera expression should update icon-halo-color.");
XCTAssertEqualObjects(layer.iconHaloColor, functionExpression,
@@ -1958,7 +1920,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconHaloColor, pedanticFunctionExpression,
@"iconHaloColor should round-trip camera-data expressions.");
-
layer.iconHaloColor = nil;
XCTAssertTrue(rawLayer->getIconHaloColor().isUndefined(),
@@ -1999,7 +1960,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconHaloWidth(), propertyValue,
@"Setting iconHaloWidth to a camera expression should update icon-halo-width.");
XCTAssertEqualObjects(layer.iconHaloWidth, functionExpression,
@@ -2030,7 +1991,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconHaloWidth, pedanticFunctionExpression,
@"iconHaloWidth should round-trip camera-data expressions.");
-
layer.iconHaloWidth = nil;
XCTAssertTrue(rawLayer->getIconHaloWidth().isUndefined(),
@@ -2071,7 +2031,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconOpacity(), propertyValue,
@"Setting iconOpacity to a camera expression should update icon-opacity.");
XCTAssertEqualObjects(layer.iconOpacity, functionExpression,
@@ -2102,7 +2062,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.iconOpacity, pedanticFunctionExpression,
@"iconOpacity should round-trip camera-data expressions.");
-
layer.iconOpacity = nil;
XCTAssertTrue(rawLayer->getIconOpacity().isUndefined(),
@@ -2149,13 +2108,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconTranslate(), propertyValue,
@"Setting iconTranslation to a camera expression should update icon-translate.");
XCTAssertEqualObjects(layer.iconTranslation, functionExpression,
@"iconTranslation should round-trip camera expressions.");
-
layer.iconTranslation = nil;
XCTAssertTrue(rawLayer->getIconTranslate().isUndefined(),
@@ -2193,13 +2151,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getIconTranslateAnchor(), propertyValue,
@"Setting iconTranslationAnchor to a camera expression should update icon-translate-anchor.");
XCTAssertEqualObjects(layer.iconTranslationAnchor, functionExpression,
@"iconTranslationAnchor should round-trip camera expressions.");
-
layer.iconTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getIconTranslateAnchor().isUndefined(),
@@ -2237,7 +2194,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextColor(), propertyValue,
@"Setting textColor to a camera expression should update text-color.");
XCTAssertEqualObjects(layer.textColor, functionExpression,
@@ -2268,7 +2225,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textColor, pedanticFunctionExpression,
@"textColor should round-trip camera-data expressions.");
-
layer.textColor = nil;
XCTAssertTrue(rawLayer->getTextColor().isUndefined(),
@@ -2309,7 +2265,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextHaloBlur(), propertyValue,
@"Setting textHaloBlur to a camera expression should update text-halo-blur.");
XCTAssertEqualObjects(layer.textHaloBlur, functionExpression,
@@ -2340,7 +2296,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textHaloBlur, pedanticFunctionExpression,
@"textHaloBlur should round-trip camera-data expressions.");
-
layer.textHaloBlur = nil;
XCTAssertTrue(rawLayer->getTextHaloBlur().isUndefined(),
@@ -2381,7 +2336,7 @@
{ 18, { 1, 0, 0, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::Color> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextHaloColor(), propertyValue,
@"Setting textHaloColor to a camera expression should update text-halo-color.");
XCTAssertEqualObjects(layer.textHaloColor, functionExpression,
@@ -2412,7 +2367,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textHaloColor, pedanticFunctionExpression,
@"textHaloColor should round-trip camera-data expressions.");
-
layer.textHaloColor = nil;
XCTAssertTrue(rawLayer->getTextHaloColor().isUndefined(),
@@ -2453,7 +2407,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextHaloWidth(), propertyValue,
@"Setting textHaloWidth to a camera expression should update text-halo-width.");
XCTAssertEqualObjects(layer.textHaloWidth, functionExpression,
@@ -2484,7 +2438,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textHaloWidth, pedanticFunctionExpression,
@"textHaloWidth should round-trip camera-data expressions.");
-
layer.textHaloWidth = nil;
XCTAssertTrue(rawLayer->getTextHaloWidth().isUndefined(),
@@ -2525,7 +2478,7 @@
{ 18, 0xff },
}};
propertyValue = mbgl::style::CameraFunction<float> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextOpacity(), propertyValue,
@"Setting textOpacity to a camera expression should update text-opacity.");
XCTAssertEqualObjects(layer.textOpacity, functionExpression,
@@ -2556,7 +2509,6 @@
pedanticFunctionExpression = [NSExpression expressionWithFormat:@"mgl_interpolate:withCurveType:parameters:stops:($zoomLevel, 'linear', nil, %@)", @{@10: pedanticFunctionExpression}];
XCTAssertEqualObjects(layer.textOpacity, pedanticFunctionExpression,
@"textOpacity should round-trip camera-data expressions.");
-
layer.textOpacity = nil;
XCTAssertTrue(rawLayer->getTextOpacity().isUndefined(),
@@ -2603,13 +2555,12 @@
{ 18, { 1, 1 } },
}};
propertyValue = mbgl::style::CameraFunction<std::array<float, 2>> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextTranslate(), propertyValue,
@"Setting textTranslation to a camera expression should update text-translate.");
XCTAssertEqualObjects(layer.textTranslation, functionExpression,
@"textTranslation should round-trip camera expressions.");
-
layer.textTranslation = nil;
XCTAssertTrue(rawLayer->getTextTranslate().isUndefined(),
@@ -2647,13 +2598,12 @@
{ 18, mbgl::style::TranslateAnchorType::Viewport },
}};
propertyValue = mbgl::style::CameraFunction<mbgl::style::TranslateAnchorType> { intervalStops };
-
+
XCTAssertEqual(rawLayer->getTextTranslateAnchor(), propertyValue,
@"Setting textTranslationAnchor to a camera expression should update text-translate-anchor.");
XCTAssertEqualObjects(layer.textTranslationAnchor, functionExpression,
@"textTranslationAnchor should round-trip camera expressions.");
-
layer.textTranslationAnchor = nil;
XCTAssertTrue(rawLayer->getTextTranslateAnchor().isUndefined(),
diff --git a/platform/default/mbgl/storage/offline.cpp b/platform/default/mbgl/storage/offline.cpp
index 7670790be9..598a0b182b 100644
--- a/platform/default/mbgl/storage/offline.cpp
+++ b/platform/default/mbgl/storage/offline.cpp
@@ -43,7 +43,7 @@ uint64_t OfflineTilePyramidRegionDefinition::tileCount(style::SourceType type, u
const Range<uint8_t> clampedZoomRange = coveringZoomRange(type, tileSize, zoomRange);
unsigned long result = 0;;
for (uint8_t z = clampedZoomRange.min; z <= clampedZoomRange.max; z++) {
- result += util::tileCount(bounds, z, tileSize);
+ result += util::tileCount(bounds, z);
}
return result;
diff --git a/platform/default/mbgl/storage/offline_database.cpp b/platform/default/mbgl/storage/offline_database.cpp
index 65c2097182..2b872ab87b 100644
--- a/platform/default/mbgl/storage/offline_database.cpp
+++ b/platform/default/mbgl/storage/offline_database.cpp
@@ -10,11 +10,6 @@
namespace mbgl {
-OfflineDatabase::Statement::~Statement() {
- stmt.reset();
- stmt.clearBindings();
-}
-
OfflineDatabase::OfflineDatabase(std::string path_, uint64_t maximumCacheSize_)
: path(std::move(path_)),
maximumCacheSize(maximumCacheSize_) {
@@ -28,48 +23,62 @@ OfflineDatabase::~OfflineDatabase() {
statements.clear();
db.reset();
} catch (mapbox::sqlite::Exception& ex) {
- Log::Error(Event::Database, ex.code, ex.what());
+ Log::Error(Event::Database, (int)ex.code, ex.what());
}
}
-void OfflineDatabase::connect(int flags) {
- db = std::make_unique<mapbox::sqlite::Database>(path.c_str(), flags);
- db->setBusyTimeout(Milliseconds::max());
- db->exec("PRAGMA foreign_keys = ON");
-}
-
void OfflineDatabase::ensureSchema() {
if (path != ":memory:") {
- try {
- connect(mapbox::sqlite::ReadWrite);
-
- switch (userVersion()) {
- case 0: break; // cache-only database; ok to delete
- case 1: break; // cache-only database; ok to delete
- case 2: migrateToVersion3(); // fall through
- case 3: // no-op and fall through
- case 4: migrateToVersion5(); // fall through
- case 5: migrateToVersion6(); // fall through
- case 6: return;
- default: break; // downgrade, delete the database
- }
-
- removeExisting();
- connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
- } catch (mapbox::sqlite::Exception& ex) {
- if (ex.code != mapbox::sqlite::Exception::Code::CANTOPEN && ex.code != mapbox::sqlite::Exception::Code::NOTADB) {
+ auto result = mapbox::sqlite::Database::tryOpen(path, mapbox::sqlite::ReadWrite);
+ if (result.is<mapbox::sqlite::Exception>()) {
+ const auto& ex = result.get<mapbox::sqlite::Exception>();
+ if (ex.code == mapbox::sqlite::ResultCode::NotADB) {
+ // Corrupted; blow it away.
+ removeExisting();
+ } else if (ex.code == mapbox::sqlite::ResultCode::CantOpen) {
+ // Doesn't exist yet.
+ } else {
Log::Error(Event::Database, "Unexpected error connecting to database: %s", ex.what());
- throw;
+ throw ex;
}
-
+ } else {
try {
- if (ex.code == mapbox::sqlite::Exception::Code::NOTADB) {
+ db = std::make_unique<mapbox::sqlite::Database>(std::move(result.get<mapbox::sqlite::Database>()));
+ db->setBusyTimeout(Milliseconds::max());
+ db->exec("PRAGMA foreign_keys = ON");
+
+ switch (userVersion()) {
+ case 0:
+ case 1:
+ // cache-only database; ok to delete
+ removeExisting();
+ 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) {
removeExisting();
+ } else {
+ throw;
}
- connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
- } catch (...) {
- Log::Error(Event::Database, "Unexpected error creating database: %s", util::toString(std::current_exception()).c_str());
- throw;
}
}
}
@@ -77,9 +86,9 @@ void OfflineDatabase::ensureSchema() {
try {
#include "offline_schema.cpp.include"
- connect(mapbox::sqlite::ReadWrite | mapbox::sqlite::Create);
-
- // If you change the schema you must write a migration from the previous version.
+ db = std::make_unique<mapbox::sqlite::Database>(mapbox::sqlite::Database::open(path, mapbox::sqlite::ReadWrite | mapbox::sqlite::Create));
+ 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");
@@ -92,14 +101,13 @@ void OfflineDatabase::ensureSchema() {
}
int OfflineDatabase::userVersion() {
- auto stmt = db->prepare("PRAGMA user_version");
- stmt.run();
- return stmt.get<int>(0);
+ return static_cast<int>(getPragma<int64_t>("PRAGMA user_version"));
}
void OfflineDatabase::removeExisting() {
Log::Warning(Event::Database, "Removing existing incompatible offline database");
+ statements.clear();
db.reset();
try {
@@ -135,14 +143,12 @@ void OfflineDatabase::migrateToVersion6() {
transaction.commit();
}
-OfflineDatabase::Statement OfflineDatabase::getStatement(const char * sql) {
+mapbox::sqlite::Statement& OfflineDatabase::getStatement(const char* sql) {
auto it = statements.find(sql);
-
- if (it != statements.end()) {
- return Statement(*it->second);
+ if (it == statements.end()) {
+ it = statements.emplace(sql, std::make_unique<mapbox::sqlite::Statement>(*db, sql)).first;
}
-
- return Statement(*statements.emplace(sql, std::make_unique<mapbox::sqlite::Statement>(db->prepare(sql))).first->second);
+ return *it->second;
}
optional<Response> OfflineDatabase::get(const Resource& resource) {
@@ -209,41 +215,40 @@ std::pair<bool, uint64_t> OfflineDatabase::putInternal(const Resource& resource,
}
optional<std::pair<Response, uint64_t>> OfflineDatabase::getResource(const Resource& resource) {
- // clang-format off
- Statement accessedStmt = getStatement(
- "UPDATE resources SET accessed = ?1 WHERE url = ?2");
- // clang-format on
-
- accessedStmt->bind(1, util::now());
- accessedStmt->bind(2, resource.url);
- accessedStmt->run();
+ // Update accessed timestamp used for LRU eviction.
+ {
+ 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();
+ }
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
// 0 1 2 3 4 5
"SELECT etag, expires, must_revalidate, modified, data, compressed "
"FROM resources "
- "WHERE url = ?");
+ "WHERE url = ?") };
// clang-format on
- stmt->bind(1, resource.url);
+ query.bind(1, resource.url);
- if (!stmt->run()) {
+ if (!query.run()) {
return {};
}
Response response;
uint64_t size = 0;
- response.etag = stmt->get<optional<std::string>>(0);
- response.expires = stmt->get<optional<Timestamp>>(1);
- response.mustRevalidate = stmt->get<bool>(2);
- response.modified = stmt->get<optional<Timestamp>>(3);
+ response.etag = query.get<optional<std::string>>(0);
+ response.expires = query.get<optional<Timestamp>>(1);
+ response.mustRevalidate = query.get<bool>(2);
+ response.modified = query.get<optional<Timestamp>>(3);
- optional<std::string> data = stmt->get<optional<std::string>>(4);
+ auto data = query.get<optional<std::string>>(4);
if (!data) {
response.noContent = true;
- } else if (stmt->get<bool>(5)) {
+ } else if (query.get<bool>(5)) {
response.data = std::make_shared<std::string>(util::decompress(*data));
size = data->length();
} else {
@@ -255,16 +260,13 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getResource(const Resou
}
optional<int64_t> OfflineDatabase::hasResource(const Resource& resource) {
- // clang-format off
- Statement stmt = getStatement("SELECT length(data) FROM resources WHERE url = ?");
- // clang-format on
-
- stmt->bind(1, resource.url);
- if (!stmt->run()) {
+ mapbox::sqlite::Query query{ getStatement("SELECT length(data) FROM resources WHERE url = ?") };
+ query.bind(1, resource.url);
+ if (!query.run()) {
return {};
}
- return stmt->get<optional<int64_t>>(0);
+ return query.get<optional<int64_t>>(0);
}
bool OfflineDatabase::putResource(const Resource& resource,
@@ -273,19 +275,19 @@ bool OfflineDatabase::putResource(const Resource& resource,
bool compressed) {
if (response.notModified) {
// clang-format off
- Statement update = getStatement(
+ mapbox::sqlite::Query notModifiedQuery{ getStatement(
"UPDATE resources "
"SET accessed = ?1, "
" expires = ?2, "
" must_revalidate = ?3 "
- "WHERE url = ?4 ");
+ "WHERE url = ?4 ") };
// clang-format on
- update->bind(1, util::now());
- update->bind(2, response.expires);
- update->bind(3, response.mustRevalidate);
- update->bind(4, resource.url);
- update->run();
+ notModifiedQuery.bind(1, util::now());
+ notModifiedQuery.bind(2, response.expires);
+ notModifiedQuery.bind(3, response.mustRevalidate);
+ notModifiedQuery.bind(4, resource.url);
+ notModifiedQuery.run();
return false;
}
@@ -296,7 +298,7 @@ bool OfflineDatabase::putResource(const Resource& resource,
mapbox::sqlite::Transaction transaction(*db, mapbox::sqlite::Transaction::Immediate);
// clang-format off
- Statement update = getStatement(
+ mapbox::sqlite::Query updateQuery{ getStatement(
"UPDATE resources "
"SET kind = ?1, "
" etag = ?2, "
@@ -306,81 +308,83 @@ bool OfflineDatabase::putResource(const Resource& resource,
" accessed = ?6, "
" data = ?7, "
" compressed = ?8 "
- "WHERE url = ?9 ");
+ "WHERE url = ?9 ") };
// clang-format on
- update->bind(1, int(resource.kind));
- update->bind(2, response.etag);
- update->bind(3, response.expires);
- update->bind(4, response.mustRevalidate);
- update->bind(5, response.modified);
- update->bind(6, util::now());
- update->bind(9, resource.url);
+ updateQuery.bind(1, int(resource.kind));
+ updateQuery.bind(2, response.etag);
+ updateQuery.bind(3, response.expires);
+ updateQuery.bind(4, response.mustRevalidate);
+ updateQuery.bind(5, response.modified);
+ updateQuery.bind(6, util::now());
+ updateQuery.bind(9, resource.url);
if (response.noContent) {
- update->bind(7, nullptr);
- update->bind(8, false);
+ updateQuery.bind(7, nullptr);
+ updateQuery.bind(8, false);
} else {
- update->bindBlob(7, data.data(), data.size(), false);
- update->bind(8, compressed);
+ updateQuery.bindBlob(7, data.data(), data.size(), false);
+ updateQuery.bind(8, compressed);
}
- update->run();
- if (update->changes() != 0) {
+ updateQuery.run();
+ if (updateQuery.changes() != 0) {
transaction.commit();
return false;
}
// clang-format off
- Statement insert = getStatement(
+ mapbox::sqlite::Query insertQuery{ getStatement(
"INSERT INTO resources (url, kind, etag, expires, must_revalidate, modified, accessed, data, compressed) "
- "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9) ");
+ "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9) ") };
// clang-format on
- insert->bind(1, resource.url);
- insert->bind(2, int(resource.kind));
- insert->bind(3, response.etag);
- insert->bind(4, response.expires);
- insert->bind(5, response.mustRevalidate);
- insert->bind(6, response.modified);
- insert->bind(7, util::now());
+ insertQuery.bind(1, resource.url);
+ insertQuery.bind(2, int(resource.kind));
+ insertQuery.bind(3, response.etag);
+ insertQuery.bind(4, response.expires);
+ insertQuery.bind(5, response.mustRevalidate);
+ insertQuery.bind(6, response.modified);
+ insertQuery.bind(7, util::now());
if (response.noContent) {
- insert->bind(8, nullptr);
- insert->bind(9, false);
+ insertQuery.bind(8, nullptr);
+ insertQuery.bind(9, false);
} else {
- insert->bindBlob(8, data.data(), data.size(), false);
- insert->bind(9, compressed);
+ insertQuery.bindBlob(8, data.data(), data.size(), false);
+ insertQuery.bind(9, compressed);
}
- insert->run();
+ insertQuery.run();
transaction.commit();
return true;
}
optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource::TileData& tile) {
- // clang-format off
- Statement accessedStmt = getStatement(
- "UPDATE tiles "
- "SET accessed = ?1 "
- "WHERE url_template = ?2 "
- " AND pixel_ratio = ?3 "
- " AND x = ?4 "
- " AND y = ?5 "
- " AND z = ?6 ");
- // clang-format on
+ {
+ // clang-format off
+ mapbox::sqlite::Query accessedQuery{ getStatement(
+ "UPDATE tiles "
+ "SET accessed = ?1 "
+ "WHERE url_template = ?2 "
+ " AND pixel_ratio = ?3 "
+ " AND x = ?4 "
+ " AND y = ?5 "
+ " AND z = ?6 ") };
+ // clang-format on
- accessedStmt->bind(1, util::now());
- accessedStmt->bind(2, tile.urlTemplate);
- accessedStmt->bind(3, tile.pixelRatio);
- accessedStmt->bind(4, tile.x);
- accessedStmt->bind(5, tile.y);
- accessedStmt->bind(6, tile.z);
- accessedStmt->run();
+ accessedQuery.bind(1, util::now());
+ accessedQuery.bind(2, tile.urlTemplate);
+ accessedQuery.bind(3, tile.pixelRatio);
+ accessedQuery.bind(4, tile.x);
+ accessedQuery.bind(5, tile.y);
+ accessedQuery.bind(6, tile.z);
+ accessedQuery.run();
+ }
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
// 0 1 2, 3, 4, 5
"SELECT etag, expires, must_revalidate, modified, data, compressed "
"FROM tiles "
@@ -388,31 +392,31 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource:
" AND pixel_ratio = ?2 "
" AND x = ?3 "
" AND y = ?4 "
- " AND z = ?5 ");
+ " AND z = ?5 ") };
// clang-format on
- stmt->bind(1, tile.urlTemplate);
- stmt->bind(2, tile.pixelRatio);
- stmt->bind(3, tile.x);
- stmt->bind(4, tile.y);
- stmt->bind(5, tile.z);
+ query.bind(1, tile.urlTemplate);
+ query.bind(2, tile.pixelRatio);
+ query.bind(3, tile.x);
+ query.bind(4, tile.y);
+ query.bind(5, tile.z);
- if (!stmt->run()) {
+ if (!query.run()) {
return {};
}
Response response;
uint64_t size = 0;
- response.etag = stmt->get<optional<std::string>>(0);
- response.expires = stmt->get<optional<Timestamp>>(1);
- response.mustRevalidate = stmt->get<bool>(2);
- response.modified = stmt->get<optional<Timestamp>>(3);
+ response.etag = query.get<optional<std::string>>(0);
+ response.expires = query.get<optional<Timestamp>>(1);
+ response.mustRevalidate = query.get<bool>(2);
+ response.modified = query.get<optional<Timestamp>>(3);
- optional<std::string> data = stmt->get<optional<std::string>>(4);
+ optional<std::string> data = query.get<optional<std::string>>(4);
if (!data) {
response.noContent = true;
- } else if (stmt->get<bool>(5)) {
+ } else if (query.get<bool>(5)) {
response.data = std::make_shared<std::string>(util::decompress(*data));
size = data->length();
} else {
@@ -425,27 +429,27 @@ optional<std::pair<Response, uint64_t>> OfflineDatabase::getTile(const Resource:
optional<int64_t> OfflineDatabase::hasTile(const Resource::TileData& tile) {
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query size{ getStatement(
"SELECT length(data) "
"FROM tiles "
"WHERE url_template = ?1 "
" AND pixel_ratio = ?2 "
" AND x = ?3 "
" AND y = ?4 "
- " AND z = ?5 ");
+ " AND z = ?5 ") };
// clang-format on
- stmt->bind(1, tile.urlTemplate);
- stmt->bind(2, tile.pixelRatio);
- stmt->bind(3, tile.x);
- stmt->bind(4, tile.y);
- stmt->bind(5, tile.z);
+ size.bind(1, tile.urlTemplate);
+ size.bind(2, tile.pixelRatio);
+ size.bind(3, tile.x);
+ size.bind(4, tile.y);
+ size.bind(5, tile.z);
- if (!stmt->run()) {
+ if (!size.run()) {
return {};
}
- return stmt->get<optional<int64_t>>(0);
+ return size.get<optional<int64_t>>(0);
}
bool OfflineDatabase::putTile(const Resource::TileData& tile,
@@ -454,7 +458,7 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
bool compressed) {
if (response.notModified) {
// clang-format off
- Statement update = getStatement(
+ mapbox::sqlite::Query notModifiedQuery{ getStatement(
"UPDATE tiles "
"SET accessed = ?1, "
" expires = ?2, "
@@ -463,18 +467,18 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
" AND pixel_ratio = ?5 "
" AND x = ?6 "
" AND y = ?7 "
- " AND z = ?8 ");
+ " AND z = ?8 ") };
// clang-format on
- update->bind(1, util::now());
- update->bind(2, response.expires);
- update->bind(3, response.mustRevalidate);
- update->bind(4, tile.urlTemplate);
- update->bind(5, tile.pixelRatio);
- update->bind(6, tile.x);
- update->bind(7, tile.y);
- update->bind(8, tile.z);
- update->run();
+ notModifiedQuery.bind(1, util::now());
+ notModifiedQuery.bind(2, response.expires);
+ notModifiedQuery.bind(3, response.mustRevalidate);
+ notModifiedQuery.bind(4, tile.urlTemplate);
+ notModifiedQuery.bind(5, tile.pixelRatio);
+ notModifiedQuery.bind(6, tile.x);
+ notModifiedQuery.bind(7, tile.y);
+ notModifiedQuery.bind(8, tile.z);
+ notModifiedQuery.run();
return false;
}
@@ -485,7 +489,7 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
mapbox::sqlite::Transaction transaction(*db, mapbox::sqlite::Transaction::Immediate);
// clang-format off
- Statement update = getStatement(
+ mapbox::sqlite::Query updateQuery{ getStatement(
"UPDATE tiles "
"SET modified = ?1, "
" etag = ?2, "
@@ -498,78 +502,75 @@ bool OfflineDatabase::putTile(const Resource::TileData& tile,
" AND pixel_ratio = ?9 "
" AND x = ?10 "
" AND y = ?11 "
- " AND z = ?12 ");
+ " AND z = ?12 ") };
// clang-format on
- update->bind(1, response.modified);
- update->bind(2, response.etag);
- update->bind(3, response.expires);
- update->bind(4, response.mustRevalidate);
- update->bind(5, util::now());
- update->bind(8, tile.urlTemplate);
- update->bind(9, tile.pixelRatio);
- update->bind(10, tile.x);
- update->bind(11, tile.y);
- update->bind(12, tile.z);
+ updateQuery.bind(1, response.modified);
+ updateQuery.bind(2, response.etag);
+ updateQuery.bind(3, response.expires);
+ updateQuery.bind(4, response.mustRevalidate);
+ updateQuery.bind(5, util::now());
+ updateQuery.bind(8, tile.urlTemplate);
+ updateQuery.bind(9, tile.pixelRatio);
+ updateQuery.bind(10, tile.x);
+ updateQuery.bind(11, tile.y);
+ updateQuery.bind(12, tile.z);
if (response.noContent) {
- update->bind(6, nullptr);
- update->bind(7, false);
+ updateQuery.bind(6, nullptr);
+ updateQuery.bind(7, false);
} else {
- update->bindBlob(6, data.data(), data.size(), false);
- update->bind(7, compressed);
+ updateQuery.bindBlob(6, data.data(), data.size(), false);
+ updateQuery.bind(7, compressed);
}
- update->run();
- if (update->changes() != 0) {
+ updateQuery.run();
+ if (updateQuery.changes() != 0) {
transaction.commit();
return false;
}
// clang-format off
- Statement insert = getStatement(
+ mapbox::sqlite::Query insertQuery{ getStatement(
"INSERT INTO tiles (url_template, pixel_ratio, x, y, z, modified, must_revalidate, etag, expires, accessed, data, compressed) "
- "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)");
+ "VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)") };
// clang-format on
- insert->bind(1, tile.urlTemplate);
- insert->bind(2, tile.pixelRatio);
- insert->bind(3, tile.x);
- insert->bind(4, tile.y);
- insert->bind(5, tile.z);
- insert->bind(6, response.modified);
- insert->bind(7, response.mustRevalidate);
- insert->bind(8, response.etag);
- insert->bind(9, response.expires);
- insert->bind(10, util::now());
+ insertQuery.bind(1, tile.urlTemplate);
+ insertQuery.bind(2, tile.pixelRatio);
+ insertQuery.bind(3, tile.x);
+ insertQuery.bind(4, tile.y);
+ insertQuery.bind(5, tile.z);
+ insertQuery.bind(6, response.modified);
+ insertQuery.bind(7, response.mustRevalidate);
+ insertQuery.bind(8, response.etag);
+ insertQuery.bind(9, response.expires);
+ insertQuery.bind(10, util::now());
if (response.noContent) {
- insert->bind(11, nullptr);
- insert->bind(12, false);
+ insertQuery.bind(11, nullptr);
+ insertQuery.bind(12, false);
} else {
- insert->bindBlob(11, data.data(), data.size(), false);
- insert->bind(12, compressed);
+ insertQuery.bindBlob(11, data.data(), data.size(), false);
+ insertQuery.bind(12, compressed);
}
- insert->run();
+ insertQuery.run();
transaction.commit();
return true;
}
std::vector<OfflineRegion> OfflineDatabase::listRegions() {
- // clang-format off
- Statement stmt = getStatement(
- "SELECT id, definition, description FROM regions");
- // clang-format on
+ mapbox::sqlite::Query query{ getStatement("SELECT id, definition, description FROM regions") };
std::vector<OfflineRegion> result;
- while (stmt->run()) {
+ while (query.run()) {
result.push_back(OfflineRegion(
- stmt->get<int64_t>(0),
- decodeOfflineRegionDefinition(stmt->get<std::string>(1)),
- stmt->get<std::vector<uint8_t>>(2)));
+ query.get<int64_t>(0),
+ decodeOfflineRegionDefinition(query.get<std::string>(1)),
+ query.get<std::vector<uint8_t>>(2)));
}
return result;
@@ -578,39 +579,37 @@ std::vector<OfflineRegion> OfflineDatabase::listRegions() {
OfflineRegion OfflineDatabase::createRegion(const OfflineRegionDefinition& definition,
const OfflineRegionMetadata& metadata) {
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
"INSERT INTO regions (definition, description) "
- "VALUES (?1, ?2) ");
+ "VALUES (?1, ?2) ") };
// clang-format on
- stmt->bind(1, encodeOfflineRegionDefinition(definition));
- stmt->bindBlob(2, metadata);
- stmt->run();
+ query.bind(1, encodeOfflineRegionDefinition(definition));
+ query.bindBlob(2, metadata);
+ query.run();
- return OfflineRegion(stmt->lastInsertRowId(), definition, metadata);
+ return OfflineRegion(query.lastInsertRowId(), definition, metadata);
}
OfflineRegionMetadata OfflineDatabase::updateMetadata(const int64_t regionID, const OfflineRegionMetadata& metadata) {
// clang-format off
- Statement stmt = getStatement(
- "UPDATE regions SET description = ?1"
- "WHERE id = ?2");
+ mapbox::sqlite::Query query{ getStatement(
+ "UPDATE regions SET description = ?1 "
+ "WHERE id = ?2") };
// clang-format on
- stmt->bindBlob(1, metadata);
- stmt->bind(2, regionID);
- stmt->run();
+ query.bindBlob(1, metadata);
+ query.bind(2, regionID);
+ query.run();
return metadata;
}
void OfflineDatabase::deleteRegion(OfflineRegion&& region) {
- // clang-format off
- Statement stmt = getStatement(
- "DELETE FROM regions WHERE id = ?");
- // clang-format on
-
- stmt->bind(1, region.getID());
- stmt->run();
+ {
+ mapbox::sqlite::Query query{ getStatement("DELETE FROM regions WHERE id = ?") };
+ query.bind(1, region.getID());
+ query.run();
+ }
evict(0);
db->exec("PRAGMA incremental_vacuum");
@@ -656,7 +655,7 @@ uint64_t OfflineDatabase::putRegionResource(int64_t regionID, const Resource& re
bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
if (resource.kind == Resource::Kind::Tile) {
// clang-format off
- Statement insert = getStatement(
+ mapbox::sqlite::Query insertQuery{ getStatement(
"INSERT OR IGNORE INTO region_tiles (region_id, tile_id) "
"SELECT ?1, tiles.id "
"FROM tiles "
@@ -664,24 +663,24 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
" AND pixel_ratio = ?3 "
" AND x = ?4 "
" AND y = ?5 "
- " AND z = ?6 ");
+ " AND z = ?6 ") };
// clang-format on
const Resource::TileData& tile = *resource.tileData;
- insert->bind(1, regionID);
- insert->bind(2, tile.urlTemplate);
- insert->bind(3, tile.pixelRatio);
- insert->bind(4, tile.x);
- insert->bind(5, tile.y);
- insert->bind(6, tile.z);
- insert->run();
-
- if (insert->changes() == 0) {
+ insertQuery.bind(1, regionID);
+ insertQuery.bind(2, tile.urlTemplate);
+ insertQuery.bind(3, tile.pixelRatio);
+ insertQuery.bind(4, tile.x);
+ insertQuery.bind(5, tile.y);
+ insertQuery.bind(6, tile.z);
+ insertQuery.run();
+
+ if (insertQuery.changes() == 0) {
return false;
}
// clang-format off
- Statement select = getStatement(
+ mapbox::sqlite::Query selectQuery{ getStatement(
"SELECT region_id "
"FROM region_tiles, tiles "
"WHERE region_id != ?1 "
@@ -690,58 +689,54 @@ bool OfflineDatabase::markUsed(int64_t regionID, const Resource& resource) {
" AND x = ?4 "
" AND y = ?5 "
" AND z = ?6 "
- "LIMIT 1 ");
+ "LIMIT 1 ") };
// clang-format on
- select->bind(1, regionID);
- select->bind(2, tile.urlTemplate);
- select->bind(3, tile.pixelRatio);
- select->bind(4, tile.x);
- select->bind(5, tile.y);
- select->bind(6, tile.z);
- return !select->run();
+ selectQuery.bind(1, regionID);
+ selectQuery.bind(2, tile.urlTemplate);
+ selectQuery.bind(3, tile.pixelRatio);
+ selectQuery.bind(4, tile.x);
+ selectQuery.bind(5, tile.y);
+ selectQuery.bind(6, tile.z);
+ return !selectQuery.run();
} else {
// clang-format off
- Statement insert = getStatement(
+ mapbox::sqlite::Query insertQuery{ getStatement(
"INSERT OR IGNORE INTO region_resources (region_id, resource_id) "
"SELECT ?1, resources.id "
"FROM resources "
- "WHERE resources.url = ?2 ");
+ "WHERE resources.url = ?2 ") };
// clang-format on
- insert->bind(1, regionID);
- insert->bind(2, resource.url);
- insert->run();
+ insertQuery.bind(1, regionID);
+ insertQuery.bind(2, resource.url);
+ insertQuery.run();
- if (insert->changes() == 0) {
+ if (insertQuery.changes() == 0) {
return false;
}
// clang-format off
- Statement select = getStatement(
+ mapbox::sqlite::Query selectQuery{ getStatement(
"SELECT region_id "
"FROM region_resources, resources "
"WHERE region_id != ?1 "
" AND resources.url = ?2 "
- "LIMIT 1 ");
+ "LIMIT 1 ") };
// clang-format on
- select->bind(1, regionID);
- select->bind(2, resource.url);
- return !select->run();
+ selectQuery.bind(1, regionID);
+ selectQuery.bind(2, resource.url);
+ return !selectQuery.run();
}
}
OfflineRegionDefinition OfflineDatabase::getRegionDefinition(int64_t regionID) {
- // clang-format off
- Statement stmt = getStatement(
- "SELECT definition FROM regions WHERE id = ?1");
- // clang-format on
-
- stmt->bind(1, regionID);
- stmt->run();
+ mapbox::sqlite::Query query{ getStatement("SELECT definition FROM regions WHERE id = ?1") };
+ query.bind(1, regionID);
+ query.run();
- return decodeOfflineRegionDefinition(stmt->get<std::string>(0));
+ return decodeOfflineRegionDefinition(query.get<std::string>(0));
}
OfflineRegionStatus OfflineDatabase::getRegionCompletedStatus(int64_t regionID) {
@@ -760,35 +755,35 @@ OfflineRegionStatus OfflineDatabase::getRegionCompletedStatus(int64_t regionID)
std::pair<int64_t, int64_t> OfflineDatabase::getCompletedResourceCountAndSize(int64_t regionID) {
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
"SELECT COUNT(*), SUM(LENGTH(data)) "
"FROM region_resources, resources "
"WHERE region_id = ?1 "
- "AND resource_id = resources.id ");
+ "AND resource_id = resources.id ") };
// clang-format on
- stmt->bind(1, regionID);
- stmt->run();
- return { stmt->get<int64_t>(0), stmt->get<int64_t>(1) };
+ query.bind(1, regionID);
+ query.run();
+ return { query.get<int64_t>(0), query.get<int64_t>(1) };
}
std::pair<int64_t, int64_t> OfflineDatabase::getCompletedTileCountAndSize(int64_t regionID) {
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
"SELECT COUNT(*), SUM(LENGTH(data)) "
"FROM region_tiles, tiles "
"WHERE region_id = ?1 "
- "AND tile_id = tiles.id ");
+ "AND tile_id = tiles.id ") };
// clang-format on
- stmt->bind(1, regionID);
- stmt->run();
- return { stmt->get<int64_t>(0), stmt->get<int64_t>(1) };
+ query.bind(1, regionID);
+ query.run();
+ return { query.get<int64_t>(0), query.get<int64_t>(1) };
}
template <class T>
-T OfflineDatabase::getPragma(const char * sql) {
- Statement stmt = getStatement(sql);
- stmt->run();
- return stmt->get<T>(0);
+T OfflineDatabase::getPragma(const char* sql) {
+ mapbox::sqlite::Query query{ getStatement(sql) };
+ query.run();
+ return query.get<T>(0);
}
// Remove least-recently used resources and tiles until the used database size,
@@ -813,7 +808,7 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
// size, and because pages can get fragmented on the database.
while (usedSize() + neededFreeSize + pageSize > maximumCacheSize) {
// clang-format off
- Statement accessedStmt = getStatement(
+ mapbox::sqlite::Query accessedQuery{ getStatement(
"SELECT max(accessed) "
"FROM ( "
" SELECT accessed "
@@ -829,16 +824,16 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
" WHERE tile_id IS NULL "
" ORDER BY accessed ASC LIMIT ?1 "
") "
- );
- accessedStmt->bind(1, 50);
+ ) };
+ accessedQuery.bind(1, 50);
// clang-format on
- if (!accessedStmt->run()) {
+ if (!accessedQuery.run()) {
return false;
}
- Timestamp accessed = accessedStmt->get<Timestamp>(0);
+ Timestamp accessed = accessedQuery.get<Timestamp>(0);
// clang-format off
- Statement stmt1 = getStatement(
+ mapbox::sqlite::Query resourceQuery{ getStatement(
"DELETE FROM resources "
"WHERE id IN ( "
" SELECT id FROM resources "
@@ -846,14 +841,14 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
" ON resource_id = resources.id "
" WHERE resource_id IS NULL "
" AND accessed <= ?1 "
- ") ");
+ ") ") };
// clang-format on
- stmt1->bind(1, accessed);
- stmt1->run();
- uint64_t changes1 = stmt1->changes();
+ resourceQuery.bind(1, accessed);
+ resourceQuery.run();
+ const uint64_t resourceChanges = resourceQuery.changes();
// clang-format off
- Statement stmt2 = getStatement(
+ mapbox::sqlite::Query tileQuery{ getStatement(
"DELETE FROM tiles "
"WHERE id IN ( "
" SELECT id FROM tiles "
@@ -861,16 +856,16 @@ bool OfflineDatabase::evict(uint64_t neededFreeSize) {
" ON tile_id = tiles.id "
" WHERE tile_id IS NULL "
" AND accessed <= ?1 "
- ") ");
+ ") ") };
// clang-format on
- stmt2->bind(1, accessed);
- stmt2->run();
- uint64_t changes2 = stmt2->changes();
+ tileQuery.bind(1, accessed);
+ tileQuery.run();
+ const uint64_t tileChanges = tileQuery.changes();
// The cached value of offlineTileCount does not need to be updated
// here because only non-offline tiles can be removed by eviction.
- if (changes1 == 0 && changes2 == 0) {
+ if (resourceChanges == 0 && tileChanges == 0) {
return false;
}
}
@@ -901,16 +896,16 @@ uint64_t OfflineDatabase::getOfflineMapboxTileCount() {
}
// clang-format off
- Statement stmt = getStatement(
+ mapbox::sqlite::Query query{ getStatement(
"SELECT COUNT(DISTINCT id) "
"FROM region_tiles, tiles "
"WHERE tile_id = tiles.id "
- "AND url_template LIKE 'mapbox://%' ");
+ "AND url_template LIKE 'mapbox://%' ") };
// clang-format on
- stmt->run();
+ query.run();
- offlineMapboxTileCount = stmt->get<int64_t>(0);
+ offlineMapboxTileCount = query.get<int64_t>(0);
return *offlineMapboxTileCount;
}
diff --git a/platform/default/mbgl/storage/offline_database.hpp b/platform/default/mbgl/storage/offline_database.hpp
index 91b544a9e0..e0d90a9a15 100644
--- a/platform/default/mbgl/storage/offline_database.hpp
+++ b/platform/default/mbgl/storage/offline_database.hpp
@@ -15,6 +15,7 @@ namespace mapbox {
namespace sqlite {
class Database;
class Statement;
+class Query;
} // namespace sqlite
} // namespace mapbox
@@ -58,7 +59,6 @@ public:
uint64_t getOfflineMapboxTileCount();
private:
- void connect(int flags);
int userVersion();
void ensureSchema();
void removeExisting();
@@ -66,20 +66,7 @@ private:
void migrateToVersion5();
void migrateToVersion6();
- class Statement {
- public:
- explicit Statement(mapbox::sqlite::Statement& stmt_) : stmt(stmt_) {}
- Statement(Statement&&) = default;
- Statement(const Statement&) = delete;
- ~Statement();
-
- mapbox::sqlite::Statement* operator->() { return &stmt; };
-
- private:
- mapbox::sqlite::Statement& stmt;
- };
-
- Statement getStatement(const char *);
+ mapbox::sqlite::Statement& getStatement(const char *);
optional<std::pair<Response, uint64_t>> getTile(const Resource::TileData&);
optional<int64_t> hasTile(const Resource::TileData&);
@@ -102,8 +89,8 @@ private:
std::pair<int64_t, int64_t> getCompletedTileCountAndSize(int64_t regionID);
const std::string path;
- std::unique_ptr<::mapbox::sqlite::Database> db;
- std::unordered_map<const char *, std::unique_ptr<::mapbox::sqlite::Statement>> statements;
+ std::unique_ptr<mapbox::sqlite::Database> db;
+ std::unordered_map<const char *, const std::unique_ptr<mapbox::sqlite::Statement>> statements;
template <class T>
T getPragma(const char *);
diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp
index 2e08354fdf..776adc8f3a 100644
--- a/platform/default/sqlite3.cpp
+++ b/platform/default/sqlite3.cpp
@@ -14,27 +14,20 @@ namespace sqlite {
class DatabaseImpl {
public:
- DatabaseImpl(const char* filename, int flags)
+ DatabaseImpl(sqlite3* db_)
+ : db(db_)
{
- const int error = sqlite3_open_v2(filename, &db, flags, nullptr);
- if (error != SQLITE_OK) {
- const auto message = sqlite3_errmsg(db);
- db = nullptr;
- throw Exception { error, message };
- }
}
~DatabaseImpl()
{
- if (!db) return;
-
const int error = sqlite3_close(db);
if (error != SQLITE_OK) {
mbgl::Log::Error(mbgl::Event::Database, "%s (Code %i)", sqlite3_errmsg(db), error);
}
}
- sqlite3* db = nullptr;
+ sqlite3* db;
};
class StatementImpl {
@@ -69,14 +62,84 @@ public:
template <typename T>
using optional = std::experimental::optional<T>;
+static const char* codeToString(const int err) {
+ switch (err) {
+ case SQLITE_OK: return "SQLITE_OK";
+ case SQLITE_ERROR: return "SQLITE_ERROR";
+ case SQLITE_INTERNAL: return "SQLITE_INTERNAL";
+ case SQLITE_PERM: return "SQLITE_PERM";
+ case SQLITE_ABORT: return "SQLITE_ABORT";
+ case SQLITE_BUSY: return "SQLITE_BUSY";
+ case SQLITE_LOCKED: return "SQLITE_LOCKED";
+ case SQLITE_NOMEM: return "SQLITE_NOMEM";
+ case SQLITE_READONLY: return "SQLITE_READONLY";
+ case SQLITE_INTERRUPT: return "SQLITE_INTERRUPT";
+ case SQLITE_IOERR: return "SQLITE_IOERR";
+ case SQLITE_CORRUPT: return "SQLITE_CORRUPT";
+ case SQLITE_NOTFOUND: return "SQLITE_NOTFOUND";
+ case SQLITE_FULL: return "SQLITE_FULL";
+ case SQLITE_CANTOPEN: return "SQLITE_CANTOPEN";
+ case SQLITE_PROTOCOL: return "SQLITE_PROTOCOL";
+ case SQLITE_EMPTY: return "SQLITE_EMPTY";
+ case SQLITE_SCHEMA: return "SQLITE_SCHEMA";
+ case SQLITE_TOOBIG: return "SQLITE_TOOBIG";
+ case SQLITE_CONSTRAINT: return "SQLITE_CONSTRAINT";
+ case SQLITE_MISMATCH: return "SQLITE_MISMATCH";
+ case SQLITE_MISUSE: return "SQLITE_MISUSE";
+ case SQLITE_NOLFS: return "SQLITE_NOLFS";
+ case SQLITE_AUTH: return "SQLITE_AUTH";
+ case SQLITE_FORMAT: return "SQLITE_FORMAT";
+ case SQLITE_RANGE: return "SQLITE_RANGE";
+ case SQLITE_NOTADB: return "SQLITE_NOTADB";
+ case SQLITE_NOTICE: return "SQLITE_NOTICE";
+ case SQLITE_WARNING: return "SQLITE_WARNING";
+ case SQLITE_ROW: return "SQLITE_ROW";
+ case SQLITE_DONE: return "SQLITE_DONE";
+ default: return "<unknown>";
+ }
+}
+
static void errorLogCallback(void *, const int err, const char *msg) {
- if (err == SQLITE_ERROR) {
- mbgl::Log::Error(mbgl::Event::Database, "%s (Code %i)", msg, err);
- } else if (err == SQLITE_WARNING) {
- mbgl::Log::Warning(mbgl::Event::Database, "%s (Code %i)", msg, err);
- } else {
- mbgl::Log::Info(mbgl::Event::Database, "%s (Code %i)", msg, err);
+ auto severity = mbgl::EventSeverity::Info;
+
+ switch (err) {
+ case SQLITE_ERROR: // Generic error
+ case SQLITE_INTERNAL: // Internal logic error in SQLite
+ case SQLITE_PERM: // Access permission denied
+ case SQLITE_ABORT: // Callback routine requested an abort
+ case SQLITE_BUSY: // The database file is locked
+ case SQLITE_LOCKED: // A table in the database is locked
+ case SQLITE_NOMEM: // A malloc() failed
+ case SQLITE_READONLY: // Attempt to write a readonly database
+ case SQLITE_INTERRUPT: // Operation terminated by sqlite3_interrupt(
+ case SQLITE_IOERR: // Some kind of disk I/O error occurred
+ case SQLITE_CORRUPT: // The database disk image is malformed
+ case SQLITE_NOTFOUND: // Unknown opcode in sqlite3_file_control()
+ case SQLITE_FULL: // Insertion failed because database is full
+ case SQLITE_CANTOPEN: // Unable to open the database file
+ case SQLITE_PROTOCOL: // Database lock protocol error
+ case SQLITE_EMPTY: // Internal use only
+ case SQLITE_SCHEMA: // The database schema changed
+ case SQLITE_TOOBIG: // String or BLOB exceeds size limit
+ case SQLITE_CONSTRAINT: // Abort due to constraint violation
+ case SQLITE_MISMATCH: // Data type mismatch
+ case SQLITE_MISUSE: // Library used incorrectly
+ case SQLITE_NOLFS: // Uses OS features not supported on host
+ case SQLITE_AUTH: // Authorization denied
+ case SQLITE_FORMAT: // Not used
+ case SQLITE_RANGE: // 2nd parameter to sqlite3_bind out of range
+ case SQLITE_NOTADB: // File opened that is not a database file
+ severity = mbgl::EventSeverity::Error;
+ break;
+ case SQLITE_WARNING: // Warnings from sqlite3_log()
+ severity = mbgl::EventSeverity::Warning;
+ break;
+ case SQLITE_NOTICE: // Notifications from sqlite3_log()
+ default:
+ break;
}
+
+ mbgl::Log::Record(severity, mbgl::Event::Database, "%s (%s)", msg, codeToString(err));
}
const static bool sqliteVersionCheck __attribute__((unused)) = []() {
@@ -94,11 +157,29 @@ const static bool sqliteVersionCheck __attribute__((unused)) = []() {
return true;
}();
-Database::Database(const std::string &filename, int flags)
- : impl(std::make_unique<DatabaseImpl>(filename.c_str(), flags))
-{
+mapbox::util::variant<Database, Exception> Database::tryOpen(const std::string &filename, int flags) {
+ sqlite3* db = nullptr;
+ const int error = sqlite3_open_v2(filename.c_str(), &db, flags, nullptr);
+ if (error != SQLITE_OK) {
+ const auto message = sqlite3_errmsg(db);
+ return Exception { error, message };
+ }
+ return Database(std::make_unique<DatabaseImpl>(db));
}
+Database Database::open(const std::string &filename, int flags) {
+ auto result = tryOpen(filename, flags);
+ if (result.is<Exception>()) {
+ throw result.get<Exception>();
+ } else {
+ return std::move(result.get<Database>());
+ }
+}
+
+Database::Database(std::unique_ptr<DatabaseImpl> impl_)
+ : impl(std::move(impl_))
+{}
+
Database::Database(Database &&other)
: impl(std::move(other.impl)) {}
@@ -131,128 +212,137 @@ void Database::exec(const std::string &sql) {
}
}
-Statement Database::prepare(const char *query) {
- assert(impl);
- return Statement(this, query);
+Statement::Statement(Database& db, const char* sql)
+ : impl(std::make_unique<StatementImpl>(db.impl->db, sql)) {
}
-Statement::Statement(Database *db, const char *sql)
- : impl(std::make_unique<StatementImpl>(db->impl->db, sql))
-{
+Statement::~Statement() {
+#ifndef NDEBUG
+ // Crash if we're destructing this object while we know a Query object references this.
+ assert(!used);
+#endif
}
-Statement::Statement(Statement &&other) {
- *this = std::move(other);
-}
+Query::Query(Statement& stmt_) : stmt(stmt_) {
+ assert(stmt.impl);
-Statement &Statement::operator=(Statement &&other) {
- std::swap(impl, other.impl);
- return *this;
+#ifndef NDEBUG
+ assert(!stmt.used);
+ stmt.used = true;
+#endif
}
-Statement::~Statement() = default;
+Query::~Query() {
+ reset();
+ clearBindings();
-template <> void Statement::bind(int offset, std::nullptr_t) {
- assert(impl);
- impl->check(sqlite3_bind_null(impl->stmt, offset));
+#ifndef NDEBUG
+ stmt.used = false;
+#endif
}
-template <> void Statement::bind(int offset, int8_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, std::nullptr_t) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_null(stmt.impl->stmt, offset));
}
-template <> void Statement::bind(int offset, int16_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, int8_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, int32_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, int16_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, int64_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, int32_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, uint8_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, int64_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, uint16_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, uint8_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, uint32_t value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
+template <> void Query::bind(int offset, uint16_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, float value) {
- assert(impl);
- impl->check(sqlite3_bind_double(impl->stmt, offset, value));
+template <> void Query::bind(int offset, uint32_t value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, double value) {
- assert(impl);
- impl->check(sqlite3_bind_double(impl->stmt, offset, value));
+template <> void Query::bind(int offset, float value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_double(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, bool value) {
- assert(impl);
- impl->check(sqlite3_bind_int(impl->stmt, offset, value));
+template <> void Query::bind(int offset, double value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_double(stmt.impl->stmt, offset, value));
}
-template <> void Statement::bind(int offset, const char *value) {
- assert(impl);
- impl->check(sqlite3_bind_text(impl->stmt, offset, value, -1, SQLITE_STATIC));
+template <> void Query::bind(int offset, bool value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int(stmt.impl->stmt, offset, value));
}
-// We currently cannot use sqlite3_bind_blob64 / sqlite3_bind_text64 because they
-// was introduced in SQLite 3.8.7, and we need to support earlier versions:
-// iOS 8.0: 3.7.13
-// iOS 8.2: 3.8.5
-// According to http://stackoverflow.com/questions/14288128/what-version-of-sqlite-does-ios-provide,
-// the first iOS version with 3.8.7+ was 9.0, with 3.8.8.
+template <> void Query::bind(int offset, const char *value) {
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_text(stmt.impl->stmt, offset, value, -1, SQLITE_STATIC));
+}
-void Statement::bind(int offset, const char * value, std::size_t length, bool retain) {
- assert(impl);
+// We currently cannot use sqlite3_bind_blob64 / sqlite3_bind_text64 because they
+// were introduced in SQLite 3.8.7, and we need to support earlier versions:
+// Android 11: 3.7
+// Android 21: 3.8
+// Android 24: 3.9
+// Per https://developer.android.com/reference/android/database/sqlite/package-summary.
+// The first iOS version with 3.8.7+ was 9.0, with 3.8.8.
+
+void Query::bind(int offset, const char * value, std::size_t length, bool retain) {
+ assert(stmt.impl);
if (length > std::numeric_limits<int>::max()) {
throw std::range_error("value too long for sqlite3_bind_text");
}
- impl->check(sqlite3_bind_text(impl->stmt, offset, value, int(length),
+ stmt.impl->check(sqlite3_bind_text(stmt.impl->stmt, offset, value, int(length),
retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
}
-void Statement::bind(int offset, const std::string& value, bool retain) {
+void Query::bind(int offset, const std::string& value, bool retain) {
bind(offset, value.data(), value.size(), retain);
}
-void Statement::bindBlob(int offset, const void * value, std::size_t length, bool retain) {
- assert(impl);
+void Query::bindBlob(int offset, const void * value, std::size_t length, bool retain) {
+ assert(stmt.impl);
if (length > std::numeric_limits<int>::max()) {
throw std::range_error("value too long for sqlite3_bind_text");
}
- impl->check(sqlite3_bind_blob(impl->stmt, offset, value, int(length),
+ stmt.impl->check(sqlite3_bind_blob(stmt.impl->stmt, offset, value, int(length),
retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
}
-void Statement::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
+void Query::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
bindBlob(offset, value.data(), value.size(), retain);
}
template <>
-void Statement::bind(
+void Query::bind(
int offset, std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds> value) {
- assert(impl);
- impl->check(sqlite3_bind_int64(impl->stmt, offset, std::chrono::system_clock::to_time_t(value)));
+ assert(stmt.impl);
+ stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, std::chrono::system_clock::to_time_t(value)));
}
-template <> void Statement::bind(int offset, optional<std::string> value) {
+template <> void Query::bind(int offset, optional<std::string> value) {
if (!value) {
bind(offset, nullptr);
} else {
@@ -261,7 +351,7 @@ template <> void Statement::bind(int offset, optional<std::string> value) {
}
template <>
-void Statement::bind(
+void Query::bind(
int offset,
optional<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>> value) {
if (!value) {
@@ -271,86 +361,86 @@ void Statement::bind(
}
}
-bool Statement::run() {
- assert(impl);
- const int err = sqlite3_step(impl->stmt);
- impl->lastInsertRowId = sqlite3_last_insert_rowid(sqlite3_db_handle(impl->stmt));
- impl->changes = sqlite3_changes(sqlite3_db_handle(impl->stmt));
+bool Query::run() {
+ assert(stmt.impl);
+ const int err = sqlite3_step(stmt.impl->stmt);
+ stmt.impl->lastInsertRowId = sqlite3_last_insert_rowid(sqlite3_db_handle(stmt.impl->stmt));
+ stmt.impl->changes = sqlite3_changes(sqlite3_db_handle(stmt.impl->stmt));
if (err == SQLITE_DONE) {
return false;
} else if (err == SQLITE_ROW) {
return true;
} else if (err != SQLITE_OK) {
- throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(impl->stmt)) };
+ throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(stmt.impl->stmt)) };
} else {
return false;
}
}
-template <> bool Statement::get(int offset) {
- assert(impl);
- return sqlite3_column_int(impl->stmt, offset);
+template <> bool Query::get(int offset) {
+ assert(stmt.impl);
+ return sqlite3_column_int(stmt.impl->stmt, offset);
}
-template <> int Statement::get(int offset) {
- assert(impl);
- return sqlite3_column_int(impl->stmt, offset);
+template <> int Query::get(int offset) {
+ assert(stmt.impl);
+ return sqlite3_column_int(stmt.impl->stmt, offset);
}
-template <> int64_t Statement::get(int offset) {
- assert(impl);
- return sqlite3_column_int64(impl->stmt, offset);
+template <> int64_t Query::get(int offset) {
+ assert(stmt.impl);
+ return sqlite3_column_int64(stmt.impl->stmt, offset);
}
-template <> double Statement::get(int offset) {
- assert(impl);
- return sqlite3_column_double(impl->stmt, offset);
+template <> double Query::get(int offset) {
+ assert(stmt.impl);
+ return sqlite3_column_double(stmt.impl->stmt, offset);
}
-template <> std::string Statement::get(int offset) {
- assert(impl);
+template <> std::string Query::get(int offset) {
+ assert(stmt.impl);
return {
- reinterpret_cast<const char *>(sqlite3_column_blob(impl->stmt, offset)),
- size_t(sqlite3_column_bytes(impl->stmt, offset))
+ reinterpret_cast<const char *>(sqlite3_column_blob(stmt.impl->stmt, offset)),
+ size_t(sqlite3_column_bytes(stmt.impl->stmt, offset))
};
}
-template <> std::vector<uint8_t> Statement::get(int offset) {
- assert(impl);
- const auto* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(impl->stmt, offset));
- const uint8_t* end = begin + sqlite3_column_bytes(impl->stmt, offset);
+template <> std::vector<uint8_t> Query::get(int offset) {
+ assert(stmt.impl);
+ const auto* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt.impl->stmt, offset));
+ const uint8_t* end = begin + sqlite3_column_bytes(stmt.impl->stmt, offset);
return { begin, end };
}
template <>
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
-Statement::get(int offset) {
- assert(impl);
+Query::get(int offset) {
+ assert(stmt.impl);
return std::chrono::time_point_cast<std::chrono::seconds>(
- std::chrono::system_clock::from_time_t(sqlite3_column_int64(impl->stmt, offset)));
+ std::chrono::system_clock::from_time_t(sqlite3_column_int64(stmt.impl->stmt, offset)));
}
-template <> optional<int64_t> Statement::get(int offset) {
- assert(impl);
- if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
+template <> optional<int64_t> Query::get(int offset) {
+ assert(stmt.impl);
+ if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
return optional<int64_t>();
} else {
return get<int64_t>(offset);
}
}
-template <> optional<double> Statement::get(int offset) {
- assert(impl);
- if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
+template <> optional<double> Query::get(int offset) {
+ assert(stmt.impl);
+ if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
return optional<double>();
} else {
return get<double>(offset);
}
}
-template <> optional<std::string> Statement::get(int offset) {
- assert(impl);
- if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
+template <> optional<std::string> Query::get(int offset) {
+ assert(stmt.impl);
+ if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
return optional<std::string>();
} else {
return get<std::string>(offset);
@@ -359,9 +449,9 @@ template <> optional<std::string> Statement::get(int offset) {
template <>
optional<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>>
-Statement::get(int offset) {
- assert(impl);
- if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
+Query::get(int offset) {
+ assert(stmt.impl);
+ if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
return {};
} else {
return get<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>>(
@@ -369,24 +459,24 @@ Statement::get(int offset) {
}
}
-void Statement::reset() {
- assert(impl);
- sqlite3_reset(impl->stmt);
+void Query::reset() {
+ assert(stmt.impl);
+ sqlite3_reset(stmt.impl->stmt);
}
-void Statement::clearBindings() {
- assert(impl);
- sqlite3_clear_bindings(impl->stmt);
+void Query::clearBindings() {
+ assert(stmt.impl);
+ sqlite3_clear_bindings(stmt.impl->stmt);
}
-int64_t Statement::lastInsertRowId() const {
- assert(impl);
- return impl->lastInsertRowId;
+int64_t Query::lastInsertRowId() const {
+ assert(stmt.impl);
+ return stmt.impl->lastInsertRowId;
}
-uint64_t Statement::changes() const {
- assert(impl);
- auto changes_ = impl->changes;
+uint64_t Query::changes() const {
+ assert(stmt.impl);
+ auto changes_ = stmt.impl->changes;
return (changes_ < 0 ? 0 : changes_);
}
diff --git a/platform/default/sqlite3.hpp b/platform/default/sqlite3.hpp
index 82e3ceff6d..cdc94298fe 100644
--- a/platform/default/sqlite3.hpp
+++ b/platform/default/sqlite3.hpp
@@ -5,6 +5,7 @@
#include <stdexcept>
#include <chrono>
#include <memory>
+#include <mapbox/variant.hpp>
namespace mapbox {
namespace sqlite {
@@ -19,36 +20,72 @@ enum OpenFlag : int {
PrivateCache = 0x00040000,
};
-struct Exception : std::runtime_error {
- enum Code : int {
- OK = 0,
- CANTOPEN = 14,
- NOTADB = 26
- };
+enum class ResultCode : int {
+ OK = 0,
+ Error = 1,
+ Internal = 2,
+ Perm = 3,
+ Abort = 4,
+ Busy = 5,
+ Locked = 6,
+ NoMem = 7,
+ ReadOnly = 8,
+ Interrupt = 9,
+ IOErr = 10,
+ Corrupt = 11,
+ NotFound = 12,
+ Full = 13,
+ CantOpen = 14,
+ Protocol = 15,
+ Schema = 17,
+ TooBig = 18,
+ Constraint = 19,
+ Mismatch = 20,
+ Misuse = 21,
+ NoLFS = 22,
+ Auth = 23,
+ Range = 25,
+ NotADB = 26
+};
- Exception(int err, const char *msg) : std::runtime_error(msg), code(err) {}
- Exception(int err, const std::string& msg) : std::runtime_error(msg), code(err) {}
- const int code = OK;
+class Exception : public std::runtime_error {
+public:
+ Exception(int err, const char* msg)
+ : std::runtime_error(msg), code(static_cast<ResultCode>(err)) {
+ }
+ Exception(ResultCode err, const char* msg)
+ : std::runtime_error(msg), code(err) {
+ }
+ Exception(int err, const std::string& msg)
+ : std::runtime_error(msg), code(static_cast<ResultCode>(err)) {
+ }
+ Exception(ResultCode err, const std::string& msg)
+ : std::runtime_error(msg), code(err) {
+ }
+ const ResultCode code = ResultCode::OK;
};
class DatabaseImpl;
class Statement;
class StatementImpl;
+class Query;
class Database {
private:
+ Database(std::unique_ptr<DatabaseImpl>);
Database(const Database &) = delete;
Database &operator=(const Database &) = delete;
public:
- Database(const std::string &filename, int flags = 0);
+ static mapbox::util::variant<Database, Exception> tryOpen(const std::string &filename, int flags = 0);
+ static Database open(const std::string &filename, int flags = 0);
+
Database(Database &&);
~Database();
Database &operator=(Database &&);
void setBusyTimeout(std::chrono::milliseconds);
void exec(const std::string &sql);
- Statement prepare(const char *query);
private:
std::unique_ptr<DatabaseImpl> impl;
@@ -56,28 +93,54 @@ private:
friend class Statement;
};
+// A Statement object represents a prepared statement that can be run repeatedly run with a Query object.
class Statement {
+public:
+ Statement(Database& db, const char* sql);
+ Statement(const Statement&) = delete;
+ Statement(Statement&&) = delete;
+ Statement& operator=(const Statement&) = delete;
+ Statement& operator=(Statement&&) = delete;
+ ~Statement();
+
+ friend class Query;
+
private:
- Statement(const Statement &) = delete;
- Statement &operator=(const Statement &) = delete;
+ std::unique_ptr<StatementImpl> impl;
+
+#ifndef NDEBUG
+ // This flag stores whether there exists a Query object that uses this prepared statement.
+ // There may only be one Query object at a time. Statement objects must outlive Query objects.
+ // While a Query object exists, a Statement object may not be moved or deleted.
+ bool used = false;
+#endif
+};
+// A Query object is used to run a database query with a prepared statement (stored in a Statement
+// object). There may only exist one Query object per Statement object. Query objects are designed
+// to be constructed and destroyed frequently.
+class Query {
public:
- Statement(Database *db, const char *sql);
- Statement(Statement &&);
- ~Statement();
- Statement &operator=(Statement &&);
+ Query(Statement&);
+ Query(const Query&) = delete;
+ Query(Query&&) = delete;
+ Query& operator=(const Query&) = delete;
+ Query& operator=(Query&&) = delete;
+ ~Query();
- template <typename T> void bind(int offset, T value);
+ template <typename T>
+ void bind(int offset, T value);
// Text
- void bind(int offset, const char *, std::size_t length, bool retain = true);
+ void bind(int offset, const char*, std::size_t length, bool retain = true);
void bind(int offset, const std::string&, bool retain = true);
// Blob
- void bindBlob(int offset, const void *, std::size_t length, bool retain = true);
+ void bindBlob(int offset, const void*, std::size_t length, bool retain = true);
void bindBlob(int offset, const std::vector<uint8_t>&, bool retain = true);
- template <typename T> T get(int offset);
+ template <typename T>
+ T get(int offset);
bool run();
void reset();
@@ -87,7 +150,7 @@ public:
uint64_t changes() const;
private:
- std::unique_ptr<StatementImpl> impl;
+ Statement& stmt;
};
class Transaction {
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 35df4cb98d..f70330300b 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -2,6 +2,12 @@
Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started.
+## master
+
+### Packaging
+
+* The minimum deployment target for this SDK is now iOS 9.0. ([#11776](https://github.com/mapbox/mapbox-gl-native/pull/11776))
+
## 4.0.1 - May 14, 2018
### Packaging
diff --git a/platform/ios/DEVELOPING.md b/platform/ios/DEVELOPING.md
index 7a97074d38..34388c2589 100644
--- a/platform/ios/DEVELOPING.md
+++ b/platform/ios/DEVELOPING.md
@@ -4,14 +4,10 @@ This document explains how to build the Mapbox Maps SDK for iOS from source. It
## Requirements
-The Mapbox Maps SDK for iOS and iosapp demo application require iOS 8.0 or above. _Note: Support for iOS 8 will be removed in a future release and the minimum iOS deployment version will increase to iOS 9.0._
-
-The Mapbox Maps SDK for iOS requires Xcode 9.1 or above to compile from source.
+See the "Requirements" section in [INSTALL.md](INSTALL.md).
## Building the SDK
-Make sure that you have the [core dependencies](../../INSTALL.md) installed.
-
Create and open an Xcode workspace that includes both the SDK source and some Objective-C test applications by running:
```bash
diff --git a/platform/ios/INSTALL.md b/platform/ios/INSTALL.md
index 9c46e7fbe0..bfa7bf7ceb 100644
--- a/platform/ios/INSTALL.md
+++ b/platform/ios/INSTALL.md
@@ -4,13 +4,12 @@ This document explains how to build a development version of Mapbox Maps SDK for
### Requirements
-The Mapbox Maps SDK for iOS is intended to run on iOS 8.0 and above on the following devices:
+The Mapbox Maps SDK for iOS is intended to run on iOS 9.0 and above on the following devices:
* iPhone 4s and above (5, 5c, 5s, 6, 6 Plus, 7, 7 Plus, 8, 8 Plus, X)
* iPad 2 and above (3, 4, Mini, Air, Mini 2, Air 2, Pro)
* iPod touch 5th generation and above
-_Note: Support for iOS 8 will be removed in a future release and the minimum iOS deployment version will increase to iOS 9.0._
Note that debugging in 32-bit simulators (such as the iPhone 5 or iPad 2) is only partially supported.
@@ -19,16 +18,34 @@ The Mapbox Maps SDK for iOS requires:
* Xcode 9.1 or higher to compile from source
* Xcode 8.0 or higher to integrate the compiled framework into an application
-### Building the SDK
-
-1. [Install core dependencies](../../INSTALL.md).
+Before building, follow these steps to install prerequisites:
+1. Install [Xcode](https://developer.apple.com/xcode/)
+1. Launch Xcode and install any updates
+1. Install [Homebrew](http://brew.sh)
+1. Install [Node.js](https://nodejs.org/), [CMake](https://cmake.org/), and [ccache](https://ccache.samba.org):
+ ```
+ brew install node cmake ccache
+ ```
+1. Install [xcpretty](https://github.com/supermarin/xcpretty) (optional, used for prettifying command line builds):
+ ```
+ [sudo] gem install xcpretty
+ ```
1. Install [jazzy](https://github.com/realm/jazzy) for generating API documentation:
-
```
[sudo] gem install jazzy
```
+### Building the SDK
+
+1. Clone the git repository:
+ ```
+ git clone https://github.com/mapbox/mapbox-gl-native.git
+ cd mapbox-gl-native
+ ```
+ Note that this repository uses Git submodules. They'll be automatically checked out when you first run a `make` command,
+ but are not updated automatically. We recommended that you run `git submodule update` after pulling down new commits to
+ this repository.
1. Run `make iframework BUILDTYPE=Release`. The packaging script will produce a `build/ios/pkg/` folder containing:
- a `dynamic` folder containing a dynamically-linked fat framework with debug symbols for devices and the iOS Simulator
- a `documentation` folder with HTML API documentation
diff --git a/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec
index 83b7bc51f9..77ff15ab42 100644
--- a/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-nightly-dynamic.podspec
@@ -20,7 +20,7 @@ Pod::Spec.new do |m|
}
m.platform = :ios
- m.ios.deployment_target = '8.0'
+ m.ios.deployment_target = '9.0'
m.requires_arc = true
diff --git a/platform/ios/Mapbox-iOS-SDK-static-part.podspec b/platform/ios/Mapbox-iOS-SDK-static-part.podspec
index b2a114f9d2..bd98bb7272 100644
--- a/platform/ios/Mapbox-iOS-SDK-static-part.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-static-part.podspec
@@ -1,4 +1,4 @@
- m.ios.deployment_target = '8.0'
+ m.ios.deployment_target = '9.0'
m.requires_arc = true
diff --git a/platform/ios/Mapbox-iOS-SDK-symbols.podspec b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
index 05694e5b6f..7db87e1f08 100644
--- a/platform/ios/Mapbox-iOS-SDK-symbols.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-symbols.podspec
@@ -20,7 +20,7 @@ Pod::Spec.new do |m|
}
m.platform = :ios
- m.ios.deployment_target = '8.0'
+ m.ios.deployment_target = '9.0'
m.requires_arc = true
diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec
index 3fa57839b6..67e1665853 100644
--- a/platform/ios/Mapbox-iOS-SDK.podspec
+++ b/platform/ios/Mapbox-iOS-SDK.podspec
@@ -20,7 +20,7 @@ Pod::Spec.new do |m|
}
m.platform = :ios
- m.ios.deployment_target = '8.0'
+ m.ios.deployment_target = '9.0'
m.requires_arc = true
diff --git a/platform/ios/app/MBXOfflinePacksTableViewController.m b/platform/ios/app/MBXOfflinePacksTableViewController.m
index 26a15a0b95..959ae57548 100644
--- a/platform/ios/app/MBXOfflinePacksTableViewController.m
+++ b/platform/ios/app/MBXOfflinePacksTableViewController.m
@@ -45,7 +45,7 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NS_DICTIONARY_OF(NSString *, id) *)change context:(void *)context {
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *, id> *)change context:(void *)context {
if ([keyPath isEqualToString:@"packs"]) {
NSKeyValueChange changeKind = [change[NSKeyValueChangeKindKey] unsignedIntegerValue];
NSIndexSet *indices = change[NSKeyValueChangeIndexesKey];
@@ -119,9 +119,7 @@ static NSString * const MBXOfflinePacksTableViewActiveCellReuseIdentifier = @"Ac
}];
}];
[alertController addAction:downloadAction];
- if ([alertController respondsToSelector:@selector(setPreferredAction:)]) {
- alertController.preferredAction = downloadAction;
- }
+ alertController.preferredAction = downloadAction;
[self presentViewController:alertController animated:YES completion:nil];
}
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index c3585fbeae..0cb6c73d31 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -177,9 +177,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
self.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"];
self.mapView.showsScale = YES;
self.mapView.showsUserHeadingIndicator = YES;
- if ([UIFont respondsToSelector:@selector(monospacedDigitSystemFontOfSize:weight:)]) {
- self.hudLabel.titleLabel.font = [UIFont monospacedDigitSystemFontOfSize:10 weight:UIFontWeightRegular];
- }
+ self.hudLabel.titleLabel.font = [UIFont monospacedDigitSystemFontOfSize:10 weight:UIFontWeightRegular];
if ([MGLAccountManager accessToken].length)
{
@@ -209,11 +207,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self.mapView reloadStyle:self];
}];
[alertController addAction:OKAction];
+ alertController.preferredAction = OKAction;
- if ([alertController respondsToSelector:@selector(setPreferredAction:)])
- {
- alertController.preferredAction = OKAction;
- }
[self presentViewController:alertController animated:YES completion:nil];
}
}
@@ -1544,7 +1539,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self continueWorldTourWithRemainingAnnotations:annotations];
}
-- (void)continueWorldTourWithRemainingAnnotations:(NS_MUTABLE_ARRAY_OF(MGLPointAnnotation *) *)annotations
+- (void)continueWorldTourWithRemainingAnnotations:(NSMutableArray<MGLPointAnnotation *> *)annotations
{
MGLPointAnnotation *nextAnnotation = annotations.firstObject;
if (!nextAnnotation || !_isTouringWorld)
diff --git a/platform/ios/benchmark/MBXBenchViewController.mm b/platform/ios/benchmark/MBXBenchViewController.mm
index d4629e2521..84c2790d50 100644
--- a/platform/ios/benchmark/MBXBenchViewController.mm
+++ b/platform/ios/benchmark/MBXBenchViewController.mm
@@ -76,10 +76,8 @@
[self startBenchmarkIteration];
}];
[alertController addAction:OKAction];
+ alertController.preferredAction = OKAction;
- if ([alertController respondsToSelector:@selector(setPreferredAction:)]) {
- alertController.preferredAction = OKAction;
- }
[self presentViewController:alertController animated:YES completion:nil];
}
}
diff --git a/platform/ios/docs/doc-README.md b/platform/ios/docs/doc-README.md
index 7cd0376d07..3a95aa96de 100644
--- a/platform/ios/docs/doc-README.md
+++ b/platform/ios/docs/doc-README.md
@@ -1,6 +1,6 @@
# [Mapbox Maps SDK for iOS](https://www.mapbox.com/ios-sdk/)
-The Mapbox Maps SDK for iOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 8.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
+The Mapbox Maps SDK for iOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 9.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
![Mapbox Maps SDK for iOS screenshots](img/screenshot.png)
diff --git a/platform/ios/docs/pod-README.md b/platform/ios/docs/pod-README.md
index f94073bd9f..8a3080055d 100644
--- a/platform/ios/docs/pod-README.md
+++ b/platform/ios/docs/pod-README.md
@@ -1,6 +1,6 @@
# [Mapbox Maps SDK for iOS](https://www.mapbox.com/ios-sdk/)
-The Mapbox Maps SDK for iOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 8.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
+The Mapbox Maps SDK for iOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa Touch applications on iOS 9.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
For more information, check out the [Mapbox Maps SDK for iOS homepage](https://www.mapbox.com/ios-sdk/) and the [full changelog](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/ios/CHANGELOG.md) online.
@@ -10,7 +10,7 @@ For more information, check out the [Mapbox Maps SDK for iOS homepage](https://w
The Mapbox Maps SDK for iOS may be installed as either a dynamic framework or a static framework. (To reduce the download size, the static framework is omitted from some distributions; you may need to download the full package from the [release page](https://github.com/mapbox/mapbox-gl-native/releases/).)
-Integrating the Mapbox Maps SDK for iOS requires Xcode 8.0 or higher. To use this SDK with Xcode 7.3.1, download and use a symbols build from the [releases](https://github.com/mapbox/mapbox-gl-native/releases) page.
+Integrating the Mapbox Maps SDK for iOS requires Xcode 8.0 or higher.
{{DYNAMIC}}
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index 46c10dab89..78cfff965c 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -3394,7 +3394,6 @@
CODE_SIGN_STYLE = Automatic;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "Integration Tests/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.integration-tests";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3420,7 +3419,6 @@
CODE_SIGN_STYLE = Automatic;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "Integration Tests/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.integration-tests";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3446,7 +3444,6 @@
CODE_SIGN_STYLE = Automatic;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "Integration Test Harness/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.Integration-Test-Harness";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3471,7 +3468,6 @@
CODE_SIGN_STYLE = Automatic;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = "Integration Test Harness/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 11.2;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.mapbox.Integration-Test-Harness";
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -3531,7 +3527,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -3586,7 +3582,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
@@ -3602,7 +3598,6 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL;
PRODUCT_NAME = "Mapbox GL";
@@ -3616,7 +3611,6 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.MapboxGL;
PRODUCT_NAME = "Mapbox GL";
@@ -3651,7 +3645,6 @@
CLANG_ENABLE_MODULES = YES;
HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
INFOPLIST_FILE = test/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_CPLUSPLUSFLAGS = (
@@ -3676,7 +3669,6 @@
CLANG_ENABLE_MODULES = YES;
HEADER_SEARCH_PATHS = "$(mbgl_core_INCLUDE_DIRECTORIES)";
INFOPLIST_FILE = test/Info.plist;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_CPLUSPLUSFLAGS = (
@@ -3711,7 +3703,6 @@
);
INFOPLIST_FILE = framework/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_CPLUSPLUSFLAGS = (
@@ -3754,7 +3745,6 @@
);
INFOPLIST_FILE = framework/Info.plist;
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
OTHER_CFLAGS = "-fvisibility=hidden";
OTHER_CPLUSPLUSFLAGS = (
@@ -3868,7 +3858,6 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = "$(SRCROOT)/benchmark/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.bench;
PRODUCT_NAME = "Bench GL";
@@ -3880,7 +3869,6 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
INFOPLIST_FILE = "$(SRCROOT)/benchmark/Info.plist";
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.mapbox.bench;
PRODUCT_NAME = "Bench GL";
diff --git a/platform/ios/src/MGLAnnotationContainerView.h b/platform/ios/src/MGLAnnotationContainerView.h
index 90d2964831..ccec3052a6 100644
--- a/platform/ios/src/MGLAnnotationContainerView.h
+++ b/platform/ios/src/MGLAnnotationContainerView.h
@@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN
+ (instancetype)annotationContainerViewWithAnnotationContainerView:(MGLAnnotationContainerView *)annotationContainerView;
-- (void)addSubviews:(NS_ARRAY_OF(MGLAnnotationView *) *)subviews;
+- (void)addSubviews:(NSArray<MGLAnnotationView *> *)subviews;
@end
diff --git a/platform/ios/src/MGLAnnotationContainerView.m b/platform/ios/src/MGLAnnotationContainerView.m
index 9a823c839c..6c82a1836d 100644
--- a/platform/ios/src/MGLAnnotationContainerView.m
+++ b/platform/ios/src/MGLAnnotationContainerView.m
@@ -3,7 +3,7 @@
@interface MGLAnnotationContainerView ()
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(MGLAnnotationView *) *annotationViews;
+@property (nonatomic) NSMutableArray<MGLAnnotationView *> *annotationViews;
@end
@@ -26,7 +26,7 @@
return newAnnotationContainerView;
}
-- (void)addSubviews:(NS_ARRAY_OF(MGLAnnotationView *) *)subviews
+- (void)addSubviews:(NSArray<MGLAnnotationView *> *)subviews
{
for (MGLAnnotationView *view in subviews)
{
diff --git a/platform/ios/src/MGLAnnotationContainerView_Private.h b/platform/ios/src/MGLAnnotationContainerView_Private.h
index 007b03550b..9dce54842d 100644
--- a/platform/ios/src/MGLAnnotationContainerView_Private.h
+++ b/platform/ios/src/MGLAnnotationContainerView_Private.h
@@ -7,7 +7,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface MGLAnnotationContainerView (Private)
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(MGLAnnotationView *) *annotationViews;
+@property (nonatomic) NSMutableArray<MGLAnnotationView *> *annotationViews;
@end
diff --git a/platform/ios/src/MGLMapAccessibilityElement.mm b/platform/ios/src/MGLMapAccessibilityElement.mm
index 8bce38a145..c1cc5304d7 100644
--- a/platform/ios/src/MGLMapAccessibilityElement.mm
+++ b/platform/ios/src/MGLMapAccessibilityElement.mm
@@ -56,10 +56,8 @@
// may be in the local language, which may be written in another script.
// Attempt to transform to the script of the preferred language, keeping
// the original string if no transform exists or if transformation fails.
- if (@available(iOS 9.0, *)) {
- NSString *dominantScript = [NSOrthography mgl_dominantScriptForMapboxStreetsLanguage:languageCode];
- name = [name mgl_stringByTransliteratingIntoScript:dominantScript];
- }
+ NSString *dominantScript = [NSOrthography mgl_dominantScriptForMapboxStreetsLanguage:languageCode];
+ name = [name mgl_stringByTransliteratingIntoScript:dominantScript];
self.accessibilityLabel = name;
}
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index 020dc5e830..fd0ca19b26 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -189,7 +189,7 @@ MGL_EXPORT IB_DESIGNABLE
*/
@property (nonatomic, readonly, nullable) MGLStyle *style;
-@property (nonatomic, readonly) NS_ARRAY_OF(NSURL *) *bundledStyleURLs __attribute__((unavailable("Call the relevant class method of MGLStyle for the URL of a particular default style.")));
+@property (nonatomic, readonly) NSArray<NSURL *> *bundledStyleURLs __attribute__((unavailable("Call the relevant class method of MGLStyle for the URL of a particular default style.")));
/**
URL of the style currently displayed in the receiver.
@@ -286,7 +286,7 @@ MGL_EXPORT IB_DESIGNABLE
*/
- (IBAction)showAttribution:(id)sender;
-@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((unavailable("Support for style classes has been removed.")));
+@property (nonatomic) NSArray<NSString *> *styleClasses __attribute__((unavailable("Support for style classes has been removed.")));
- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((unavailable("Support for style classes has been removed.")));
@@ -773,7 +773,7 @@ MGL_EXPORT IB_DESIGNABLE
@param animated `YES` if you want the map region change to be animated, or `NO`
if you want the map to display the new region immediately without animations.
*/
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations animated:(BOOL)animated;
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations animated:(BOOL)animated;
/**
Sets the visible region so that the map displays the specified annotations with
@@ -788,7 +788,7 @@ MGL_EXPORT IB_DESIGNABLE
@param animated `YES` if you want the map region change to be animated, or `NO`
if you want the map to display the new region immediately without animations.
*/
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated;
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated;
/**
A camera representing the current viewpoint of the map.
@@ -1076,7 +1076,7 @@ MGL_EXPORT IB_DESIGNABLE
annotations are associated with the map view, the value of this property is
`nil`.
*/
-@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *annotations;
+@property (nonatomic, readonly, nullable) NSArray<id <MGLAnnotation>> *annotations;
/**
Adds an annotation to the map view.
@@ -1104,7 +1104,7 @@ MGL_EXPORT IB_DESIGNABLE
must conform to the `MGLAnnotation` protocol. The map view retains each
individual annotation object.
*/
-- (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations;
+- (void)addAnnotations:(NSArray<id <MGLAnnotation>> *)annotations;
/**
Removes an annotation from the map view, deselecting it if it is selected.
@@ -1129,7 +1129,7 @@ MGL_EXPORT IB_DESIGNABLE
@param annotations The array of annotation objects to remove. Objects in the
array must conform to the `MGLAnnotation` protocol.
*/
-- (void)removeAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations;
+- (void)removeAnnotations:(NSArray<id <MGLAnnotation>> *)annotations;
/**
Returns an `MGLAnnotationView` if the given annotation is currently associated
@@ -1180,7 +1180,7 @@ MGL_EXPORT IB_DESIGNABLE
annotations are associated with the map view or if no annotations associated
with the map view are currently visible, the value of this property is `nil`.
*/
-@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *visibleAnnotations;
+@property (nonatomic, readonly, nullable) NSArray<id <MGLAnnotation>> *visibleAnnotations;
/**
Returns the list of annotations associated with the receiver that intersect with
@@ -1191,7 +1191,7 @@ MGL_EXPORT IB_DESIGNABLE
no annotations associated with the map view are currently visible in the
rectangle.
*/
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotationsInRect:(CGRect)rect;
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotationsInRect:(CGRect)rect;
#pragma mark Managing Annotation Selections
@@ -1208,7 +1208,7 @@ MGL_EXPORT IB_DESIGNABLE
@note In versions prior to `4.0.0` if the annotation was offscreen it was not
selected.
*/
-@property (nonatomic, copy) NS_ARRAY_OF(id <MGLAnnotation>) *selectedAnnotations;
+@property (nonatomic, copy) NSArray<id <MGLAnnotation>> *selectedAnnotations;
/**
Selects an annotation and displays its callout view.
@@ -1246,7 +1246,7 @@ MGL_EXPORT IB_DESIGNABLE
overlays are associated with the map view, the value of this property is
empty array.
*/
-@property (nonatomic, readonly, nonnull) NS_ARRAY_OF(id <MGLOverlay>) *overlays;
+@property (nonatomic, readonly, nonnull) NSArray<id <MGLOverlay>> *overlays;
/**
Adds a single overlay object to the map.
@@ -1265,7 +1265,7 @@ MGL_EXPORT IB_DESIGNABLE
@param overlays An array of objects, each of which must conform to the
`MGLOverlay` protocol.
*/
-- (void)addOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
+- (void)addOverlays:(NSArray<id <MGLOverlay>> *)overlays;
/**
Removes a single overlay object from the map.
@@ -1285,7 +1285,7 @@ MGL_EXPORT IB_DESIGNABLE
@param overlays An array of objects, each of which conforms to the `MGLOverlay`
protocol.
*/
-- (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
+- (void)removeOverlays:(NSArray<id <MGLOverlay>> *)overlays;
#pragma mark Accessing the Underlying Map Data
@@ -1301,7 +1301,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point NS_SWIFT_NAME(visibleFeatures(at:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point NS_SWIFT_NAME(visibleFeatures(at:));
/**
Returns an array of rendered map features that intersect with a given point,
@@ -1320,7 +1320,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
/**
Returns an array of rendered map features that intersect with a given point,
@@ -1387,7 +1387,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:predicate:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:predicate:));
/**
Returns an array of rendered map features that intersect with the given
@@ -1402,7 +1402,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect NS_SWIFT_NAME(visibleFeatures(in:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect NS_SWIFT_NAME(visibleFeatures(in:));
/**
Returns an array of rendered map features that intersect with the given
@@ -1421,7 +1421,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:));
/**
Returns an array of rendered map features that intersect with the given
@@ -1493,7 +1493,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:predicate:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:predicate:));
#pragma mark Debugging the Map
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index 71f308caf0..26b23abb4e 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -194,14 +194,14 @@ public:
@property (nonatomic) GLKView *glView;
@property (nonatomic) UIImageView *glSnapshotView;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *scaleBarConstraints;
+@property (nonatomic) NSMutableArray<NSLayoutConstraint *> *scaleBarConstraints;
@property (nonatomic, readwrite) MGLScaleBar *scaleBar;
@property (nonatomic, readwrite) UIImageView *compassView;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *compassViewConstraints;
+@property (nonatomic) NSMutableArray<NSLayoutConstraint *> *compassViewConstraints;
@property (nonatomic, readwrite) UIImageView *logoView;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *logoViewConstraints;
+@property (nonatomic) NSMutableArray<NSLayoutConstraint *> *logoViewConstraints;
@property (nonatomic, readwrite) UIButton *attributionButton;
-@property (nonatomic) NS_MUTABLE_ARRAY_OF(NSLayoutConstraint *) *attributionButtonConstraints;
+@property (nonatomic) NSMutableArray<NSLayoutConstraint *> *attributionButtonConstraints;
@property (nonatomic, readwrite) MGLStyle *style;
@@ -217,7 +217,7 @@ public:
@property (nonatomic) MGLCameraChangeReason cameraChangeReasonBitmask;
/// Mapping from reusable identifiers to annotation images.
-@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLAnnotationImage *) *annotationImagesByIdentifier;
+@property (nonatomic) NSMutableDictionary<NSString *, MGLAnnotationImage *> *annotationImagesByIdentifier;
/// Currently shown popover representing the selected annotation.
@property (nonatomic) UIView<MGLCalloutView> *calloutViewForSelectedAnnotation;
@@ -235,7 +235,7 @@ public:
@property (nonatomic) MGLMapViewProxyAccessibilityElement *mapViewProxyAccessibilityElement;
@property (nonatomic) MGLAnnotationContainerView *annotationContainerView;
@property (nonatomic) MGLUserLocation *userLocation;
-@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, NS_MUTABLE_ARRAY_OF(MGLAnnotationView *) *) *annotationViewReuseQueueByIdentifier;
+@property (nonatomic) NSMutableDictionary<NSString *, NSMutableArray<MGLAnnotationView *> *> *annotationViewReuseQueueByIdentifier;
@end
@@ -287,9 +287,9 @@ public:
BOOL _delegateHasLineWidthsForShapeAnnotations;
MGLCompassDirectionFormatter *_accessibilityCompassFormatter;
- NS_ARRAY_OF(id <MGLFeature>) *_visiblePlaceFeatures;
- NS_ARRAY_OF(id <MGLFeature>) *_visibleRoadFeatures;
- NS_MUTABLE_SET_OF(MGLFeatureAccessibilityElement *) *_featureAccessibilityElements;
+ NSArray<id <MGLFeature>> *_visiblePlaceFeatures;
+ NSArray<id <MGLFeature>> *_visibleRoadFeatures;
+ NSMutableSet<MGLFeatureAccessibilityElement *> *_featureAccessibilityElements;
BOOL _accessibilityValueAnnouncementIsPending;
MGLReachability *_reachability;
@@ -335,12 +335,12 @@ public:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyle
++ (NSSet<NSString *> *)keyPathsForValuesAffectingStyle
{
return [NSSet setWithObject:@"styleURL"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyleURL
++ (NSSet<NSString *> *)keyPathsForValuesAffectingStyleURL
{
return [NSSet setWithObjects:@"styleURL__", nil];
}
@@ -624,18 +624,8 @@ public:
UIGraphicsBeginImageContextWithOptions(scaleImage.size, NO, [UIScreen mainScreen].scale);
[scaleImage drawInRect:{ CGPointZero, scaleImage.size }];
- CGFloat northSize = 11;
- UIFont *northFont;
- if ([UIFont respondsToSelector:@selector(systemFontOfSize:weight:)])
- {
- northFont = [UIFont systemFontOfSize:northSize weight:UIFontWeightUltraLight];
- }
- else
- {
- northFont = [UIFont systemFontOfSize:northSize];
- }
NSAttributedString *north = [[NSAttributedString alloc] initWithString:NSLocalizedStringWithDefaultValue(@"COMPASS_NORTH", nil, nil, @"N", @"Compass abbreviation for north") attributes:@{
- NSFontAttributeName: northFont,
+ NSFontAttributeName: [UIFont systemFontOfSize:11 weight:UIFontWeightUltraLight],
NSForegroundColorAttributeName: [UIColor whiteColor],
}];
CGRect stringRect = CGRectMake((scaleImage.size.width - north.size.width) / 2,
@@ -1273,7 +1263,7 @@ public:
}
}
-- (void)touchesBegan:(__unused NS_SET_OF(UITouch *) *)touches withEvent:(__unused UIEvent *)event
+- (void)touchesBegan:(__unused NSSet<UITouch *> *)touches withEvent:(__unused UIEvent *)event
{
_changeDelimiterSuppressionDepth = 0;
_mbglMap->setGestureInProgress(false);
@@ -2238,22 +2228,22 @@ public:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomEnabled
++ (NSSet<NSString *> *)keyPathsForValuesAffectingZoomEnabled
{
return [NSSet setWithObject:@"allowsZooming"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingScrollEnabled
++ (NSSet<NSString *> *)keyPathsForValuesAffectingScrollEnabled
{
return [NSSet setWithObject:@"allowsScrolling"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingRotateEnabled
++ (NSSet<NSString *> *)keyPathsForValuesAffectingRotateEnabled
{
return [NSSet setWithObject:@"allowsRotating"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingPitchEnabled
++ (NSSet<NSString *> *)keyPathsForValuesAffectingPitchEnabled
{
return [NSSet setWithObject:@"allowsTilting"];
}
@@ -2419,7 +2409,7 @@ public:
return value;
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visiblePlaceFeatures
+- (NSArray<id <MGLFeature>> *)visiblePlaceFeatures
{
if (!_visiblePlaceFeatures)
{
@@ -2429,7 +2419,7 @@ public:
return _visiblePlaceFeatures;
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleRoadFeatures
+- (NSArray<id <MGLFeature>> *)visibleRoadFeatures
{
if (!_visibleRoadFeatures)
{
@@ -2907,7 +2897,7 @@ public:
#pragma mark - Geography -
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCenterCoordinate
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCenterCoordinate
{
return [NSSet setWithObjects:@"latitude", @"longitude", @"camera", nil];
}
@@ -2998,7 +2988,7 @@ public:
_mbglMap->easeTo(cameraOptions, animationOptions);
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomLevel
++ (NSSet<NSString *> *)keyPathsForValuesAffectingZoomLevel
{
return [NSSet setWithObject:@"camera"];
}
@@ -3167,7 +3157,7 @@ public:
[self didChangeValueForKey:@"visibleCoordinateBounds"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingDirection
++ (NSSet<NSString *> *)keyPathsForValuesAffectingDirection
{
return [NSSet setWithObject:@"camera"];
}
@@ -3217,12 +3207,12 @@ public:
[self setDirection:direction animated:NO];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingPitch
++ (NSSet<NSString *> *)keyPathsForValuesAffectingPitch
{
return [NSSet setWithObject:@"camera"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCamera
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCamera
{
return [NSSet setWithObjects:@"longitude", @"latitude", @"centerCoordinate", @"zoomLevel", @"direction", nil];
}
@@ -3496,7 +3486,7 @@ public:
#pragma mark - Annotations -
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)annotations
+- (nullable NSArray<id <MGLAnnotation>> *)annotations
{
if (_annotationContextsByAnnotationTag.empty())
{
@@ -3520,12 +3510,12 @@ public:
return [NSArray arrayWithObjects:&annotations[0] count:annotations.size()];
}
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotations
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotations
{
return [self visibleAnnotationsInRect:self.bounds];
}
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotationsInRect:(CGRect)rect
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotationsInRect:(CGRect)rect
{
if (_annotationContextsByAnnotationTag.empty())
{
@@ -3599,7 +3589,7 @@ public:
[self addAnnotations:@[ annotation ]];
}
-- (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations
+- (void)addAnnotations:(NSArray<id <MGLAnnotation>> *)annotations
{
if ( ! annotations) return;
[self willChangeValueForKey:@"annotations"];
@@ -3740,7 +3730,7 @@ public:
UIAccessibilityPostNotification(UIAccessibilityLayoutChangedNotification, nil);
}
-- (void)updateAnnotationContainerViewWithAnnotationViews:(NS_ARRAY_OF(MGLAnnotationView *) *)annotationViews
+- (void)updateAnnotationContainerViewWithAnnotationViews:(NSArray<MGLAnnotationView *> *)annotationViews
{
if (annotationViews.count == 0) return;
@@ -3895,7 +3885,7 @@ public:
[self removeAnnotations:@[ annotation ]];
}
-- (void)removeAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations
+- (void)removeAnnotations:(NSArray<id <MGLAnnotation>> *)annotations
{
if ( ! annotations) return;
@@ -3956,11 +3946,11 @@ public:
}
}
-- (nonnull NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+- (nonnull NSArray<id <MGLOverlay>> *)overlays
{
if (self.annotations == nil) { return @[]; }
- NS_MUTABLE_ARRAY_OF(id <MGLOverlay>) *mutableOverlays = [NSMutableArray array];
+ NSMutableArray<id <MGLOverlay>> *mutableOverlays = [NSMutableArray array];
[self.annotations enumerateObjectsUsingBlock:^(id<MGLAnnotation> _Nonnull annotation, NSUInteger idx, BOOL * _Nonnull stop) {
if ([annotation conformsToProtocol:@protocol(MGLOverlay)])
@@ -3977,7 +3967,7 @@ public:
[self addOverlays:@[ overlay ]];
}
-- (void)addOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+- (void)addOverlays:(NSArray<id <MGLOverlay>> *)overlays
{
#if DEBUG
for (id <MGLOverlay> overlay in overlays)
@@ -3994,7 +3984,7 @@ public:
[self removeOverlays:@[ overlay ]];
}
-- (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+- (void)removeOverlays:(NSArray<id <MGLOverlay>> *)overlays
{
#if DEBUG
for (id <MGLOverlay> overlay in overlays)
@@ -4226,13 +4216,13 @@ public:
[self didChangeValueForKey:@"selectedAnnotations"];
}
-- (NS_ARRAY_OF(id <MGLAnnotation>) *)selectedAnnotations
+- (NSArray<id <MGLAnnotation>> *)selectedAnnotations
{
id <MGLAnnotation> selectedAnnotation = self.selectedAnnotation;
return (selectedAnnotation ? @[ selectedAnnotation ] : @[]);
}
-- (void)setSelectedAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)selectedAnnotations
+- (void)setSelectedAnnotations:(NSArray<id <MGLAnnotation>> *)selectedAnnotations
{
if ( ! selectedAnnotations.count) return;
@@ -4599,7 +4589,7 @@ public:
completion:NULL];
}
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations animated:(BOOL)animated
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations animated:(BOOL)animated
{
CGFloat maximumPadding = 100;
CGFloat yPadding = (self.frame.size.height / 5 <= maximumPadding) ? (self.frame.size.height / 5) : maximumPadding;
@@ -4610,7 +4600,7 @@ public:
[self showAnnotations:annotations edgePadding:edgeInsets animated:animated];
}
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(UIEdgeInsets)insets animated:(BOOL)animated
{
if ( ! annotations || ! annotations.count) return;
@@ -4798,7 +4788,7 @@ public:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingUserLocation
++ (NSSet<NSString *> *)keyPathsForValuesAffectingUserLocation
{
return [NSSet setWithObject:@"userLocationAnnotationView"];
}
@@ -5289,16 +5279,16 @@ public:
#pragma mark Data
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point
{
return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers {
return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:styleLayerIdentifiers predicate:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(NSPredicate *)predicate
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers predicate:(NSPredicate *)predicate
{
mbgl::ScreenCoordinate screenCoordinate = { point.x, point.y };
@@ -5323,15 +5313,15 @@ public:
return MGLFeaturesFromMBGLFeatures(features);
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect {
return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers {
return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:styleLayerIdentifiers predicate:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
mbgl::ScreenBox screenBox = {
{ CGRectGetMinX(rect), CGRectGetMinY(rect) },
{ CGRectGetMaxX(rect), CGRectGetMaxY(rect) },
@@ -6065,7 +6055,7 @@ public:
views:views]];
}
-- (NS_MUTABLE_ARRAY_OF(MGLAnnotationView *) *)annotationViewReuseQueueForIdentifier:(NSString *)identifier {
+- (NSMutableArray<MGLAnnotationView *> *)annotationViewReuseQueueForIdentifier:(NSString *)identifier {
if (!_annotationViewReuseQueueByIdentifier[identifier])
{
_annotationViewReuseQueueByIdentifier[identifier] = [NSMutableArray array];
@@ -6222,7 +6212,7 @@ private:
@implementation MGLMapView (IBAdditions)
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyleURL__
++ (NSSet<NSString *> *)keyPathsForValuesAffectingStyleURL__
{
return [NSSet setWithObject:@"styleURL"];
}
@@ -6245,7 +6235,7 @@ private:
self.styleURL = url;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLatitude
++ (NSSet<NSString *> *)keyPathsForValuesAffectingLatitude
{
return [NSSet setWithObjects:@"centerCoordinate", @"camera", nil];
}
@@ -6271,7 +6261,7 @@ private:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLongitude
++ (NSSet<NSString *> *)keyPathsForValuesAffectingLongitude
{
return [NSSet setWithObjects:@"centerCoordinate", @"camera", nil];
}
@@ -6297,7 +6287,7 @@ private:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsZooming
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsZooming
{
return [NSSet setWithObject:@"zoomEnabled"];
}
@@ -6312,7 +6302,7 @@ private:
self.zoomEnabled = allowsZooming;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsScrolling
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsScrolling
{
return [NSSet setWithObject:@"scrollEnabled"];
}
@@ -6327,7 +6317,7 @@ private:
self.scrollEnabled = allowsScrolling;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsRotating
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsRotating
{
return [NSSet setWithObject:@"rotateEnabled"];
}
@@ -6342,7 +6332,7 @@ private:
self.rotateEnabled = allowsRotating;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsTilting
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsTilting
{
return [NSSet setWithObject:@"pitchEnabled"];
}
@@ -6357,7 +6347,7 @@ private:
self.pitchEnabled = allowsTilting;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingShowsHeading
++ (NSSet<NSString *> *)keyPathsForValuesAffectingShowsHeading
{
return [NSSet setWithObject:@"showsUserHeadingIndicator"];
}
diff --git a/platform/ios/src/MGLMapViewDelegate.h b/platform/ios/src/MGLMapViewDelegate.h
index 0368d8413c..201e3db84b 100644
--- a/platform/ios/src/MGLMapViewDelegate.h
+++ b/platform/ios/src/MGLMapViewDelegate.h
@@ -428,7 +428,7 @@ NS_ASSUME_NONNULL_BEGIN
@param annotationViews An array of `MGLAnnotationView` objects representing the
views that were added.
*/
-- (void)mapView:(MGLMapView *)mapView didAddAnnotationViews:(NS_ARRAY_OF(MGLAnnotationView *) *)annotationViews;
+- (void)mapView:(MGLMapView *)mapView didAddAnnotationViews:(NSArray<MGLAnnotationView *> *)annotationViews;
#pragma mark Selecting Annotations
diff --git a/platform/ios/src/MGLScaleBar.mm b/platform/ios/src/MGLScaleBar.mm
index 139dffdfab..a2fc24c75c 100644
--- a/platform/ios/src/MGLScaleBar.mm
+++ b/platform/ios/src/MGLScaleBar.mm
@@ -178,12 +178,7 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
#pragma mark - Convenience methods
- (BOOL)usesRightToLeftLayout {
- // semanticContentAttribute is iOS 9+
- if ([self.superview respondsToSelector:@selector(semanticContentAttribute)]) {
- return [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.superview.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft;
- } else {
- return UIApplication.sharedApplication.userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft;
- }
+ return [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.superview.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft;
}
- (BOOL)usesMetricSystem {
diff --git a/platform/ios/src/MGLUserLocation.m b/platform/ios/src/MGLUserLocation.m
index 074d138a72..245cbf4371 100644
--- a/platform/ios/src/MGLUserLocation.m
+++ b/platform/ios/src/MGLUserLocation.m
@@ -68,7 +68,7 @@ NS_ASSUME_NONNULL_END
return ! [key isEqualToString:@"location"] && ! [key isEqualToString:@"heading"];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCoordinate
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCoordinate
{
return [NSSet setWithObject:@"location"];
}
diff --git a/platform/ios/test/MGLMapAccessibilityElementTests.m b/platform/ios/test/MGLMapAccessibilityElementTests.m
index 89a595421e..916461e708 100644
--- a/platform/ios/test/MGLMapAccessibilityElementTests.m
+++ b/platform/ios/test/MGLMapAccessibilityElementTests.m
@@ -25,11 +25,7 @@
@"name_en": @"Цинциннати",
};
element = [[MGLFeatureAccessibilityElement alloc] initWithAccessibilityContainer:self feature:feature];
- if (@available(iOS 9.0, *)) {
- XCTAssertEqualObjects(element.accessibilityLabel, @"Cincinnati", @"Accessibility label should be romanized.");
- } else {
- XCTAssertEqualObjects(element.accessibilityLabel, @"Цинциннати", @"Accessibility label should not be romanized.");
- }
+ XCTAssertEqualObjects(element.accessibilityLabel, @"Cincinnati", @"Accessibility label should be romanized.");
}
- (void)testPlaceFeatureValues {
diff --git a/platform/linux/README.md b/platform/linux/README.md
index 8b8ac9d089..a8a4d459ee 100644
--- a/platform/linux/README.md
+++ b/platform/linux/README.md
@@ -6,7 +6,7 @@ We are using Ubuntu for development. While the software should work on other dis
This process gives you a Linux desktop app built on a Linux host system.
-### Build
+### Prerequisites
Install GCC 4.9+ if you are running Ubuntu 14.04 or older. Alternatively, you can also use [Clang 3.5+](http://llvm.org/apt/).
@@ -15,9 +15,6 @@ Install GCC 4.9+ if you are running Ubuntu 14.04 or older. Alternatively, you ca
sudo apt-get install gcc-4.9 g++-4.9
export CXX=g++-4.9
-**Note**: We partially support C++14 because GCC 4.9 does not fully implement the
-final draft of the C++14 standard. More information in [DEVELOPING.md](DEVELOPING.md).
-
Ensure you have git and other build essentials:
sudo apt-get install curl git build-essential zlib1g-dev automake \
@@ -38,6 +35,21 @@ Install glfw3 dependencies:
x11proto-xf86vidmode-dev libxxf86vm-dev \
libxcursor-dev libxinerama-dev
+[Node.js](https://nodejs.org/) 4.2.1 or later is also required.
+
+[ccache](https://ccache.samba.org) is optional, but improves recompilation performance.
+
+## Build
+
+Clone the git repository:
+
+ git clone https://github.com/mapbox/mapbox-gl-native.git
+ cd mapbox-gl-native
+
+Note that this repository uses Git submodules. They'll be automatically checked out when you first run a `make` command,
+but are not updated automatically. We recommended that you run `git submodule update` after pulling down new commits to
+this repository.
+
Set the environment variable `MAPBOX_ACCESS_TOKEN` to your [Mapbox access token](ACCESS_TOKEN.md):
export MAPBOX_ACCESS_TOKEN=MYTOKEN
diff --git a/platform/linux/config.cmake b/platform/linux/config.cmake
index dd5f0af112..53683daef0 100644
--- a/platform/linux/config.cmake
+++ b/platform/linux/config.cmake
@@ -11,7 +11,22 @@ mason_use(benchmark VERSION 1.2.0)
mason_use(icu VERSION 58.1-min-size)
mason_use(args VERSION 6.2.0 HEADER_ONLY)
-include(cmake/loop-uv.cmake)
+add_library(mbgl-loop-uv STATIC
+ platform/default/async_task.cpp
+ platform/default/run_loop.cpp
+ platform/default/timer.cpp
+)
+
+target_include_directories(mbgl-loop-uv
+ PRIVATE include
+ PRIVATE src
+)
+
+target_link_libraries(mbgl-loop-uv
+ PRIVATE mbgl-core
+)
+
+target_add_mason_package(mbgl-loop-uv PUBLIC libuv)
macro(mbgl_platform_core)
target_add_mason_package(mbgl-core PUBLIC mesa)
@@ -110,8 +125,6 @@ macro(mbgl_platform_glfw)
PRIVATE mbgl-loop-uv
)
- target_add_mason_package(mbgl-glfw PUBLIC libuv)
-
add_custom_command(
TARGET mbgl-glfw POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
@@ -126,8 +139,6 @@ macro(mbgl_platform_render)
PRIVATE mbgl-filesource
PRIVATE mbgl-loop-uv
)
-
- target_add_mason_package(mbgl-render PUBLIC libuv)
endmacro()
@@ -136,8 +147,6 @@ macro(mbgl_platform_offline)
PRIVATE mbgl-filesource
PRIVATE mbgl-loop-uv
)
-
- target_add_mason_package(mbgl-offline PUBLIC libuv)
endmacro()
@@ -160,8 +169,6 @@ macro(mbgl_platform_test)
PRIVATE mbgl-filesource
PRIVATE mbgl-loop-uv
)
-
- target_add_mason_package(mbgl-test PUBLIC libuv)
endmacro()
@@ -180,8 +187,6 @@ macro(mbgl_platform_benchmark)
PRIVATE mbgl-filesource
PRIVATE mbgl-loop-uv
)
-
- target_add_mason_package(mbgl-benchmark PUBLIC libuv)
endmacro()
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 6c01d7add5..ab71e62ec6 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -1,5 +1,11 @@
# Changelog for Mapbox Maps SDK for macOS
+## master
+
+### Packaging
+
+* The minimum deployment target for this SDK is now macOS 10.11.0. ([#11776](https://github.com/mapbox/mapbox-gl-native/pull/11776))
+
## 0.7.1
### Style layers
diff --git a/platform/macos/DEVELOPING.md b/platform/macos/DEVELOPING.md
index bac5683266..f4d946c527 100644
--- a/platform/macos/DEVELOPING.md
+++ b/platform/macos/DEVELOPING.md
@@ -4,24 +4,10 @@ This document explains how to build the Mapbox Maps SDK for macOS from source. I
## Requirements
-The Mapbox Maps SDK for macOS and the macosapp demo application run on macOS 10.10.0 or above.
-
-The Mapbox Maps SDK for macOS requires Xcode 8.0 or above.
+See the "Requirements" section in [INSTALL.md](INSTALL.md).
## Building the SDK
-1. [Install core dependencies](../../INSTALL.md).
-1. Run `make xproj`.
-1. Switch to the “dynamic” or “macosapp” scheme. The former builds just the Cocoa framework, while the latter also builds a Cocoa demo application based on it.
-
-### Packaging builds
-
-Install [jazzy](https://github.com/realm/jazzy) for generating API documentation:
-
-```bash
-[sudo] gem install jazzy
-```
-
Build and package the SDK by using one of the following commands:
* `make xpackage` builds a dynamic framework in the Debug configuration, including debug symbols.
diff --git a/platform/macos/INSTALL.md b/platform/macos/INSTALL.md
index c723d3e062..f0fb0278be 100644
--- a/platform/macos/INSTALL.md
+++ b/platform/macos/INSTALL.md
@@ -6,19 +6,41 @@ This document explains how to build a development version of the Mapbox Maps SDK
The Mapbox Maps SDK for macOS requires the macOS 10.10.0 SDK (or above) and Xcode 8.0 (or above). To use this SDK with Xcode 7.3.1, download and use a symbols build from the [releases](https://github.com/mapbox/mapbox-gl-native/releases) page.
-### Building the SDK from source
-
-To build the SDK from source:
-
-1. [Install core dependencies](../../INSTALL.md).
+Before building, follow these steps to install prerequisites:
+1. Install [Xcode](https://developer.apple.com/xcode/)
+1. Launch Xcode and install any updates
+1. Install [Homebrew](http://brew.sh)
+1. Install [Node.js](https://nodejs.org/), [CMake](https://cmake.org/), and [ccache](https://ccache.samba.org):
+ ```
+ brew install node cmake ccache
+ ```
+1. Install [xcpretty](https://github.com/supermarin/xcpretty) (optional, used for prettifying command line builds):
+ ```
+ [sudo] gem install xcpretty
+ ```
1. Install [jazzy](https://github.com/realm/jazzy) for generating API documentation:
-
```
[sudo] gem install jazzy
```
-1. Run `make xpackage`, which produces a `Mapbox.framework` in the `build/macos/pkg/` folder.
+### Building the SDK from source
+
+To build the SDK from source:
+
+1. Clone the git repository:
+ ```
+ git clone https://github.com/mapbox/mapbox-gl-native.git
+ cd mapbox-gl-native
+ ```
+ Note that this repository uses Git submodules. They'll be automatically checked out when you first run a `make` command,
+ but are not updated automatically. We recommended that you run `git submodule update` after pulling down new commits to
+ this repository.
+1. Run:
+ ```
+ make xpackage
+ ```
+ This produces a `Mapbox.framework` in the `build/macos/pkg/` folder.
### Installation
diff --git a/platform/macos/Mapbox-macOS-SDK-symbols.podspec b/platform/macos/Mapbox-macOS-SDK-symbols.podspec
index 48e43c63bb..ef2772336d 100644
--- a/platform/macos/Mapbox-macOS-SDK-symbols.podspec
+++ b/platform/macos/Mapbox-macOS-SDK-symbols.podspec
@@ -20,7 +20,7 @@ Pod::Spec.new do |m|
}
m.platform = :osx
- m.osx.deployment_target = '10.10'
+ m.osx.deployment_target = '10.11'
m.requires_arc = true
diff --git a/platform/macos/Mapbox-macOS-SDK.podspec b/platform/macos/Mapbox-macOS-SDK.podspec
index 27151ae69d..16b63cb34d 100644
--- a/platform/macos/Mapbox-macOS-SDK.podspec
+++ b/platform/macos/Mapbox-macOS-SDK.podspec
@@ -20,7 +20,7 @@ Pod::Spec.new do |m|
}
m.platform = :osx
- m.osx.deployment_target = '10.10'
+ m.osx.deployment_target = '10.11'
m.requires_arc = true
diff --git a/platform/macos/app/AppDelegate.m b/platform/macos/app/AppDelegate.m
index 0d780424f9..f7b35d0c83 100644
--- a/platform/macos/app/AppDelegate.m
+++ b/platform/macos/app/AppDelegate.m
@@ -29,7 +29,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfResourcesCompleted {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCountOfResourcesCompleted {
return [NSSet setWithObjects:@"progress", nil];
}
@@ -37,7 +37,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
return self.progress.countOfResourcesCompleted;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfResourcesExpected {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCountOfResourcesExpected {
return [NSSet setWithObjects:@"progress", nil];
}
@@ -45,7 +45,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
return self.progress.countOfResourcesExpected;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfBytesCompleted {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCountOfBytesCompleted {
return [NSSet setWithObjects:@"progress", nil];
}
@@ -53,7 +53,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
return self.progress.countOfBytesCompleted;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfTilesCompleted {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCountOfTilesCompleted {
return [NSSet setWithObjects:@"progress", nil];
}
@@ -61,7 +61,7 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
return self.progress.countOfTilesCompleted;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCountOfTileBytesCompleted {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCountOfTileBytesCompleted {
return [NSSet setWithObjects:@"progress", nil];
}
@@ -157,11 +157,11 @@ NSString * const MGLLastMapDebugMaskDefaultsKey = @"MGLLastMapDebugMask";
- (void)handleGetURLEvent:(NSAppleEventDescriptor *)event withReplyEvent:(NSAppleEventDescriptor *)replyEvent {
// mapboxgl://?center=29.95,-90.066667&zoom=14&bearing=45&pitch=30
NSURL *url = [NSURL URLWithString:[event paramDescriptorForKeyword:keyDirectObject].stringValue];
- NS_MUTABLE_DICTIONARY_OF(NSString *, NSString *) *params = [[NSMutableDictionary alloc] init];
+ NSMutableDictionary<NSString *, NSString *> *params = [[NSMutableDictionary alloc] init];
for (NSString *param in [url.query componentsSeparatedByString:@"&"]) {
NSArray *parts = [param componentsSeparatedByString:@"="];
if (parts.count >= 2) {
- params[parts[0]] = [parts[1] stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
+ params[parts[0]] = [parts[1] stringByRemovingPercentEncoding];
}
}
diff --git a/platform/macos/app/MGLStyle+MBXAdditions.h b/platform/macos/app/MGLStyle+MBXAdditions.h
index dcaf42af28..29c2cda867 100644
--- a/platform/macos/app/MGLStyle+MBXAdditions.h
+++ b/platform/macos/app/MGLStyle+MBXAdditions.h
@@ -2,6 +2,6 @@
@interface MGLStyle (MBXAdditions)
-@property (nonatomic, strong) NS_ARRAY_OF(__kindof MGLStyleLayer *) *reversedLayers;
+@property (nonatomic, strong) NSArray<__kindof MGLStyleLayer *> *reversedLayers;
@end
diff --git a/platform/macos/app/MGLStyle+MBXAdditions.m b/platform/macos/app/MGLStyle+MBXAdditions.m
index be571d8b30..a0773cc2c0 100644
--- a/platform/macos/app/MGLStyle+MBXAdditions.m
+++ b/platform/macos/app/MGLStyle+MBXAdditions.m
@@ -2,15 +2,15 @@
@implementation MGLStyle (MBXAdditions)
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingReversedLayers {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingReversedLayers {
return [NSSet setWithObject:@"layers"];
}
-- (NS_ARRAY_OF(__kindof MGLStyleLayer *) *)reversedLayers {
+- (NSArray<__kindof MGLStyleLayer *> *)reversedLayers {
return self.layers.reverseObjectEnumerator.allObjects;
}
-- (void)setReversedLayers:(NS_ARRAY_OF(__kindof MGLStyleLayer *) *)reversedLayers {
+- (void)setReversedLayers:(NSArray<__kindof MGLStyleLayer *> *)reversedLayers {
self.layers = reversedLayers.reverseObjectEnumerator.allObjects;
}
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index aee14c5c2f..4ee6050565 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -19,7 +19,7 @@ static const CLLocationCoordinate2D WorldTourDestinations[] = {
{ .latitude = -13.15589555, .longitude = -74.2178961777998 },
};
-NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotation>) *shapes) {
+NSArray<id <MGLAnnotation>> *MBXFlattenedShapes(NSArray<id <MGLAnnotation>> *shapes) {
NSMutableArray *flattenedShapes = [NSMutableArray arrayWithCapacity:shapes.count];
for (id <MGLAnnotation> shape in shapes) {
NSArray *subshapes;
@@ -346,7 +346,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
- (void)toggleStyleLayersAtArrangedObjectIndexes:(NSIndexSet *)indices {
- NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
+ NSArray<MGLStyleLayer *> *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
BOOL isVisible = layers.firstObject.visible;
[self.undoManager registerUndoWithTarget:self handler:^(MapDocument * _Nonnull target) {
[target toggleStyleLayersAtArrangedObjectIndexes:indices];
@@ -382,7 +382,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self deleteStyleLayersAtArrangedObjectIndexes:indices];
}
-- (void)insertStyleLayers:(NS_ARRAY_OF(MGLStyleLayer *) *)layers atArrangedObjectIndexes:(NSIndexSet *)indices {
+- (void)insertStyleLayers:(NSArray<MGLStyleLayer *> *)layers atArrangedObjectIndexes:(NSIndexSet *)indices {
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self deleteStyleLayersAtArrangedObjectIndexes:indices];
}];
@@ -402,7 +402,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
}
- (void)deleteStyleLayersAtArrangedObjectIndexes:(NSIndexSet *)indices {
- NS_ARRAY_OF(MGLStyleLayer *) *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
+ NSArray<MGLStyleLayer *> *layers = [self.mapView.style.reversedLayers objectsAtIndexes:indices];
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self insertStyleLayers:layers atArrangedObjectIndexes:indices];
}];
@@ -578,7 +578,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
[self continueWorldTourWithRemainingAnnotations:annotations];
}
-- (void)continueWorldTourWithRemainingAnnotations:(NS_MUTABLE_ARRAY_OF(MGLPointAnnotation *) *)annotations {
+- (void)continueWorldTourWithRemainingAnnotations:(NSMutableArray<MGLPointAnnotation *> *)annotations {
MGLPointAnnotation *nextAnnotation = annotations.firstObject;
if (!nextAnnotation || !_isTouringWorld) {
_isTouringWorld = NO;
@@ -1242,7 +1242,7 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
#pragma mark NSSharingServicePickerDelegate methods
-- (NS_ARRAY_OF(NSSharingService *) *)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items proposedSharingServices:(NS_ARRAY_OF(NSSharingService *) *)proposedServices {
+- (NSArray<NSSharingService *> *)sharingServicePicker:(NSSharingServicePicker *)sharingServicePicker sharingServicesForItems:(NSArray *)items proposedSharingServices:(NSArray<NSSharingService *> *)proposedServices {
NSURL *shareURL = self.shareURL;
NSURL *browserURL = [[NSWorkspace sharedWorkspace] URLForApplicationToOpenURL:shareURL];
NSImage *browserIcon = [[NSWorkspace sharedWorkspace] iconForFile:browserURL.path];
diff --git a/platform/macos/config.cmake b/platform/macos/config.cmake
index e929bb55c6..28573258d9 100644
--- a/platform/macos/config.cmake
+++ b/platform/macos/config.cmake
@@ -6,7 +6,6 @@ mason_use(benchmark VERSION 1.2.0)
mason_use(icu VERSION 58.1-min-size)
mason_use(args VERSION 6.2.0 HEADER_ONLY)
-include(cmake/loop-uv.cmake)
include(cmake/loop-darwin.cmake)
macro(mbgl_platform_core)
diff --git a/platform/macos/docs/doc-README.md b/platform/macos/docs/doc-README.md
index 8089ae17d1..8ce2df39a4 100644
--- a/platform/macos/docs/doc-README.md
+++ b/platform/macos/docs/doc-README.md
@@ -1,6 +1,6 @@
# [Mapbox Maps SDK for macOS](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/macos/)
-The Mapbox Maps SDK for macOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, Interface Builder, or AppleScript. The SDK takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
+The Mapbox Maps SDK for macOS is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.11.0 and above using Objective-C, Swift, Interface Builder, or AppleScript. The SDK takes stylesheets that conform to the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL.
![](img/screenshot.jpg)
diff --git a/platform/macos/docs/pod-README.md b/platform/macos/docs/pod-README.md
index 97e77673ee..4827124be0 100644
--- a/platform/macos/docs/pod-README.md
+++ b/platform/macos/docs/pod-README.md
@@ -10,7 +10,7 @@ Put interactive, scalable world maps into your native Cocoa application with the
![](https://raw.githubusercontent.com/mapbox/mapbox-gl-native/master/platform/macos/docs/img/screenshot.jpg)
-The Mapbox Maps SDK for macOS is compatible with macOS 10.10.0 and above for Cocoa applications developed in Objective-C, Swift, Interface Builder, or AppleScript. For hybrid applications, consider [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/).
+The Mapbox Maps SDK for macOS is compatible with macOS 10.11.0 and above for Cocoa applications developed in Objective-C, Swift, Interface Builder, or AppleScript. For hybrid applications, consider [Mapbox GL JS](https://www.mapbox.com/mapbox-gl-js/).
## Installation
@@ -37,7 +37,7 @@ After running `carthage update`, you’ll find Mapbox.framework in the Carthage/
Create a [Podfile](https://guides.cocoapods.org/syntax/podfile.html) with the following specification:
```rb
-platform :osx, '10.10'
+platform :osx, '10.11'
target 'TargetNameForYourApp' do
pod 'Mapbox-iOS-SDK', '~> x.y'
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 5b17c61de2..4cb436fdbf 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -1833,7 +1833,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SYMROOT = "$(PROJECT_DIR)/cmake";
@@ -1886,7 +1886,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- MACOSX_DEPLOYMENT_TARGET = 10.10;
+ MACOSX_DEPLOYMENT_TARGET = 10.11;
MTL_ENABLE_DEBUG_INFO = NO;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SYMROOT = "$(PROJECT_DIR)/cmake";
diff --git a/platform/macos/src/MGLMapView+IBAdditions.mm b/platform/macos/src/MGLMapView+IBAdditions.mm
index eada47ef90..cef2863ee6 100644
--- a/platform/macos/src/MGLMapView+IBAdditions.mm
+++ b/platform/macos/src/MGLMapView+IBAdditions.mm
@@ -4,7 +4,7 @@
@implementation MGLMapView (IBAdditions)
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyleURL__ {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingStyleURL__ {
return [NSSet setWithObject:@"styleURL"];
}
@@ -23,7 +23,7 @@
self.styleURL = url;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLatitude {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingLatitude {
return [NSSet setWithObjects:@"centerCoordinate", @"camera", nil];
}
@@ -45,7 +45,7 @@
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingLongitude {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingLongitude {
return [NSSet setWithObjects:@"centerCoordinate", @"camera", nil];
}
@@ -67,7 +67,7 @@
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsZooming {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsZooming {
return [NSSet setWithObject:@"zoomEnabled"];
}
@@ -79,7 +79,7 @@
self.zoomEnabled = allowsZooming;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsScrolling {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsScrolling {
return [NSSet setWithObject:@"scrollEnabled"];
}
@@ -91,7 +91,7 @@
self.scrollEnabled = allowsScrolling;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsRotating {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsRotating {
return [NSSet setWithObject:@"rotateEnabled"];
}
@@ -103,7 +103,7 @@
self.rotateEnabled = allowsRotating;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingAllowsTilting {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingAllowsTilting {
return [NSSet setWithObject:@"pitchEnabled"];
}
diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h
index e3de1069a9..824df827ac 100644
--- a/platform/macos/src/MGLMapView.h
+++ b/platform/macos/src/MGLMapView.h
@@ -443,7 +443,7 @@ MGL_EXPORT IB_DESIGNABLE
@param animated `YES` if you want the map region change to be animated, or `NO`
if you want the map to display the new region immediately without animations.
*/
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations animated:(BOOL)animated;
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations animated:(BOOL)animated;
/**
Sets the visible region so that the map displays the specified annotations with
@@ -458,7 +458,7 @@ MGL_EXPORT IB_DESIGNABLE
@param animated `YES` if you want the map region change to be animated, or `NO`
if you want the map to display the new region immediately without animations.
*/
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated;
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated;
/**
Returns the camera that best fits the given coordinate bounds.
@@ -621,7 +621,7 @@ MGL_EXPORT IB_DESIGNABLE
annotations are associated with the map view, the value of this property is
`nil`.
*/
-@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *annotations;
+@property (nonatomic, readonly, nullable) NSArray<id <MGLAnnotation>> *annotations;
/**
Adds an annotation to the map view.
@@ -651,7 +651,7 @@ MGL_EXPORT IB_DESIGNABLE
must conform to the `MGLAnnotation` protocol. The map view retains each
individual annotation object.
*/
-- (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations;
+- (void)addAnnotations:(NSArray<id <MGLAnnotation>> *)annotations;
/**
The complete list of annotations associated with the receiver that are
@@ -661,7 +661,7 @@ MGL_EXPORT IB_DESIGNABLE
annotations are associated with the map view or if no annotations associated
with the map view are currently visible, the value of this property is `nil`.
*/
-@property (nonatomic, readonly, nullable) NS_ARRAY_OF(id <MGLAnnotation>) *visibleAnnotations;
+@property (nonatomic, readonly, nullable) NSArray<id <MGLAnnotation>> *visibleAnnotations;
/**
Removes an annotation from the map view, deselecting it if it is selected.
@@ -686,7 +686,7 @@ MGL_EXPORT IB_DESIGNABLE
@param annotations The array of annotation objects to remove. Objects in the
array must conform to the `MGLAnnotation` protocol.
*/
-- (void)removeAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations;
+- (void)removeAnnotations:(NSArray<id <MGLAnnotation>> *)annotations;
/**
Returns a reusable annotation image object associated with its identifier.
@@ -712,7 +712,7 @@ MGL_EXPORT IB_DESIGNABLE
no annotations associated with the map view are currently visible in the
rectangle.
*/
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotationsInRect:(CGRect)rect;
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotationsInRect:(CGRect)rect;
#pragma mark Managing Annotation Selections
@@ -729,7 +729,7 @@ MGL_EXPORT IB_DESIGNABLE
@note In versions prior to `4.0.0` if the annotation was offscreen it was not
selected.
*/
-@property (nonatomic, copy) NS_ARRAY_OF(id <MGLAnnotation>) *selectedAnnotations;
+@property (nonatomic, copy) NSArray<id <MGLAnnotation>> *selectedAnnotations;
/**
Selects an annotation and displays a callout popover for it.
@@ -791,7 +791,7 @@ MGL_EXPORT IB_DESIGNABLE
overlays are associated with the map view, the value of this property is
empty array.
*/
-@property (nonatomic, readonly, nonnull) NS_ARRAY_OF(id <MGLOverlay>) *overlays;
+@property (nonatomic, readonly, nonnull) NSArray<id <MGLOverlay>> *overlays;
/**
Adds a single overlay to the map.
@@ -811,7 +811,7 @@ MGL_EXPORT IB_DESIGNABLE
@param overlays An array of objects, each of which must conform to the
`MGLOverlay` protocol.
*/
-- (void)addOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
+- (void)addOverlays:(NSArray<id <MGLOverlay>> *)overlays;
/**
Removes a single overlay from the map.
@@ -831,7 +831,7 @@ MGL_EXPORT IB_DESIGNABLE
@param overlays An array of objects, each of which conforms to the `MGLOverlay`
protocol.
*/
-- (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays;
+- (void)removeOverlays:(NSArray<id <MGLOverlay>> *)overlays;
#pragma mark Accessing the Underlying Map Data
@@ -847,7 +847,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point NS_SWIFT_NAME(visibleFeatures(at:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point NS_SWIFT_NAME(visibleFeatures(at:));
/**
Returns an array of rendered map features that intersect with a given point,
@@ -866,7 +866,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
/**
Returns an array of rendered map features that intersect with a given point,
@@ -928,7 +928,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:predicate:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:predicate:));
/**
Returns an array of rendered map features that intersect with the given
@@ -943,7 +943,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect NS_SWIFT_NAME(visibleFeatures(in:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect NS_SWIFT_NAME(visibleFeatures(in:));
/**
Returns an array of rendered map features that intersect with the given
@@ -962,7 +962,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers NS_SWIFT_NAME(visibleFeatures(at:styleLayerIdentifiers:));
/**
Returns an array of rendered map features that intersect with the given
@@ -1026,7 +1026,7 @@ MGL_EXPORT IB_DESIGNABLE
@return An array of objects conforming to the `MGLFeature` protocol that
represent features in the sources used by the current style.
*/
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:predicate:));
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(nullable NSSet<NSString *> *)styleLayerIdentifiers predicate:(nullable NSPredicate *)predicate NS_SWIFT_NAME(visibleFeatures(in:styleLayerIdentifiers:predicate:));
#pragma mark Converting Geographic Coordinates
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 5b78dcca14..bc9ac1e641 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -149,7 +149,7 @@ public:
@property (nonatomic, readwrite) MGLStyle *style;
/// Mapping from reusable identifiers to annotation images.
-@property (nonatomic) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLAnnotationImage *) *annotationImagesByIdentifier;
+@property (nonatomic) NSMutableDictionary<NSString *, MGLAnnotationImage *> *annotationImagesByIdentifier;
/// Currently shown popover representing the selected annotation.
@property (nonatomic) NSPopover *calloutForSelectedAnnotation;
@@ -611,7 +611,7 @@ public:
#pragma mark Style
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingStyle {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingStyle {
return [NSSet setWithObject:@"styleURL"];
}
@@ -965,7 +965,7 @@ public:
#pragma mark Viewport
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCenterCoordinate {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCenterCoordinate {
return [NSSet setWithObjects:@"latitude", @"longitude", @"camera", nil];
}
@@ -1015,7 +1015,7 @@ public:
_pendingLongitude = pendingLongitude;
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingZoomLevel {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingZoomLevel {
return [NSSet setWithObject:@"camera"];
}
@@ -1083,7 +1083,7 @@ public:
}
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingDirection {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingDirection {
return [NSSet setWithObject:@"camera"];
}
@@ -1107,7 +1107,7 @@ public:
[self setDirection:_mbglMap->getBearing() + delta animated:animated];
}
-+ (NS_SET_OF(NSString *) *)keyPathsForValuesAffectingCamera {
++ (NSSet<NSString *> *)keyPathsForValuesAffectingCamera {
return [NSSet setWithObjects:@"latitude", @"longitude", @"centerCoordinate", @"zoomLevel", @"direction", nil];
}
@@ -1765,7 +1765,7 @@ public:
#pragma mark Annotations
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)annotations {
+- (nullable NSArray<id <MGLAnnotation>> *)annotations {
if (_annotationContextsByAnnotationTag.empty()) {
return nil;
}
@@ -1781,12 +1781,12 @@ public:
return [NSArray arrayWithObjects:&annotations[0] count:annotations.size()];
}
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotations
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotations
{
return [self visibleFeaturesInRect:self.bounds];
}
-- (nullable NS_ARRAY_OF(id <MGLAnnotation>) *)visibleAnnotationsInRect:(CGRect)rect
+- (nullable NSArray<id <MGLAnnotation>> *)visibleAnnotationsInRect:(CGRect)rect
{
if (_annotationContextsByAnnotationTag.empty())
{
@@ -1852,7 +1852,7 @@ public:
}
}
-- (void)addAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations {
+- (void)addAnnotations:(NSArray<id <MGLAnnotation>> *)annotations {
if (!annotations) {
return;
}
@@ -1987,7 +1987,7 @@ public:
}
}
-- (void)removeAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations {
+- (void)removeAnnotations:(NSArray<id <MGLAnnotation>> *)annotations {
if (!annotations) {
return;
}
@@ -2192,12 +2192,12 @@ public:
[self didChangeValueForKey:@"selectedAnnotations"];
}
-- (NS_ARRAY_OF(id <MGLAnnotation>) *)selectedAnnotations {
+- (NSArray<id <MGLAnnotation>> *)selectedAnnotations {
id <MGLAnnotation> selectedAnnotation = self.selectedAnnotation;
return selectedAnnotation ? @[selectedAnnotation] : @[];
}
-- (void)setSelectedAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)selectedAnnotations {
+- (void)setSelectedAnnotations:(NSArray<id <MGLAnnotation>> *)selectedAnnotations {
if (!selectedAnnotations.count) {
return;
}
@@ -2338,7 +2338,7 @@ public:
}
}
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations animated:(BOOL)animated {
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations animated:(BOOL)animated {
CGFloat maximumPadding = 100;
CGFloat yPadding = (NSHeight(self.bounds) / 5 <= maximumPadding) ? (NSHeight(self.bounds) / 5) : maximumPadding;
CGFloat xPadding = (NSWidth(self.bounds) / 5 <= maximumPadding) ? (NSWidth(self.bounds) / 5) : maximumPadding;
@@ -2348,7 +2348,7 @@ public:
[self showAnnotations:annotations edgePadding:edgeInsets animated:animated];
}
-- (void)showAnnotations:(NS_ARRAY_OF(id <MGLAnnotation>) *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated {
+- (void)showAnnotations:(NSArray<id <MGLAnnotation>> *)annotations edgePadding:(NSEdgeInsets)insets animated:(BOOL)animated {
if ( ! annotations || ! annotations.count) return;
mbgl::LatLngBounds bounds = mbgl::LatLngBounds::empty();
@@ -2547,11 +2547,11 @@ public:
#pragma mark Overlays
-- (nonnull NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+- (nonnull NSArray<id <MGLOverlay>> *)overlays
{
if (self.annotations == nil) { return @[]; }
- NS_MUTABLE_ARRAY_OF(id <MGLOverlay>) *mutableOverlays = [NSMutableArray array];
+ NSMutableArray<id <MGLOverlay>> *mutableOverlays = [NSMutableArray array];
[self.annotations enumerateObjectsUsingBlock:^(id<MGLAnnotation> _Nonnull annotation, NSUInteger idx, BOOL * _Nonnull stop) {
if ([annotation conformsToProtocol:@protocol(MGLOverlay)])
@@ -2567,7 +2567,7 @@ public:
[self addOverlays:@[overlay]];
}
-- (void)addOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+- (void)addOverlays:(NSArray<id <MGLOverlay>> *)overlays
{
#if DEBUG
for (id <MGLOverlay> overlay in overlays) {
@@ -2581,7 +2581,7 @@ public:
[self removeOverlays:@[overlay]];
}
-- (void)removeOverlays:(NS_ARRAY_OF(id <MGLOverlay>) *)overlays {
+- (void)removeOverlays:(NSArray<id <MGLOverlay>> *)overlays {
#if DEBUG
for (id <MGLOverlay> overlay in overlays) {
NSAssert([overlay conformsToProtocol:@protocol(MGLOverlay)], @"Overlay does not conform to MGLOverlay");
@@ -2662,15 +2662,15 @@ public:
#pragma mark Data
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point {
return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(CGPoint)point inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers {
return [self visibleFeaturesAtPoint:point inStyleLayersWithIdentifiers:styleLayerIdentifiers predicate:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesAtPoint:(NSPoint)point inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
// Cocoa origin is at the lower-left corner.
mbgl::ScreenCoordinate screenCoordinate = { point.x, NSHeight(self.bounds) - point.y };
@@ -2693,15 +2693,15 @@ public:
return MGLFeaturesFromMBGLFeatures(features);
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect {
return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(CGRect)rect inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers {
return [self visibleFeaturesInRect:rect inStyleLayersWithIdentifiers:styleLayerIdentifiers predicate:nil];
}
-- (NS_ARRAY_OF(id <MGLFeature>) *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(NS_SET_OF(NSString *) *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
+- (NSArray<id <MGLFeature>> *)visibleFeaturesInRect:(NSRect)rect inStyleLayersWithIdentifiers:(NSSet<NSString *> *)styleLayerIdentifiers predicate:(NSPredicate *)predicate {
// Cocoa origin is at the lower-left corner.
mbgl::ScreenBox screenBox = {
{ NSMinX(rect), NSHeight(self.bounds) - NSMaxY(rect) },
diff --git a/platform/node/DEVELOPING.md b/platform/node/DEVELOPING.md
index b313d75c13..215b06c7bf 100644
--- a/platform/node/DEVELOPING.md
+++ b/platform/node/DEVELOPING.md
@@ -4,11 +4,13 @@ This document explains how to build the [Node.js](https://nodejs.org/) bindings
## Building
-To develop these bindings, you’ll need to build them from source. Building requires [installing all of the basic dependencies needed for Mapbox GL Native](../../INSTALL.md), then running:
+To develop these bindings, you’ll need to build them from source. Building requires the prerequisites listed in either
+the [macOS](../macos/INSTALL.md#requirements) or [Linux](../linux/README.md#prerequisites) install documentation, depending
+on the target platform.
- npm install --build-from-source
+To compile the Node.js bindings and install module dependencies, from the repository root directory, run:
-From the root directory. This will compile the Node.js bindings and install module dependencies.
+ npm install --build-from-source
To recompile just the C++ code while developing, run `make node`.
diff --git a/platform/node/README.md b/platform/node/README.md
index d19b2a9343..ac5bcd7e8d 100644
--- a/platform/node/README.md
+++ b/platform/node/README.md
@@ -17,7 +17,8 @@ Run:
npm install @mapbox/mapbox-gl-native
```
-Other platforms will fall back to a source compile with `make node`; see INSTALL.md in the repository root directory for prequisites.
+Other platforms will fall back to a source compile with `make node`; see [DEVELOPING.md](DEVELOPING.md) for details on
+building from source.
## Testing
diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json
index e0c2475b75..47cb07c85a 100644
--- a/platform/node/test/ignores.json
+++ b/platform/node/test/ignores.json
@@ -1,15 +1,30 @@
{
- "query-tests/circle-pitch-scale/viewport-inside-align-map": "https://github.com/mapbox/mapbox-gl-native/issues/10615",
- "query-tests/circle-pitch-scale/viewport-inside-align-viewport": "https://github.com/mapbox/mapbox-gl-native/issues/10615",
- "query-tests/edge-cases/box-cutting-antimeridian-z0": "https://github.com/mapbox/mapbox-gl-native/issues/11607",
- "query-tests/edge-cases/null-island": "https://github.com/mapbox/mapbox-gl-native/issues/11607",
+ "expression-tests/collator/accent-equals-de": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/accent-lt-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/accent-not-equals-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/base-default-locale": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/base-equals-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/base-gt-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/case-lteq-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/case-not-equals-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/case-omitted-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/comparison-number-error": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/diacritic-omitted-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/equals-non-string-error": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/non-object-error": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/variant-equals-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/collator/variant-gteq-en": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/is-supported-script/default": "This tests RTL text plugin behavior specific to GL JS",
+ "expression-tests/resolved-locale/basic": "https://github.com/mapbox/mapbox-gl-native/issues/11692",
+ "expression-tests/to-string/basic": "https://github.com/mapbox/mapbox-gl-native/issues/11719",
"query-tests/geometry/multilinestring": "needs investigation",
"query-tests/geometry/multipolygon": "needs investigation",
"query-tests/geometry/polygon": "needs investigation",
- "query-tests/symbol/panned-after-insert": "https://github.com/mapbox/mapbox-gl-native/issues/10408",
- "query-tests/symbol/rotated-after-insert": "https://github.com/mapbox/mapbox-gl-native/issues/10408",
"query-tests/world-wrapping/box": "skip - needs issue",
"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/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/debug/collision": "https://github.com/mapbox/mapbox-gl-native/issues/3841",
"render-tests/debug/collision-lines": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
@@ -27,6 +42,8 @@
"render-tests/fill-extrusion-pattern/opacity": "https://github.com/mapbox/mapbox-gl-js/issues/3327",
"render-tests/geojson/inline-linestring-fill": "current behavior is arbitrary",
"render-tests/geojson/inline-polygon-symbol": "behavior needs reconciliation with gl-js",
+ "render-tests/line-gradient/gradient": "https://github.com/mapbox/mapbox-gl-native/issues/11718",
+ "render-tests/line-gradient/translucent": "https://github.com/mapbox/mapbox-gl-native/issues/11718",
"render-tests/mixed-zoom/z10-z11": "https://github.com/mapbox/mapbox-gl-native/issues/10397",
"render-tests/raster-masking/overlapping-zoom": "https://github.com/mapbox/mapbox-gl-native/issues/10195",
"render-tests/real-world/bangkok": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
@@ -92,5 +109,8 @@
"render-tests/combinations/fill-translucent--fill-extrusion-translucent": "needs investigation",
"render-tests/combinations/line-translucent--fill-extrusion-translucent": "needs investigation",
"render-tests/combinations/raster-translucent--fill-extrusion-translucent": "needs investigation",
- "render-tests/combinations/symbol-translucent--fill-extrusion-translucent": "needs investigation"
+ "render-tests/combinations/symbol-translucent--fill-extrusion-translucent": "needs investigation",
+ "render-tests/feature-state/composite-expression": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
+ "render-tests/feature-state/data-expression": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue",
+ "render-tests/feature-state/vector-source": "skip - port https://github.com/mapbox/mapbox-gl-js/pull/6263 - needs issue"
}
diff --git a/platform/qt/README.md b/platform/qt/README.md
index 4d2d887828..f083d4b519 100644
--- a/platform/qt/README.md
+++ b/platform/qt/README.md
@@ -1,4 +1,4 @@
-# Mapbox Qt SDK
+# Mapbox Maps SDK for Qt
[![Circle CI build status](https://circleci.com/gh/mapbox/mapbox-gl-native.svg?style=shield)](https://circleci.com/gh/mapbox/workflows/mapbox-gl-native/tree/master) [![AppVeyor CI build status](https://ci.appveyor.com/api/projects/status/3q12kbcooc6df8uc?svg=true)](https://ci.appveyor.com/project/Mapbox/mapbox-gl-native)
@@ -9,7 +9,7 @@ available in the Qt SDK since Qt 5.9. Use the [Qt bugtracker](https://bugreports
to the plugin and this GitHub repository for bugs related to Mapbox GL Native and the Qt bindings.
You should build this repository if you want to develop/contribute using the low level Qt C++ bindings or
-want to contribute to the Mapbox GL Native projectusing the Qt port for debugging.
+want to contribute to the Mapbox GL Native project using the Qt port for debugging.
See the Mapbox Qt landing page for more details: https://www.mapbox.com/qt/
@@ -17,9 +17,7 @@ See the Mapbox Qt landing page for more details: https://www.mapbox.com/qt/
#### Linux
-For Linux (tested on Ubuntu) desktop, together with these [build
-instructions](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/linux#build),
-you also need:
+For Linux (tested on Ubuntu) desktop, together with these [build instructions](../linux/README.md), you also need:
```
$ sudo apt-get install qt5-default
@@ -55,8 +53,7 @@ At runtime, you will also need installed:
### Build instructions
-Public API headers
-can be found in the [platform/qt/include](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/qt/include) directory.
+Public API headers can be found in the [platform/qt/include](qt/include) directory.
#### Linux and macOS
diff --git a/platform/qt/app/mapwindow.cpp b/platform/qt/app/mapwindow.cpp
index f6d5473192..390d89915a 100644
--- a/platform/qt/app/mapwindow.cpp
+++ b/platform/qt/app/mapwindow.cpp
@@ -22,6 +22,13 @@ MapWindow::MapWindow(const QMapboxGLSettings &settings)
setWindowIcon(QIcon(":icon.png"));
}
+MapWindow::~MapWindow()
+{
+ // Make sure we have a valid context so we
+ // can delete the QMapboxGL.
+ makeCurrent();
+}
+
void MapWindow::selfTest()
{
if (m_bearingAnimation) {
diff --git a/platform/qt/app/mapwindow.hpp b/platform/qt/app/mapwindow.hpp
index c484114ec0..6c05f03562 100644
--- a/platform/qt/app/mapwindow.hpp
+++ b/platform/qt/app/mapwindow.hpp
@@ -29,6 +29,7 @@ class MapWindow : public QGLWidget
public:
MapWindow(const QMapboxGLSettings &);
+ ~MapWindow();
void selfTest();
diff --git a/platform/qt/config.qdocconf b/platform/qt/config.qdocconf
index d6f0edbd32..9d3b8a7ef4 100644
--- a/platform/qt/config.qdocconf
+++ b/platform/qt/config.qdocconf
@@ -7,7 +7,7 @@ include($QT_INSTALL_DOCS/global/qt-html-templates-online.qdocconf)
Cpp.ignoretokens = Q_MAPBOXGL_EXPORT
project = QMapboxGL
-description = Mapbox Qt SDK
+description = Mapbox Maps SDK for Qt
language = Cpp
outputdir = docs
diff --git a/platform/qt/include/qmapbox.hpp b/platform/qt/include/qmapbox.hpp
index 369890343f..1ab04403cf 100644
--- a/platform/qt/include/qmapbox.hpp
+++ b/platform/qt/include/qmapbox.hpp
@@ -9,10 +9,14 @@
// This header follows the Qt coding style: https://wiki.qt.io/Qt_Coding_Style
-#if defined(QT_BUILD_MAPBOXGL_LIB)
- #define Q_MAPBOXGL_EXPORT Q_DECL_EXPORT
+#if !defined(QT_MAPBOXGL_STATIC)
+# if defined(QT_BUILD_MAPBOXGL_LIB)
+# define Q_MAPBOXGL_EXPORT Q_DECL_EXPORT
+# else
+# define Q_MAPBOXGL_EXPORT Q_DECL_IMPORT
+# endif
#else
- #define Q_MAPBOXGL_EXPORT Q_DECL_IMPORT
+# define Q_MAPBOXGL_EXPORT
#endif
namespace QMapbox {
diff --git a/platform/qt/include/qmapboxgl.hpp b/platform/qt/include/qmapboxgl.hpp
index 70fe270902..79eb672d1f 100644
--- a/platform/qt/include/qmapboxgl.hpp
+++ b/platform/qt/include/qmapboxgl.hpp
@@ -128,6 +128,13 @@ public:
MapChangeSourceDidChange
};
+ enum MapLoadingFailure {
+ StyleParseFailure,
+ StyleLoadFailure,
+ NotFoundFailure,
+ UnknownFailure
+ };
+
// Determines the orientation of the map.
enum NorthOrientation {
NorthUpwards, // Default
@@ -248,6 +255,7 @@ public slots:
signals:
void needsRendering();
void mapChanged(QMapboxGL::MapChange);
+ void mapLoadingFailed(QMapboxGL::MapLoadingFailure, const QString &reason);
void copyrightsChanged(const QString &copyrightsHtml);
void staticRenderFinished(const QString &error);
@@ -259,5 +267,6 @@ private:
};
Q_DECLARE_METATYPE(QMapboxGL::MapChange);
+Q_DECLARE_METATYPE(QMapboxGL::MapLoadingFailure);
#endif // QMAPBOXGL_H
diff --git a/platform/qt/qt.cmake b/platform/qt/qt.cmake
index d1d597bda6..989618a59a 100644
--- a/platform/qt/qt.cmake
+++ b/platform/qt/qt.cmake
@@ -145,6 +145,7 @@ elseif (CMAKE_HOST_SYSTEM_NAME STREQUAL "Windows")
add_definitions("-Wno-unused-command-line-argument")
add_definitions("-Wno-unused-local-typedef")
add_definitions("-Wno-unused-private-field")
+ add_definitions("-Wno-inconsistent-missing-override")
list(APPEND MBGL_QT_CORE_FILES
PRIVATE platform/qt/src/thread.cpp
diff --git a/platform/qt/src/qmapbox.cpp b/platform/qt/src/qmapbox.cpp
index 87a9358772..2180f22d07 100644
--- a/platform/qt/src/qmapbox.cpp
+++ b/platform/qt/src/qmapbox.cpp
@@ -24,7 +24,7 @@ namespace QMapbox {
/*!
\namespace QMapbox
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
Contains miscellaneous Mapbox bindings used throughout QMapboxGL.
*/
@@ -74,7 +74,7 @@ namespace QMapbox {
/*!
\class QMapbox::Feature
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
Represents \l {https://www.mapbox.com/help/define-features/}{map features}
via its \a type (PointType, LineStringType or PolygonType), \a geometry, \a
@@ -94,7 +94,7 @@ namespace QMapbox {
/*!
\class QMapbox::ShapeAnnotationGeometry
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
Represents a shape annotation geometry.
*/
@@ -113,7 +113,7 @@ namespace QMapbox {
/*!
\class QMapbox::SymbolAnnotation
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
A symbol annotation comprises of its geometry and an icon identifier.
*/
@@ -121,7 +121,7 @@ namespace QMapbox {
/*!
\class QMapbox::LineAnnotation
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
Represents a line annotation object, along with its properties.
@@ -131,7 +131,7 @@ namespace QMapbox {
/*!
\class QMapbox::FillAnnotation
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
Represents a fill annotation object, along with its properties.
@@ -177,7 +177,7 @@ namespace QMapbox {
/*!
\class QMapbox::CustomLayerRenderParameters
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
QMapbox::CustomLayerRenderParameters provides the data passed on each render
pass for a custom layer.
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index 2e736c0aa2..8c3355dc09 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -89,15 +89,33 @@ QThreadStorage<std::shared_ptr<mbgl::util::RunLoop>> loop;
std::shared_ptr<mbgl::DefaultFileSource> sharedDefaultFileSource(
const std::string& cachePath, const std::string& assetRoot, uint64_t maximumCacheSize) {
- static std::weak_ptr<mbgl::DefaultFileSource> weak;
- auto fs = weak.lock();
+ static std::mutex mutex;
+ static std::unordered_map<std::string, std::weak_ptr<mbgl::DefaultFileSource>> fileSources;
- if (!fs) {
- weak = fs = std::make_shared<mbgl::DefaultFileSource>(
- cachePath, assetRoot, maximumCacheSize);
+ std::lock_guard<std::mutex> lock(mutex);
+
+ // Purge entries no longer in use.
+ for (auto it = fileSources.begin(); it != fileSources.end();) {
+ if (!it->second.lock()) {
+ it = fileSources.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ // Return an existing FileSource if available.
+ auto sharedFileSource = fileSources.find(cachePath);
+ if (sharedFileSource != fileSources.end()) {
+ return sharedFileSource->second.lock();
}
- return fs;
+ // New path, create a new FileSource.
+ auto newFileSource = std::make_shared<mbgl::DefaultFileSource>(
+ cachePath, assetRoot, maximumCacheSize);
+
+ fileSources[cachePath] = newFileSource;
+
+ return newFileSource;
}
// Conversion helper functions.
@@ -136,15 +154,14 @@ std::unique_ptr<mbgl::style::Image> toStyleImage(const QString &id, const QImage
\class QMapboxGLSettings
\brief The QMapboxGLSettings class stores the initial configuration for QMapboxGL.
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
QMapboxGLSettings is used to configure QMapboxGL at the moment of its creation.
Once created, the QMapboxGLSettings of a QMapboxGL can no longer be changed.
- Cache-related settings are shared between all QMapboxGL instances because different
- maps will share the same cache database file. The first map to configure cache properties
- such as size and path will force the configuration to all newly instantiated QMapboxGL
- objects.
+ Cache-related settings are shared between all QMapboxGL instances using the same cache path.
+ The first map to configure cache properties such as size will force the configuration
+ to all newly instantiated QMapboxGL objects using the same cache in the same process.
\since 4.7
*/
@@ -454,7 +471,7 @@ void QMapboxGLSettings::setResourceTransform(const std::function<std::string(con
\class QMapboxGL
\brief The QMapboxGL class is a Qt wrapper for the Mapbox GL Native engine.
- \inmodule Mapbox Qt SDK
+ \inmodule Mapbox Maps SDK for Qt
QMapboxGL is a Qt friendly version the Mapbox GL Native engine using Qt types
and deep integration with Qt event loop. QMapboxGL relies as much as possible
@@ -518,6 +535,19 @@ void QMapboxGLSettings::setResourceTransform(const std::function<std::string(con
*/
/*!
+ \enum QMapboxGL::MapLoadingFailure
+
+ This enum represents map loading failure type.
+
+ \value StyleParseFailure Failure to parse the style.
+ \value StyleLoadFailure Failure to load the style data.
+ \value NotFoundFailure Failure to obtain style resource file.
+ \value UnknownFailure Unknown map loading failure.
+
+ \sa mapLoadingFailed()
+*/
+
+/*!
\enum QMapboxGL::NorthOrientation
This enum sets the orientation of the north bearing. It will directly affect bearing when
@@ -1636,6 +1666,13 @@ void QMapboxGL::connectionEstablished()
*/
/*!
+ \fn void QMapboxGL::mapLoadingFailed(QMapboxGL::MapLoadingFailure type, const QString &description)
+
+ This signal is emitted when a map loading failure happens. Details of the
+ failures are provided, including its \a type and textual \a description.
+*/
+
+/*!
\fn void QMapboxGL::copyrightsChanged(const QString &copyrightsHtml);
This signal is emitted when the copyrights of the current content of the map
@@ -1672,6 +1709,7 @@ QMapboxGLPrivate::QMapboxGLPrivate(QMapboxGL *q, const QMapboxGLSettings &settin
qRegisterMetaType<QMapboxGL::MapChange>("QMapboxGL::MapChange");
connect(m_mapObserver.get(), SIGNAL(mapChanged(QMapboxGL::MapChange)), q, SIGNAL(mapChanged(QMapboxGL::MapChange)));
+ connect(m_mapObserver.get(), SIGNAL(mapLoadingFailed(QMapboxGL::MapLoadingFailure,QString)), q, SIGNAL(mapLoadingFailed(QMapboxGL::MapLoadingFailure,QString)));
connect(m_mapObserver.get(), SIGNAL(copyrightsChanged(QString)), q, SIGNAL(copyrightsChanged(QString)));
// Setup the Map object
diff --git a/platform/qt/src/qmapboxgl_map_observer.cpp b/platform/qt/src/qmapboxgl_map_observer.cpp
index e180ed8fda..44cb8c41d5 100644
--- a/platform/qt/src/qmapboxgl_map_observer.cpp
+++ b/platform/qt/src/qmapboxgl_map_observer.cpp
@@ -2,6 +2,10 @@
#include "qmapboxgl_p.hpp"
+#include <mbgl/util/exception.hpp>
+
+#include <exception>
+
QMapboxGLMapObserver::QMapboxGLMapObserver(QMapboxGLPrivate *d)
: d_ptr(d)
{
@@ -44,9 +48,30 @@ void QMapboxGLMapObserver::onDidFinishLoadingMap()
emit mapChanged(QMapboxGL::MapChangeDidFinishLoadingMap);
}
-void QMapboxGLMapObserver::onDidFailLoadingMap(std::exception_ptr)
+void QMapboxGLMapObserver::onDidFailLoadingMap(std::exception_ptr exception)
{
emit mapChanged(QMapboxGL::MapChangeDidFailLoadingMap);
+
+ QMapboxGL::MapLoadingFailure type;
+ QString description;
+
+ try {
+ std::rethrow_exception(exception);
+ } catch (const mbgl::util::StyleParseException& e) {
+ type = QMapboxGL::MapLoadingFailure::StyleParseFailure;
+ description = e.what();
+ } catch (const mbgl::util::StyleLoadException& e) {
+ type = QMapboxGL::MapLoadingFailure::StyleLoadFailure;
+ description = e.what();
+ } catch (const mbgl::util::NotFoundException& e) {
+ type = QMapboxGL::MapLoadingFailure::NotFoundFailure;
+ description = e.what();
+ } catch (const std::exception& e) {
+ type = QMapboxGL::MapLoadingFailure::UnknownFailure;
+ description = e.what();
+ }
+
+ emit mapLoadingFailed(type, description);
}
void QMapboxGLMapObserver::onWillStartRenderingFrame()
@@ -65,7 +90,7 @@ void QMapboxGLMapObserver::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMo
void QMapboxGLMapObserver::onWillStartRenderingMap()
{
- emit mapChanged(QMapboxGL::MapChangeWillStartLoadingMap);
+ emit mapChanged(QMapboxGL::MapChangeWillStartRenderingMap);
}
void QMapboxGLMapObserver::onDidFinishRenderingMap(mbgl::MapObserver::RenderMode mode)
diff --git a/platform/qt/src/qmapboxgl_map_observer.hpp b/platform/qt/src/qmapboxgl_map_observer.hpp
index c9d0581a90..98da5b6add 100644
--- a/platform/qt/src/qmapboxgl_map_observer.hpp
+++ b/platform/qt/src/qmapboxgl_map_observer.hpp
@@ -36,6 +36,7 @@ public:
signals:
void mapChanged(QMapboxGL::MapChange);
+ void mapLoadingFailed(QMapboxGL::MapLoadingFailure, const QString &reason);
void copyrightsChanged(const QString &copyrightsHtml);
private:
diff --git a/platform/qt/src/sqlite3.cpp b/platform/qt/src/sqlite3.cpp
index 80efd6a326..351991f881 100644
--- a/platform/qt/src/sqlite3.cpp
+++ b/platform/qt/src/sqlite3.cpp
@@ -24,11 +24,11 @@ namespace mapbox {
namespace sqlite {
// https://www.sqlite.org/rescode.html#ok
-static_assert(mbgl::underlying_type(Exception::OK) == 0, "error");
+static_assert(mbgl::underlying_type(ResultCode::OK) == 0, "error");
// https://www.sqlite.org/rescode.html#cantopen
-static_assert(mbgl::underlying_type(Exception::CANTOPEN) == 14, "error");
+static_assert(mbgl::underlying_type(ResultCode::CantOpen) == 14, "error");
// https://www.sqlite.org/rescode.html#notadb
-static_assert(mbgl::underlying_type(Exception::NOTADB) == 26, "error");
+static_assert(mbgl::underlying_type(ResultCode::NotADB) == 26, "error");
void checkQueryError(const QSqlQuery& query) {
QSqlError lastError = query.lastError();
@@ -52,15 +52,6 @@ void checkDatabaseError(const QSqlDatabase &db) {
}
}
-void checkDatabaseOpenError(const QSqlDatabase &db) {
- // Assume every error when opening the data as CANTOPEN. Qt
- // always returns -1 for `nativeErrorCode()` on database errors.
- QSqlError lastError = db.lastError();
- if (lastError.type() != QSqlError::NoError) {
- throw Exception { Exception::Code::CANTOPEN, "Error opening the database." };
- }
-}
-
namespace {
QString incrementCounter() {
static QAtomicInt count = 0;
@@ -70,32 +61,9 @@ namespace {
class DatabaseImpl {
public:
- DatabaseImpl(const char* filename, int flags)
- : connectionName(QString::number(uint64_t(QThread::currentThread())) + incrementCounter())
+ DatabaseImpl(QString connectionName_)
+ : connectionName(std::move(connectionName_))
{
- if (!QSqlDatabase::drivers().contains("QSQLITE")) {
- throw Exception { Exception::Code::CANTOPEN, "SQLite driver not found." };
- }
-
- assert(!QSqlDatabase::contains(connectionName));
- auto db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
-
- QString connectOptions = db.connectOptions();
- if (flags & OpenFlag::ReadOnly) {
- if (!connectOptions.isEmpty()) connectOptions.append(';');
- connectOptions.append("QSQLITE_OPEN_READONLY");
- }
- if (flags & OpenFlag::SharedCache) {
- if (!connectOptions.isEmpty()) connectOptions.append(';');
- connectOptions.append("QSQLITE_ENABLE_SHARED_CACHE");
- }
-
- db.setConnectOptions(connectOptions);
- db.setDatabaseName(QString(filename));
-
- if (!db.open()) {
- checkDatabaseOpenError(db);
- }
}
~DatabaseImpl() {
@@ -127,12 +95,51 @@ public:
template <typename T>
using optional = std::experimental::optional<T>;
+mapbox::util::variant<Database, Exception> Database::tryOpen(const std::string &filename, int flags) {
+ if (!QSqlDatabase::drivers().contains("QSQLITE")) {
+ return Exception { ResultCode::CantOpen, "SQLite driver not found." };
+ }
+
+ QString connectionName = QString::number(uint64_t(QThread::currentThread())) + incrementCounter();
-Database::Database(const std::string& file, int flags)
- : impl(std::make_unique<DatabaseImpl>(file.c_str(), flags)) {
- assert(impl);
+ assert(!QSqlDatabase::contains(connectionName));
+ auto db = QSqlDatabase::addDatabase("QSQLITE", connectionName);
+
+ QString connectOptions = db.connectOptions();
+ if (flags & OpenFlag::ReadOnly) {
+ if (!connectOptions.isEmpty()) connectOptions.append(';');
+ connectOptions.append("QSQLITE_OPEN_READONLY");
+ }
+ if (flags & OpenFlag::SharedCache) {
+ if (!connectOptions.isEmpty()) connectOptions.append(';');
+ connectOptions.append("QSQLITE_ENABLE_SHARED_CACHE");
+ }
+
+ db.setConnectOptions(connectOptions);
+ db.setDatabaseName(QString(filename.c_str()));
+
+ if (!db.open()) {
+ // Assume every error when opening the data as CANTOPEN. Qt
+ // always returns -1 for `nativeErrorCode()` on database errors.
+ return Exception { ResultCode::CantOpen, "Error opening the database." };
+ }
+
+ return Database(std::make_unique<DatabaseImpl>(connectionName));
}
+Database Database::open(const std::string &filename, int flags) {
+ auto result = tryOpen(filename, flags);
+ if (result.is<Exception>()) {
+ throw result.get<Exception>();
+ } else {
+ return std::move(result.get<Database>());
+ }
+}
+
+Database::Database(std::unique_ptr<DatabaseImpl> impl_)
+ : impl(std::move(impl_))
+{}
+
Database::Database(Database &&other)
: impl(std::move(other.impl)) {
assert(impl);
@@ -165,7 +172,9 @@ void Database::setBusyTimeout(std::chrono::milliseconds timeout) {
}
db.setConnectOptions(connectOptions);
if (!db.open()) {
- checkDatabaseOpenError(db);
+ // Assume every error when opening the data as CANTOPEN. Qt
+ // always returns -1 for `nativeErrorCode()` on database errors.
+ throw Exception { ResultCode::CantOpen, "Error opening the database." };
}
}
@@ -186,74 +195,82 @@ void Database::exec(const std::string &sql) {
}
}
-Statement Database::prepare(const char *query) {
- return Statement(this, query);
-}
-
-Statement::Statement(Database *db, const char *sql)
- : impl(std::make_unique<StatementImpl>(QString(sql), QSqlDatabase::database(db->impl->connectionName))) {
+Statement::Statement(Database& db, const char* sql)
+ : impl(std::make_unique<StatementImpl>(QString(sql),
+ QSqlDatabase::database(db.impl->connectionName))) {
assert(impl);
}
-Statement::Statement(Statement &&other)
- : impl(std::move(other.impl)) {
- assert(impl);
+Statement::~Statement() {
+#ifndef NDEBUG
+ // Crash if we're destructing this object while we know a Query object references this.
+ assert(!used);
+#endif
}
-Statement &Statement::operator=(Statement &&other) {
- assert(impl);
- std::swap(impl, other.impl);
- return *this;
+Query::Query(Statement& stmt_) : stmt(stmt_) {
+ assert(stmt.impl);
+
+#ifndef NDEBUG
+ assert(!stmt.used);
+ stmt.used = true;
+#endif
}
-Statement::~Statement() {
+Query::~Query() {
+ reset();
+ clearBindings();
+
+#ifndef NDEBUG
+ stmt.used = false;
+#endif
}
-template void Statement::bind(int, int64_t);
+template void Query::bind(int, int64_t);
template <typename T>
-void Statement::bind(int offset, T value) {
- assert(impl);
+void Query::bind(int offset, T value) {
+ assert(stmt.impl);
// Field numbering starts at 0.
- impl->query.bindValue(offset - 1, QVariant::fromValue<T>(value), QSql::In);
- checkQueryError(impl->query);
+ stmt.impl->query.bindValue(offset - 1, QVariant::fromValue<T>(value), QSql::In);
+ checkQueryError(stmt.impl->query);
}
template <>
-void Statement::bind(int offset, std::nullptr_t) {
- assert(impl);
+void Query::bind(int offset, std::nullptr_t) {
+ assert(stmt.impl);
// Field numbering starts at 0.
- impl->query.bindValue(offset - 1, QVariant(QVariant::Invalid), QSql::In);
- checkQueryError(impl->query);
+ stmt.impl->query.bindValue(offset - 1, QVariant(QVariant::Invalid), QSql::In);
+ checkQueryError(stmt.impl->query);
}
template <>
-void Statement::bind(int offset, int32_t value) {
+void Query::bind(int offset, int32_t value) {
bind(offset, static_cast<int64_t>(value));
}
template <>
-void Statement::bind(int offset, bool value) {
+void Query::bind(int offset, bool value) {
bind(offset, static_cast<int>(value));
}
template <>
-void Statement::bind(int offset, int8_t value) {
+void Query::bind(int offset, int8_t value) {
bind(offset, static_cast<int64_t>(value));
}
template <>
-void Statement::bind(int offset, uint8_t value) {
+void Query::bind(int offset, uint8_t value) {
bind(offset, static_cast<int64_t>(value));
}
template <>
-void Statement::bind(int offset, mbgl::Timestamp value) {
+void Query::bind(int offset, mbgl::Timestamp value) {
bind(offset, std::chrono::system_clock::to_time_t(value));
}
template <>
-void Statement::bind(int offset, optional<std::string> value) {
+void Query::bind(int offset, optional<std::string> value) {
if (value) {
bind(offset, *value);
} else {
@@ -262,7 +279,7 @@ void Statement::bind(int offset, optional<std::string> value) {
}
template <>
-void Statement::bind(int offset, optional<mbgl::Timestamp> value) {
+void Query::bind(int offset, optional<mbgl::Timestamp> value) {
if (value) {
bind(offset, *value);
} else {
@@ -270,30 +287,25 @@ void Statement::bind(int offset, optional<mbgl::Timestamp> value) {
}
}
-void Statement::bind(int offset, const char* value, std::size_t length, bool retain) {
- assert(impl);
+void Query::bind(int offset, const char* value, std::size_t length, bool /* retain */) {
+ assert(stmt.impl);
if (length > std::numeric_limits<int>::max()) {
// Kept for consistence with the default implementation.
throw std::range_error("value too long");
}
- // Qt SQLite driver treats QByteArray as blob: we need to explicitly
- // declare the variant type as string.
- QVariant text(QVariant::Type::String);
- text.setValue(retain ? QByteArray(value, length) : QByteArray::fromRawData(value, length));
-
// Field numbering starts at 0.
- impl->query.bindValue(offset - 1, std::move(text), QSql::In);
+ stmt.impl->query.bindValue(offset - 1, QString(QByteArray(value, length)), QSql::In);
- checkQueryError(impl->query);
+ checkQueryError(stmt.impl->query);
}
-void Statement::bind(int offset, const std::string& value, bool retain) {
+void Query::bind(int offset, const std::string& value, bool retain) {
bind(offset, value.data(), value.size(), retain);
}
-void Statement::bindBlob(int offset, const void* value_, std::size_t length, bool retain) {
- assert(impl);
+void Query::bindBlob(int offset, const void* value_, std::size_t length, bool retain) {
+ assert(stmt.impl);
const char* value = reinterpret_cast<const char*>(value_);
if (length > std::numeric_limits<int>::max()) {
// Kept for consistence with the default implementation.
@@ -301,123 +313,123 @@ void Statement::bindBlob(int offset, const void* value_, std::size_t length, boo
}
// Field numbering starts at 0.
- impl->query.bindValue(offset - 1, retain ? QByteArray(value, length) :
+ stmt.impl->query.bindValue(offset - 1, retain ? QByteArray(value, length) :
QByteArray::fromRawData(value, length), QSql::In | QSql::Binary);
- checkQueryError(impl->query);
+ checkQueryError(stmt.impl->query);
}
-void Statement::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
+void Query::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
bindBlob(offset, value.data(), value.size(), retain);
}
-bool Statement::run() {
- assert(impl);
+bool Query::run() {
+ assert(stmt.impl);
- if (!impl->query.isValid()) {
- if (impl->query.exec()) {
- impl->lastInsertRowId = impl->query.lastInsertId().value<int64_t>();
- impl->changes = impl->query.numRowsAffected();
+ if (!stmt.impl->query.isValid()) {
+ if (stmt.impl->query.exec()) {
+ stmt.impl->lastInsertRowId = stmt.impl->query.lastInsertId().value<int64_t>();
+ stmt.impl->changes = stmt.impl->query.numRowsAffected();
} else {
- checkQueryError(impl->query);
+ checkQueryError(stmt.impl->query);
}
}
- const bool hasNext = impl->query.next();
- if (!hasNext) impl->query.finish();
+ const bool hasNext = stmt.impl->query.next();
+ if (!hasNext) stmt.impl->query.finish();
return hasNext;
}
-template bool Statement::get(int);
-template int Statement::get(int);
-template int64_t Statement::get(int);
-template double Statement::get(int);
+template bool Query::get(int);
+template int Query::get(int);
+template int64_t Query::get(int);
+template double Query::get(int);
-template <typename T> T Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QVariant value = impl->query.value(offset);
- checkQueryError(impl->query);
+template <typename T> T Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QVariant value = stmt.impl->query.value(offset);
+ checkQueryError(stmt.impl->query);
return value.value<T>();
}
-template <> std::vector<uint8_t> Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QByteArray byteArray = impl->query.value(offset).toByteArray();
- checkQueryError(impl->query);
+template <> std::vector<uint8_t> Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QByteArray byteArray = stmt.impl->query.value(offset).toByteArray();
+ checkQueryError(stmt.impl->query);
std::vector<uint8_t> blob(byteArray.begin(), byteArray.end());
return blob;
}
-template <> mbgl::Timestamp Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QVariant value = impl->query.value(offset);
- checkQueryError(impl->query);
+template <> mbgl::Timestamp Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QVariant value = stmt.impl->query.value(offset);
+ checkQueryError(stmt.impl->query);
return std::chrono::time_point_cast<std::chrono::seconds>(
std::chrono::system_clock::from_time_t(value.value<::time_t>()));
}
-template <> optional<int64_t> Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QVariant value = impl->query.value(offset);
- checkQueryError(impl->query);
+template <> optional<int64_t> Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QVariant value = stmt.impl->query.value(offset);
+ checkQueryError(stmt.impl->query);
if (value.isNull())
return {};
return { value.value<int64_t>() };
}
-template <> optional<double> Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QVariant value = impl->query.value(offset);
- checkQueryError(impl->query);
+template <> optional<double> Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QVariant value = stmt.impl->query.value(offset);
+ checkQueryError(stmt.impl->query);
if (value.isNull())
return {};
return { value.value<double>() };
}
-template <> std::string Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QByteArray value = impl->query.value(offset).toByteArray();
- checkQueryError(impl->query);
+template <> std::string Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QByteArray value = stmt.impl->query.value(offset).toByteArray();
+ checkQueryError(stmt.impl->query);
return std::string(value.constData(), value.size());
}
-template <> optional<std::string> Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QByteArray value = impl->query.value(offset).toByteArray();
- checkQueryError(impl->query);
+template <> optional<std::string> Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QByteArray value = stmt.impl->query.value(offset).toByteArray();
+ checkQueryError(stmt.impl->query);
if (value.isNull())
return {};
return { std::string(value.constData(), value.size()) };
}
-template <> optional<mbgl::Timestamp> Statement::get(int offset) {
- assert(impl && impl->query.isValid());
- QVariant value = impl->query.value(offset);
- checkQueryError(impl->query);
+template <> optional<mbgl::Timestamp> Query::get(int offset) {
+ assert(stmt.impl && stmt.impl->query.isValid());
+ QVariant value = stmt.impl->query.value(offset);
+ checkQueryError(stmt.impl->query);
if (value.isNull())
return {};
return { std::chrono::time_point_cast<mbgl::Seconds>(
std::chrono::system_clock::from_time_t(value.value<::time_t>())) };
}
-void Statement::reset() {
- assert(impl);
- impl->query.finish();
+void Query::reset() {
+ assert(stmt.impl);
+ stmt.impl->query.finish();
}
-void Statement::clearBindings() {
+void Query::clearBindings() {
// no-op
}
-int64_t Statement::lastInsertRowId() const {
- assert(impl);
- return impl->lastInsertRowId;
+int64_t Query::lastInsertRowId() const {
+ assert(stmt.impl);
+ return stmt.impl->lastInsertRowId;
}
-uint64_t Statement::changes() const {
- assert(impl);
- return (impl->changes < 0 ? 0 : impl->changes);
+uint64_t Query::changes() const {
+ assert(stmt.impl);
+ return (stmt.impl->changes < 0 ? 0 : stmt.impl->changes);
}
Transaction::Transaction(Database& db_, Mode mode)
diff --git a/scripts/generate-shaders.js b/scripts/generate-shaders.js
index b1eeffb8a0..6758793056 100755
--- a/scripts/generate-shaders.js
+++ b/scripts/generate-shaders.js
@@ -7,6 +7,8 @@ const outputPath = 'src/mbgl/shaders';
var shaders = require('../mapbox-gl-js/src/shaders');
+delete shaders.lineGradient;
+
require('./style-code');
writeIfModified(path.join(outputPath, 'preludes.hpp'), `// NOTE: DO NOT CHANGE THIS FILE. IT IS AUTOMATICALLY GENERATED.
diff --git a/scripts/generate-style-code.js b/scripts/generate-style-code.js
index 6ddb787f19..0059863e05 100755
--- a/scripts/generate-style-code.js
+++ b/scripts/generate-style-code.js
@@ -15,10 +15,6 @@ function parseCSSColor(str) {
];
}
-global.isDataDriven = function (property) {
- return property['property-function'] === true;
-};
-
global.isLightProperty = function (property) {
return property['light-property'] === true;
};
@@ -77,30 +73,36 @@ function attributeUniformType(property, type) {
}
global.layoutPropertyType = function (property) {
- if (isDataDriven(property)) {
- return `DataDrivenLayoutProperty<${evaluatedType(property)}>`;
- } else {
- return `LayoutProperty<${evaluatedType(property)}>`;
+ switch (property['property-type']) {
+ case 'data-driven':
+ case 'cross-faded-data-driven':
+ return `DataDrivenLayoutProperty<${evaluatedType(property)}>`;
+ default:
+ return `LayoutProperty<${evaluatedType(property)}>`;
}
};
global.paintPropertyType = function (property, type) {
- if (isDataDriven(property)) {
- return `DataDrivenPaintProperty<${evaluatedType(property)}, ${attributeUniformType(property, type)}>`;
- } else if (/-pattern$/.test(property.name) || property.name === 'line-dasharray') {
- return `CrossFadedPaintProperty<${evaluatedType(property)}>`;
- } else {
- return `PaintProperty<${evaluatedType(property)}>`;
+ switch (property['property-type']) {
+ case 'data-driven':
+ case 'cross-faded-data-driven':
+ return `DataDrivenPaintProperty<${evaluatedType(property)}, ${attributeUniformType(property, type)}>`;
+ case 'cross-faded':
+ return `CrossFadedPaintProperty<${evaluatedType(property)}>`;
+ default:
+ return `PaintProperty<${evaluatedType(property)}>`;
}
};
global.propertyValueType = function (property) {
- if (isDataDriven(property)) {
- return `DataDrivenPropertyValue<${evaluatedType(property)}>`;
- } else if (property.name === 'heatmap-color') {
- return `HeatmapColorPropertyValue`;
- } else {
- return `PropertyValue<${evaluatedType(property)}>`;
+ switch (property['property-type']) {
+ case 'data-driven':
+ case 'cross-faded-data-driven':
+ return `DataDrivenPropertyValue<${evaluatedType(property)}>`;
+ case 'color-ramp':
+ return `HeatmapColorPropertyValue`;
+ default:
+ return `PropertyValue<${evaluatedType(property)}>`;
}
};
diff --git a/scripts/style-spec.js b/scripts/style-spec.js
index 196adc0b32..dd9a127b70 100644
--- a/scripts/style-spec.js
+++ b/scripts/style-spec.js
@@ -1,3 +1,4 @@
var spec = module.exports = require('../mapbox-gl-js/src/style-spec/reference/v8');
// Make temporary modifications here when Native doesn't have all features that JS has.
+delete spec.paint_line['line-gradient'];
diff --git a/src/mbgl/annotation/render_annotation_source.cpp b/src/mbgl/annotation/render_annotation_source.cpp
index a237100d13..7d776f21c4 100644
--- a/src/mbgl/annotation/render_annotation_source.cpp
+++ b/src/mbgl/annotation/render_annotation_source.cpp
@@ -65,8 +65,8 @@ RenderAnnotationSource::queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, collisionIndex);
+ const mat4& projMatrix) const {
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, projMatrix);
}
std::vector<Feature> RenderAnnotationSource::querySourceFeatures(const SourceQueryOptions&) const {
diff --git a/src/mbgl/annotation/render_annotation_source.hpp b/src/mbgl/annotation/render_annotation_source.hpp
index e812ec2883..da87d13814 100644
--- a/src/mbgl/annotation/render_annotation_source.hpp
+++ b/src/mbgl/annotation/render_annotation_source.hpp
@@ -28,7 +28,7 @@ public:
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const final;
+ const mat4& projMatrix) const final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
diff --git a/src/mbgl/geometry/feature_index.cpp b/src/mbgl/geometry/feature_index.cpp
index 57719de038..cc69a60ca0 100644
--- a/src/mbgl/geometry/feature_index.cpp
+++ b/src/mbgl/geometry/feature_index.cpp
@@ -24,34 +24,30 @@ FeatureIndex::FeatureIndex(std::unique_ptr<const GeometryTileData> tileData_)
void FeatureIndex::insert(const GeometryCollection& geometries,
std::size_t index,
const std::string& sourceLayerName,
- const std::string& bucketName) {
+ const std::string& bucketLeaderID) {
for (const auto& ring : geometries) {
auto envelope = mapbox::geometry::envelope(ring);
- grid.insert(IndexedSubfeature(index, sourceLayerName, bucketName, sortIndex++),
- {convertPoint<float>(envelope.min), convertPoint<float>(envelope.max)});
+ if (envelope.min.x < util::EXTENT &&
+ envelope.min.y < util::EXTENT &&
+ envelope.max.x >= 0 &&
+ envelope.max.y >= 0) {
+ grid.insert(IndexedSubfeature(index, sourceLayerName, bucketLeaderID, sortIndex++),
+ {convertPoint<float>(envelope.min), convertPoint<float>(envelope.max)});
+ }
}
}
-static bool topDown(const IndexedSubfeature& a, const IndexedSubfeature& b) {
- return a.sortIndex > b.sortIndex;
-}
-
-static bool topDownSymbols(const IndexedSubfeature& a, const IndexedSubfeature& b) {
- return a.sortIndex < b.sortIndex;
-}
-
void FeatureIndex::query(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
- const float bearing,
+ const TransformState& transformState,
+ const mat4& posMatrix,
const double tileSize,
const double scale,
const RenderedQueryOptions& queryOptions,
const UnwrappedTileID& tileID,
- const std::string& sourceID,
const std::vector<const RenderLayer*>& layers,
- const CollisionIndex& collisionIndex,
- const float additionalQueryRadius) const {
+ const float additionalQueryPadding) const {
if (!tileData) {
return;
@@ -59,15 +55,17 @@ void FeatureIndex::query(
// Determine query radius
const float pixelsToTileUnits = util::EXTENT / tileSize / scale;
- const int16_t additionalRadius = std::min<int16_t>(util::EXTENT, additionalQueryRadius * pixelsToTileUnits);
+ const int16_t additionalPadding = std::min<int16_t>(util::EXTENT, additionalQueryPadding * pixelsToTileUnits);
// Query the grid index
mapbox::geometry::box<int16_t> box = mapbox::geometry::envelope(queryGeometry);
- std::vector<IndexedSubfeature> features = grid.query({ convertPoint<float>(box.min - additionalRadius),
- convertPoint<float>(box.max + additionalRadius) });
+ std::vector<IndexedSubfeature> features = grid.query({ convertPoint<float>(box.min - additionalPadding),
+ convertPoint<float>(box.max + additionalPadding) });
- std::sort(features.begin(), features.end(), topDown);
+ std::sort(features.begin(), features.end(), [](const IndexedSubfeature& a, const IndexedSubfeature& b) {
+ return a.sortIndex > b.sortIndex;
+ });
size_t previousSortIndex = std::numeric_limits<size_t>::max();
for (const auto& indexedFeature : features) {
@@ -75,25 +73,59 @@ void FeatureIndex::query(
if (indexedFeature.sortIndex == previousSortIndex) continue;
previousSortIndex = indexedFeature.sortIndex;
- addFeature(result, indexedFeature, queryGeometry, queryOptions, tileID.canonical, layers, bearing, pixelsToTileUnits);
+ addFeature(result, indexedFeature, queryOptions, tileID.canonical, layers, queryGeometry, transformState, pixelsToTileUnits, posMatrix);
}
+}
+
+std::unordered_map<std::string, std::vector<Feature>> FeatureIndex::lookupSymbolFeatures(const std::vector<IndexedSubfeature>& symbolFeatures,
+ const RenderedQueryOptions& queryOptions,
+ const std::vector<const RenderLayer*>& layers,
+ const OverscaledTileID& tileID,
+ const std::shared_ptr<std::vector<size_t>>& featureSortOrder) const {
+ std::unordered_map<std::string, std::vector<Feature>> result;
+ if (!tileData) {
+ return result;
+ }
+ std::vector<IndexedSubfeature> sortedFeatures(symbolFeatures.begin(), symbolFeatures.end());
+
+ std::sort(sortedFeatures.begin(), sortedFeatures.end(), [featureSortOrder](const IndexedSubfeature& a, const IndexedSubfeature& b) {
+ // Same idea as the non-symbol sort order, but symbol features may have changed their sort order
+ // since their corresponding IndexedSubfeature was added to the CollisionIndex
+ // The 'featureSortOrder' is relatively inefficient for querying but cheap to build on every bucket sort
+ if (featureSortOrder) {
+ // queryRenderedSymbols documentation says we'll return features in
+ // "top-to-bottom" rendering order (aka last-to-first).
+ // Actually there can be multiple symbol instances per feature, so
+ // we sort each feature based on the first matching symbol instance.
+ auto sortedA = std::find(featureSortOrder->begin(), featureSortOrder->end(), a.index);
+ auto sortedB = std::find(featureSortOrder->begin(), featureSortOrder->end(), b.index);
+ assert(sortedA != featureSortOrder->end());
+ assert(sortedB != featureSortOrder->end());
+ return sortedA > sortedB;
+ } else {
+ // Bucket hasn't been re-sorted based on angle, so use same "reverse of appearance in source data"
+ // logic as non-symboles
+ return a.sortIndex > b.sortIndex;
+ }
+ });
- std::vector<IndexedSubfeature> symbolFeatures = collisionIndex.queryRenderedSymbols(queryGeometry, tileID, sourceID);
- std::sort(symbolFeatures.begin(), symbolFeatures.end(), topDownSymbols);
- for (const auto& symbolFeature : symbolFeatures) {
- addFeature(result, symbolFeature, queryGeometry, queryOptions, tileID.canonical, layers, bearing, pixelsToTileUnits);
+ for (const auto& symbolFeature : sortedFeatures) {
+ mat4 unusedMatrix;
+ addFeature(result, symbolFeature, queryOptions, tileID.canonical, layers, GeometryCoordinates(), {}, 0, unusedMatrix);
}
+ return result;
}
void FeatureIndex::addFeature(
std::unordered_map<std::string, std::vector<Feature>>& result,
const IndexedSubfeature& indexedFeature,
- const GeometryCoordinates& queryGeometry,
const RenderedQueryOptions& options,
const CanonicalTileID& tileID,
const std::vector<const RenderLayer*>& layers,
- const float bearing,
- const float pixelsToTileUnits) const {
+ const GeometryCoordinates& queryGeometry,
+ const TransformState& transformState,
+ const float pixelsToTileUnits,
+ const mat4& posMatrix) const {
auto getRenderLayer = [&] (const std::string& layerID) -> const RenderLayer* {
for (const auto& layer : layers) {
@@ -108,7 +140,7 @@ void FeatureIndex::addFeature(
std::unique_ptr<GeometryTileLayer> sourceLayer;
std::unique_ptr<GeometryTileFeature> geometryTileFeature;
- for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.bucketName)) {
+ for (const std::string& layerID : bucketLayerIDs.at(indexedFeature.bucketLeaderID)) {
const RenderLayer* renderLayer = getRenderLayer(layerID);
if (!renderLayer) {
continue;
@@ -123,7 +155,7 @@ void FeatureIndex::addFeature(
}
if (!renderLayer->is<RenderSymbolLayer>() &&
- !renderLayer->queryIntersectsFeature(queryGeometry, *geometryTileFeature, tileID.z, bearing, pixelsToTileUnits)) {
+ !renderLayer->queryIntersectsFeature(queryGeometry, *geometryTileFeature, tileID.z, transformState, pixelsToTileUnits, posMatrix)) {
continue;
}
@@ -157,8 +189,8 @@ optional<GeometryCoordinates> FeatureIndex::translateQueryGeometry(
return translated;
}
-void FeatureIndex::setBucketLayerIDs(const std::string& bucketName, const std::vector<std::string>& layerIDs) {
- bucketLayerIDs[bucketName] = layerIDs;
+void FeatureIndex::setBucketLayerIDs(const std::string& bucketLeaderID, const std::vector<std::string>& layerIDs) {
+ bucketLayerIDs[bucketLeaderID] = layerIDs;
}
} // namespace mbgl
diff --git a/src/mbgl/geometry/feature_index.hpp b/src/mbgl/geometry/feature_index.hpp
index 9e0c172342..739c1f282f 100644
--- a/src/mbgl/geometry/feature_index.hpp
+++ b/src/mbgl/geometry/feature_index.hpp
@@ -5,6 +5,7 @@
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/util/grid_index.hpp>
#include <mbgl/util/feature.hpp>
+#include <mbgl/util/mat4.hpp>
#include <vector>
#include <string>
@@ -14,6 +15,7 @@ namespace mbgl {
class RenderedQueryOptions;
class RenderLayer;
+class TransformState;
class CollisionIndex;
@@ -23,29 +25,26 @@ public:
IndexedSubfeature(std::size_t index_, std::string sourceLayerName_, std::string bucketName_, size_t sortIndex_)
: index(index_)
, sourceLayerName(std::move(sourceLayerName_))
- , bucketName(std::move(bucketName_))
+ , bucketLeaderID(std::move(bucketName_))
, sortIndex(sortIndex_)
- , tileID(0, 0, 0)
+ , bucketInstanceId(0)
{}
- IndexedSubfeature(std::size_t index_, std::string sourceLayerName_, std::string bucketName_, size_t sortIndex_,
- std::string sourceID_, CanonicalTileID tileID_)
- : index(index_)
- , sourceLayerName(std::move(sourceLayerName_))
- , bucketName(std::move(bucketName_))
- , sortIndex(std::move(sortIndex_))
- , sourceID(std::move(sourceID_))
- , tileID(std::move(tileID_))
- {}
+ IndexedSubfeature(const IndexedSubfeature& other, uint32_t bucketInstanceId_)
+ : index(other.index)
+ , sourceLayerName(other.sourceLayerName)
+ , bucketLeaderID(other.bucketLeaderID)
+ , sortIndex(other.sortIndex)
+ , bucketInstanceId(bucketInstanceId_)
+ {}
size_t index;
std::string sourceLayerName;
- std::string bucketName;
+ std::string bucketLeaderID;
size_t sortIndex;
// Only used for symbol features
- std::string sourceID;
- CanonicalTileID tileID;
+ uint32_t bucketInstanceId;
};
class FeatureIndex {
@@ -54,20 +53,19 @@ public:
const GeometryTileData* getData() { return tileData.get(); }
- void insert(const GeometryCollection&, std::size_t index, const std::string& sourceLayerName, const std::string& bucketName);
+ void insert(const GeometryCollection&, std::size_t index, const std::string& sourceLayerName, const std::string& bucketLeaderID);
void query(
std::unordered_map<std::string, std::vector<Feature>>& result,
const GeometryCoordinates& queryGeometry,
- const float bearing,
+ const TransformState&,
+ const mat4& posMatrix,
const double tileSize,
const double scale,
const RenderedQueryOptions& options,
const UnwrappedTileID&,
- const std::string&,
const std::vector<const RenderLayer*>&,
- const CollisionIndex&,
- const float additionalQueryRadius) const;
+ const float additionalQueryPadding) const;
static optional<GeometryCoordinates> translateQueryGeometry(
const GeometryCoordinates& queryGeometry,
@@ -76,18 +74,26 @@ public:
const float bearing,
const float pixelsToTileUnits);
- void setBucketLayerIDs(const std::string& bucketName, const std::vector<std::string>& layerIDs);
+ void setBucketLayerIDs(const std::string& bucketLeaderID, const std::vector<std::string>& layerIDs);
+
+ std::unordered_map<std::string, std::vector<Feature>> lookupSymbolFeatures(
+ const std::vector<IndexedSubfeature>& symbolFeatures,
+ const RenderedQueryOptions& options,
+ const std::vector<const RenderLayer*>& layers,
+ const OverscaledTileID& tileID,
+ const std::shared_ptr<std::vector<size_t>>& featureSortOrder) const;
private:
void addFeature(
std::unordered_map<std::string, std::vector<Feature>>& result,
const IndexedSubfeature&,
- const GeometryCoordinates& queryGeometry,
const RenderedQueryOptions& options,
const CanonicalTileID&,
const std::vector<const RenderLayer*>&,
- const float bearing,
- const float pixelsToTileUnits) const;
+ const GeometryCoordinates& queryGeometry,
+ const TransformState& transformState,
+ const float pixelsToTileUnits,
+ const mat4& posMatrix) const;
GridIndex<IndexedSubfeature> grid;
unsigned int sortIndex = 0;
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index cd9bcbd585..4249ffc24e 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -41,7 +41,7 @@ SymbolLayout::SymbolLayout(const BucketParameters& parameters,
std::unique_ptr<GeometryTileLayer> sourceLayer_,
ImageDependencies& imageDependencies,
GlyphDependencies& glyphDependencies)
- : bucketName(layers.at(0)->getID()),
+ : bucketLeaderID(layers.at(0)->getID()),
sourceLayer(std::move(sourceLayer_)),
overscaling(parameters.tileID.overscaleFactor()),
zoom(parameters.tileID.overscaledZ),
@@ -180,8 +180,7 @@ bool SymbolLayout::hasSymbolInstances() const {
}
void SymbolLayout::prepare(const GlyphMap& glyphMap, const GlyphPositions& glyphPositions,
- const ImageMap& imageMap, const ImagePositions& imagePositions,
- const OverscaledTileID& tileID, const std::string& sourceID) {
+ const ImageMap& imageMap, const ImagePositions& imagePositions) {
const bool textAlongLine = layout.get<TextRotationAlignment>() == AlignmentType::Map &&
layout.get<SymbolPlacement>() == SymbolPlacementType::Line;
@@ -252,7 +251,7 @@ void SymbolLayout::prepare(const GlyphMap& glyphMap, const GlyphPositions& glyph
// if either shapedText or icon position is present, add the feature
if (shapedTextOrientations.first || shapedIcon) {
- addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositionMap, tileID, sourceID);
+ addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, shapedIcon, glyphPositionMap);
}
feature.geometry.clear();
@@ -265,9 +264,7 @@ void SymbolLayout::addFeature(const std::size_t index,
const SymbolFeature& feature,
const std::pair<Shaping, Shaping>& shapedTextOrientations,
optional<PositionedIcon> shapedIcon,
- const GlyphPositionMap& glyphPositionMap,
- const OverscaledTileID& tileID,
- const std::string& sourceID) {
+ const GlyphPositionMap& glyphPositionMap) {
const float minScale = 0.5f;
const float glyphSize = 24.0f;
@@ -296,8 +293,7 @@ void SymbolLayout::addFeature(const std::size_t index,
: layout.get<SymbolPlacement>();
const float textRepeatDistance = symbolSpacing / 2;
- IndexedSubfeature indexedFeature(feature.index, sourceLayer->getName(), bucketName, symbolInstances.size(),
- sourceID, tileID.canonical);
+ 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
@@ -423,7 +419,7 @@ std::unique_ptr<SymbolBucket> SymbolLayout::place(const bool showCollisionBoxes)
const bool mayOverlap = layout.get<TextAllowOverlap>() || layout.get<IconAllowOverlap>() ||
layout.get<TextIgnorePlacement>() || layout.get<IconIgnorePlacement>();
- auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear, mayOverlap, std::move(symbolInstances));
+ auto bucket = std::make_unique<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear, mayOverlap, bucketLeaderID, std::move(symbolInstances));
for (SymbolInstance &symbolInstance : bucket->symbolInstances) {
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index 6951c29ada..43b577859f 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -34,8 +34,7 @@ public:
GlyphDependencies&);
void prepare(const GlyphMap&, const GlyphPositions&,
- const ImageMap&, const ImagePositions&,
- const OverscaledTileID&, const std::string&);
+ const ImageMap&, const ImagePositions&);
std::unique_ptr<SymbolBucket> place(const bool showCollisionBoxes);
@@ -44,7 +43,7 @@ public:
std::map<std::string,
std::pair<style::IconPaintProperties::PossiblyEvaluated, style::TextPaintProperties::PossiblyEvaluated>> layerPaintProperties;
- const std::string bucketName;
+ const std::string bucketLeaderID;
std::vector<SymbolInstance> symbolInstances;
private:
@@ -52,9 +51,7 @@ private:
const SymbolFeature&,
const std::pair<Shaping, Shaping>& shapedTextOrientations,
optional<PositionedIcon> shapedIcon,
- const GlyphPositionMap&,
- const OverscaledTileID&,
- const std::string&);
+ const GlyphPositionMap&);
bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor&);
std::map<std::u16string, std::vector<Anchor>> compareText;
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index a7beb0f1e2..d81544eed5 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -747,6 +747,11 @@ void Map::Impl::onInvalidate() {
}
void Map::Impl::onUpdate() {
+ // Don't load/render anything in still mode until explicitly requested.
+ if (mode != MapMode::Continuous && !stillImageRequest) {
+ return;
+ }
+
TimePoint timePoint = mode == MapMode::Continuous ? Clock::now() : Clock::time_point::max();
transform.updateTransitions(timePoint);
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index 18d2c24aee..a85b251fb4 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -421,4 +421,17 @@ float TransformState::getCameraToTileDistance(const UnwrappedTileID& tileID) con
return projectedCenter[3];
}
+float TransformState::maxPitchScaleFactor() const {
+ if (size.isEmpty()) {
+ return {};
+ }
+ auto latLng = screenCoordinateToLatLng({ 0, static_cast<float>(getSize().height) });
+ mat4 mat = coordinatePointMatrix(getZoom());
+ Point<double> pt = Projection::project(latLng, scale) / double(util::tileSize);
+ vec4 p = {{ pt.x, pt.y, 0, 1 }};
+ vec4 topPoint;
+ matrix::transformMat4(topPoint, p, mat);
+ return topPoint[3] / getCameraToCenterDistance();
+}
+
} // namespace mbgl
diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp
index 451802034d..b6f8ae4424 100644
--- a/src/mbgl/map/transform_state.hpp
+++ b/src/mbgl/map/transform_state.hpp
@@ -87,6 +87,7 @@ public:
}
float getCameraToTileDistance(const UnwrappedTileID&) const;
+ float maxPitchScaleFactor() const;
private:
bool rotatedNorth() const;
diff --git a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
index 5e2c937091..4fcc761280 100644
--- a/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
+++ b/src/mbgl/renderer/buckets/fill_extrusion_bucket.cpp
@@ -84,7 +84,7 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
if (nVertices == 0)
continue;
- auto edgeDistance = 0;
+ std::size_t edgeDistance = 0;
for (uint32_t i = 0; i < nVertices; i++) {
const auto& p1 = ring[i];
@@ -102,7 +102,7 @@ void FillExtrusionBucket::addFeature(const GeometryTileFeature& feature,
const Point<double> perp = util::unit(util::perp(d1 - d2));
const auto dist = util::dist<int16_t>(d1, d2);
- if (dist > std::numeric_limits<int16_t>::max()) {
+ if (edgeDistance + dist > std::numeric_limits<int16_t>::max()) {
edgeDistance = 0;
}
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index 60e8a0b504..4fe03eb453 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -18,11 +18,13 @@ SymbolBucket::SymbolBucket(style::SymbolLayoutProperties::PossiblyEvaluated layo
bool sdfIcons_,
bool iconsNeedLinear_,
bool sortFeaturesByY_,
+ const std::string bucketName_,
const std::vector<SymbolInstance>&& symbolInstances_)
: layout(std::move(layout_)),
sdfIcons(sdfIcons_),
iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()),
sortFeaturesByY(sortFeaturesByY_),
+ bucketLeaderID(std::move(bucketName_)),
symbolInstances(std::move(symbolInstances_)),
textSizeBinder(SymbolSizeBinder::create(zoom, textSize, TextSize::defaultValue())),
iconSizeBinder(SymbolSizeBinder::create(zoom, iconSize, IconSize::defaultValue())) {
@@ -200,8 +202,12 @@ void SymbolBucket::sortFeatures(const float angle) {
text.triangles.clear();
icon.triangles.clear();
+ featureSortOrder = std::make_unique<std::vector<size_t>>();
+ featureSortOrder->reserve(symbolInstanceIndexes.size());
+
for (auto i : symbolInstanceIndexes) {
const SymbolInstance& symbolInstance = symbolInstances[i];
+ featureSortOrder->push_back(symbolInstance.featureIndex);
if (symbolInstance.placedTextIndex) {
addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedTextIndex]);
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index ed8afb052c..e4aaf5ba30 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -47,6 +47,7 @@ public:
bool sdfIcons,
bool iconsNeedLinear,
bool sortFeaturesByY,
+ const std::string bucketLeaderID,
const std::vector<SymbolInstance>&&);
void upload(gl::Context&) override;
@@ -64,6 +65,8 @@ public:
const bool iconsNeedLinear;
const bool sortFeaturesByY;
+ const std::string bucketLeaderID;
+
optional<float> sortedAngle;
bool staticUploaded = false;
@@ -131,6 +134,8 @@ public:
uint32_t bucketInstanceId = 0;
bool justReloaded = false;
+
+ std::shared_ptr<std::vector<size_t>> featureSortOrder;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/layers/render_background_layer.cpp b/src/mbgl/renderer/layers/render_background_layer.cpp
index f22402ac98..2dc5fe7339 100644
--- a/src/mbgl/renderer/layers/render_background_layer.cpp
+++ b/src/mbgl/renderer/layers/render_background_layer.cpp
@@ -7,6 +7,7 @@
#include <mbgl/programs/programs.hpp>
#include <mbgl/programs/background_program.hpp>
#include <mbgl/util/tile_cover.hpp>
+#include <mbgl/map/transform_state.hpp>
namespace mbgl {
diff --git a/src/mbgl/renderer/layers/render_circle_layer.cpp b/src/mbgl/renderer/layers/render_circle_layer.cpp
index 4c96137143..b433a9d3fa 100644
--- a/src/mbgl/renderer/layers/render_circle_layer.cpp
+++ b/src/mbgl/renderer/layers/render_circle_layer.cpp
@@ -108,27 +108,75 @@ void RenderCircleLayer::render(PaintParameters& parameters, RenderSource*) {
}
}
+GeometryCoordinate projectPoint(const GeometryCoordinate& p, const mat4& posMatrix, const Size& size) {
+ vec4 pos = {{ static_cast<double>(p.x), static_cast<double>(p.y), 0, 1 }};
+ matrix::transformMat4(pos, pos, posMatrix);
+ return {
+ static_cast<int16_t>((static_cast<float>(pos[0] / pos[3]) + 1) * size.width * 0.5),
+ static_cast<int16_t>((static_cast<float>(pos[1] / pos[3]) + 1) * size.height * 0.5)
+ };
+}
+
+GeometryCoordinates projectQueryGeometry(const GeometryCoordinates& queryGeometry, const mat4& posMatrix, const Size& size) {
+ GeometryCoordinates projectedGeometry;
+ for (auto& p : queryGeometry) {
+ projectedGeometry.push_back(projectPoint(p, posMatrix, size));
+ }
+ return projectedGeometry;
+}
+
bool RenderCircleLayer::queryIntersectsFeature(
const GeometryCoordinates& queryGeometry,
const GeometryTileFeature& feature,
const float zoom,
- const float bearing,
- const float pixelsToTileUnits) const {
+ const TransformState& transformState,
+ const float pixelsToTileUnits,
+ const mat4& posMatrix) const {
// Translate query geometry
- auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
+ const GeometryCoordinates& translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
queryGeometry,
evaluated.get<style::CircleTranslate>(),
evaluated.get<style::CircleTranslateAnchor>(),
- bearing,
- pixelsToTileUnits);
+ transformState.getAngle(),
+ pixelsToTileUnits).value_or(queryGeometry);
// Evaluate functions
- auto radius = evaluated.evaluate<style::CircleRadius>(zoom, feature) * pixelsToTileUnits;
- auto stroke = evaluated.evaluate<style::CircleStrokeWidth>(zoom, feature) * pixelsToTileUnits;
+ auto radius = evaluated.evaluate<style::CircleRadius>(zoom, feature);
+ auto stroke = evaluated.evaluate<style::CircleStrokeWidth>(zoom, feature);
+ auto size = radius + stroke;
+
+ // For pitch-alignment: map, compare feature geometry to query geometry in the plane of the tile
+ // Otherwise, compare geometry in the plane of the viewport
+ // A circle with fixed scaling relative to the viewport gets larger in tile space as it moves into the distance
+ // A circle with fixed scaling relative to the map gets smaller in viewport space as it moves into the distance
+ bool alignWithMap = evaluated.evaluate<style::CirclePitchAlignment>(zoom, feature) == AlignmentType::Map;
+ const GeometryCoordinates& transformedQueryGeometry = alignWithMap ?
+ translatedQueryGeometry :
+ projectQueryGeometry(translatedQueryGeometry, posMatrix, transformState.getSize());
+ auto transformedSize = alignWithMap ? size * pixelsToTileUnits : size;
+
+ auto geometry = feature.getGeometries();
+ for (auto& ring : geometry) {
+ for (auto& point : ring) {
+ const GeometryCoordinate& transformedPoint = alignWithMap ? point : projectPoint(point, posMatrix, transformState.getSize());
+
+ float adjustedSize = transformedSize;
+ vec4 center = {{ static_cast<double>(point.x), static_cast<double>(point.y), 0, 1 }};
+ matrix::transformMat4(center, center, posMatrix);
+ auto pitchScale = evaluated.evaluate<style::CirclePitchScale>(zoom, feature);
+ auto pitchAlignment = evaluated.evaluate<style::CirclePitchAlignment>(zoom, feature);
+ if (pitchScale == CirclePitchScaleType::Viewport && pitchAlignment == AlignmentType::Map) {
+ adjustedSize *= center[3] / transformState.getCameraToCenterDistance();
+ } else if (pitchScale == CirclePitchScaleType::Map && pitchAlignment == AlignmentType::Viewport) {
+ adjustedSize *= transformState.getCameraToCenterDistance() / center[3];
+ }
+
+ if (util::polygonIntersectsBufferedPoint(transformedQueryGeometry, transformedPoint, adjustedSize)) return true;
+ }
+ }
- // Test intersection
- return util::polygonIntersectsBufferedMultiPoint(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries(), radius + stroke);
+ return false;
}
} // namespace mbgl
diff --git a/src/mbgl/renderer/layers/render_circle_layer.hpp b/src/mbgl/renderer/layers/render_circle_layer.hpp
index f31715f98f..c9eeae4652 100644
--- a/src/mbgl/renderer/layers/render_circle_layer.hpp
+++ b/src/mbgl/renderer/layers/render_circle_layer.hpp
@@ -20,8 +20,9 @@ public:
const GeometryCoordinates&,
const GeometryTileFeature&,
const float,
+ const TransformState&,
const float,
- const float) const override;
+ const mat4&) const override;
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override;
diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
index 00ab05858f..d5282c9b0d 100644
--- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.cpp
@@ -198,14 +198,15 @@ bool RenderFillExtrusionLayer::queryIntersectsFeature(
const GeometryCoordinates& queryGeometry,
const GeometryTileFeature& feature,
const float,
- const float bearing,
- const float pixelsToTileUnits) const {
+ const TransformState& transformState,
+ const float pixelsToTileUnits,
+ const mat4&) const {
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
queryGeometry,
evaluated.get<style::FillExtrusionTranslate>(),
evaluated.get<style::FillExtrusionTranslateAnchor>(),
- bearing,
+ transformState.getAngle(),
pixelsToTileUnits);
return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries());
diff --git a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
index 838494cf91..f7ba13c267 100644
--- a/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
+++ b/src/mbgl/renderer/layers/render_fill_extrusion_layer.hpp
@@ -22,8 +22,9 @@ public:
const GeometryCoordinates&,
const GeometryTileFeature&,
const float,
+ const TransformState&,
const float,
- const float) const override;
+ const mat4&) const override;
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override;
diff --git a/src/mbgl/renderer/layers/render_fill_layer.cpp b/src/mbgl/renderer/layers/render_fill_layer.cpp
index 2607ebc170..c59ca6f906 100644
--- a/src/mbgl/renderer/layers/render_fill_layer.cpp
+++ b/src/mbgl/renderer/layers/render_fill_layer.cpp
@@ -218,14 +218,15 @@ bool RenderFillLayer::queryIntersectsFeature(
const GeometryCoordinates& queryGeometry,
const GeometryTileFeature& feature,
const float,
- const float bearing,
- const float pixelsToTileUnits) const {
+ const TransformState& transformState,
+ const float pixelsToTileUnits,
+ const mat4&) const {
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
queryGeometry,
evaluated.get<style::FillTranslate>(),
evaluated.get<style::FillTranslateAnchor>(),
- bearing,
+ transformState.getAngle(),
pixelsToTileUnits);
return util::polygonIntersectsMultiPolygon(translatedQueryGeometry.value_or(queryGeometry), feature.getGeometries());
diff --git a/src/mbgl/renderer/layers/render_fill_layer.hpp b/src/mbgl/renderer/layers/render_fill_layer.hpp
index a51865698f..bd195fb828 100644
--- a/src/mbgl/renderer/layers/render_fill_layer.hpp
+++ b/src/mbgl/renderer/layers/render_fill_layer.hpp
@@ -20,8 +20,9 @@ public:
const GeometryCoordinates&,
const GeometryTileFeature&,
const float,
+ const TransformState&,
const float,
- const float) const override;
+ const mat4&) const override;
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override;
diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.cpp b/src/mbgl/renderer/layers/render_heatmap_layer.cpp
index 86884b01a4..dec9edb318 100644
--- a/src/mbgl/renderer/layers/render_heatmap_layer.cpp
+++ b/src/mbgl/renderer/layers/render_heatmap_layer.cpp
@@ -201,12 +201,12 @@ bool RenderHeatmapLayer::queryIntersectsFeature(
const GeometryCoordinates& queryGeometry,
const GeometryTileFeature& feature,
const float zoom,
- const float bearing,
- const float pixelsToTileUnits) const {
+ const TransformState&,
+ const float pixelsToTileUnits,
+ const mat4&) const {
(void) queryGeometry;
(void) feature;
(void) zoom;
- (void) bearing;
(void) pixelsToTileUnits;
return false;
}
diff --git a/src/mbgl/renderer/layers/render_heatmap_layer.hpp b/src/mbgl/renderer/layers/render_heatmap_layer.hpp
index 3f0b1f91b4..29fad7d8b8 100644
--- a/src/mbgl/renderer/layers/render_heatmap_layer.hpp
+++ b/src/mbgl/renderer/layers/render_heatmap_layer.hpp
@@ -22,8 +22,9 @@ public:
const GeometryCoordinates&,
const GeometryTileFeature&,
const float,
+ const TransformState&,
const float,
- const float) const override;
+ const mat4&) const override;
void updateColorRamp();
diff --git a/src/mbgl/renderer/layers/render_line_layer.cpp b/src/mbgl/renderer/layers/render_line_layer.cpp
index e7fe4d34b2..361ad0c76b 100644
--- a/src/mbgl/renderer/layers/render_line_layer.cpp
+++ b/src/mbgl/renderer/layers/render_line_layer.cpp
@@ -177,15 +177,16 @@ bool RenderLineLayer::queryIntersectsFeature(
const GeometryCoordinates& queryGeometry,
const GeometryTileFeature& feature,
const float zoom,
- const float bearing,
- const float pixelsToTileUnits) const {
+ const TransformState& transformState,
+ const float pixelsToTileUnits,
+ const mat4&) const {
// Translate query geometry
auto translatedQueryGeometry = FeatureIndex::translateQueryGeometry(
queryGeometry,
evaluated.get<style::LineTranslate>(),
evaluated.get<style::LineTranslateAnchor>(),
- bearing,
+ transformState.getAngle(),
pixelsToTileUnits);
// Evaluate function
diff --git a/src/mbgl/renderer/layers/render_line_layer.hpp b/src/mbgl/renderer/layers/render_line_layer.hpp
index 8bf7e2329d..5d5d79c044 100644
--- a/src/mbgl/renderer/layers/render_line_layer.hpp
+++ b/src/mbgl/renderer/layers/render_line_layer.hpp
@@ -29,8 +29,9 @@ public:
const GeometryCoordinates&,
const GeometryTileFeature&,
const float,
+ const TransformState&,
const float,
- const float) const override;
+ const mat4&) const override;
std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const override;
diff --git a/src/mbgl/renderer/render_layer.hpp b/src/mbgl/renderer/render_layer.hpp
index 5b92ffa4db..3e2f1d7525 100644
--- a/src/mbgl/renderer/render_layer.hpp
+++ b/src/mbgl/renderer/render_layer.hpp
@@ -4,6 +4,7 @@
#include <mbgl/style/layer_impl.hpp>
#include <mbgl/style/layer_type.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
+#include <mbgl/util/mat4.hpp>
#include <memory>
#include <string>
@@ -17,6 +18,7 @@ class PropertyEvaluationParameters;
class PaintParameters;
class RenderSource;
class RenderTile;
+class TransformState;
class RenderLayer {
protected:
@@ -69,8 +71,9 @@ public:
const GeometryCoordinates&,
const GeometryTileFeature&,
const float,
+ const TransformState&,
const float,
- const float) const { return false; };
+ const mat4&) const { return false; };
virtual std::unique_ptr<Bucket> createBucket(const BucketParameters&, const std::vector<const RenderLayer*>&) const = 0;
diff --git a/src/mbgl/renderer/render_source.hpp b/src/mbgl/renderer/render_source.hpp
index 53519c763e..dc80cb1dc6 100644
--- a/src/mbgl/renderer/render_source.hpp
+++ b/src/mbgl/renderer/render_source.hpp
@@ -65,7 +65,7 @@ public:
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const = 0;
+ const mat4& projMatrix) const = 0;
virtual std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const = 0;
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index 7b25b37cf2..4380ef24a1 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -85,11 +85,6 @@ void Renderer::Impl::setObserver(RendererObserver* observer_) {
void Renderer::Impl::render(const UpdateParameters& updateParameters) {
if (updateParameters.mode != MapMode::Continuous) {
- // Don't load/render anyting in still mode until explicitly requested.
- if (!updateParameters.stillImageRequest) {
- return;
- }
-
// Reset zoom history state.
zoomHistory.first = true;
}
@@ -401,10 +396,6 @@ void Renderer::Impl::render(const UpdateParameters& updateParameters) {
}
placementChanged = newPlacement->commit(*placement, parameters.timePoint);
- // commitFeatureIndexes depends on the assumption that no new FeatureIndex has been loaded since placement
- // started. If we violate this assumption, then we need to either make CollisionIndex completely independendent of
- // FeatureIndex, or find a way for its entries to point to multiple FeatureIndexes.
- commitFeatureIndexes();
crossTileSymbolIndex.pruneUnusedLayers(usedSymbolLayers);
if (placementChanged || symbolBucketsChanged) {
placement = std::move(newPlacement);
@@ -681,6 +672,39 @@ std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineStrin
return queryRenderedFeatures(geometry, options, layers);
}
+
+void Renderer::Impl::queryRenderedSymbols(std::unordered_map<std::string, std::vector<Feature>>& resultsByLayer,
+ const ScreenLineString& geometry,
+ const std::vector<const RenderLayer*>& layers,
+ const RenderedQueryOptions& options) const {
+
+ auto renderedSymbols = placement->getCollisionIndex().queryRenderedSymbols(geometry);
+ std::vector<std::reference_wrapper<const RetainedQueryData>> bucketQueryData;
+ for (auto entry : renderedSymbols) {
+ bucketQueryData.push_back(placement->getQueryData(entry.first));
+ }
+ // Although symbol query is global, symbol results are only sortable within a bucket
+ // For a predictable global sort order, we sort the buckets based on their corresponding tile position
+ std::sort(bucketQueryData.begin(), bucketQueryData.end(), [](const RetainedQueryData& a, const RetainedQueryData& b) {
+ return
+ std::tie(a.tileID.canonical.z, a.tileID.canonical.y, a.tileID.wrap, a.tileID.canonical.x) <
+ std::tie(b.tileID.canonical.z, b.tileID.canonical.y, b.tileID.wrap, b.tileID.canonical.x);
+ });
+
+ for (auto wrappedQueryData : bucketQueryData) {
+ auto& queryData = wrappedQueryData.get();
+ auto bucketSymbols = queryData.featureIndex->lookupSymbolFeatures(renderedSymbols[queryData.bucketInstanceId],
+ options,
+ layers,
+ queryData.tileID,
+ queryData.featureSortOrder);
+
+ for (auto layer : bucketSymbols) {
+ auto& resultFeatures = resultsByLayer[layer.first];
+ std::move(layer.second.begin(), layer.second.end(), std::inserter(resultFeatures, resultFeatures.end()));
+ }
+ }
+}
std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineString& geometry, const RenderedQueryOptions& options, const std::vector<const RenderLayer*>& layers) const {
std::unordered_set<std::string> sourceIDs;
@@ -688,13 +712,18 @@ std::vector<Feature> Renderer::Impl::queryRenderedFeatures(const ScreenLineStrin
sourceIDs.emplace(layer->baseImpl->source);
}
+ mat4 projMatrix;
+ transformState.getProjMatrix(projMatrix);
+
std::unordered_map<std::string, std::vector<Feature>> resultsByLayer;
for (const auto& sourceID : sourceIDs) {
if (RenderSource* renderSource = getRenderSource(sourceID)) {
- auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, layers, options, placement->getCollisionIndex());
+ auto sourceResults = renderSource->queryRenderedFeatures(geometry, transformState, layers, options, projMatrix);
std::move(sourceResults.begin(), sourceResults.end(), std::inserter(resultsByLayer, resultsByLayer.begin()));
}
}
+
+ queryRenderedSymbols(resultsByLayer, geometry, layers, options);
std::vector<Feature> result;
@@ -793,15 +822,6 @@ bool Renderer::Impl::hasTransitions(TimePoint timePoint) const {
return false;
}
-void Renderer::Impl::commitFeatureIndexes() {
- for (auto& source : renderSources) {
- for (auto& renderTile : source.second->getRenderTiles()) {
- Tile& tile = renderTile.get().tile;
- tile.commitFeatureIndex();
- }
- }
-}
-
void Renderer::Impl::updateFadingTiles() {
fadingTiles = false;
for (auto& source : renderSources) {
diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp
index 4675ac79ea..4124f6f416 100644
--- a/src/mbgl/renderer/renderer_impl.hpp
+++ b/src/mbgl/renderer/renderer_impl.hpp
@@ -64,7 +64,12 @@ private:
RenderLayer* getRenderLayer(const std::string& id);
const RenderLayer* getRenderLayer(const std::string& id) const;
-
+
+ void queryRenderedSymbols(std::unordered_map<std::string, std::vector<Feature>>& resultsByLayer,
+ const ScreenLineString& geometry,
+ const std::vector<const RenderLayer*>& layers,
+ const RenderedQueryOptions& options) const;
+
std::vector<Feature> queryRenderedFeatures(const ScreenLineString&, const RenderedQueryOptions&, const std::vector<const RenderLayer*>&) const;
// GlyphManagerObserver implementation.
@@ -74,7 +79,6 @@ private:
void onTileChanged(RenderSource&, const OverscaledTileID&) override;
void onTileError(RenderSource&, const OverscaledTileID&, std::exception_ptr) override;
- void commitFeatureIndexes();
void updateFadingTiles();
friend class Renderer;
diff --git a/src/mbgl/renderer/sources/render_custom_geometry_source.cpp b/src/mbgl/renderer/sources/render_custom_geometry_source.cpp
index 057ad5a4a7..2d28b8dd84 100644
--- a/src/mbgl/renderer/sources/render_custom_geometry_source.cpp
+++ b/src/mbgl/renderer/sources/render_custom_geometry_source.cpp
@@ -68,8 +68,8 @@ RenderCustomGeometrySource::queryRenderedFeatures(const ScreenLineString& geomet
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, collisionIndex);
+ const mat4& projMatrix) const {
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, projMatrix);
}
std::vector<Feature> RenderCustomGeometrySource::querySourceFeatures(const SourceQueryOptions& options) const {
diff --git a/src/mbgl/renderer/sources/render_custom_geometry_source.hpp b/src/mbgl/renderer/sources/render_custom_geometry_source.hpp
index 033d731029..5533fe2b83 100644
--- a/src/mbgl/renderer/sources/render_custom_geometry_source.hpp
+++ b/src/mbgl/renderer/sources/render_custom_geometry_source.hpp
@@ -28,7 +28,7 @@ public:
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const final;
+ const mat4& projMatrix) const final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp
index cbf4db70b5..0e265efff4 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.cpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.cpp
@@ -86,8 +86,8 @@ RenderGeoJSONSource::queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, collisionIndex);
+ const mat4& projMatrix) const {
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, projMatrix);
}
std::vector<Feature> RenderGeoJSONSource::querySourceFeatures(const SourceQueryOptions& options) const {
diff --git a/src/mbgl/renderer/sources/render_geojson_source.hpp b/src/mbgl/renderer/sources/render_geojson_source.hpp
index 72fccbd043..297fa09a29 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.hpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.hpp
@@ -32,7 +32,7 @@ public:
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex&) const final;
+ const mat4& projMatrix) const final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
diff --git a/src/mbgl/renderer/sources/render_image_source.cpp b/src/mbgl/renderer/sources/render_image_source.cpp
index 4946b0bc30..dce5e40185 100644
--- a/src/mbgl/renderer/sources/render_image_source.cpp
+++ b/src/mbgl/renderer/sources/render_image_source.cpp
@@ -93,7 +93,7 @@ RenderImageSource::queryRenderedFeatures(const ScreenLineString&,
const TransformState&,
const std::vector<const RenderLayer*>&,
const RenderedQueryOptions&,
- const CollisionIndex&) const {
+ const mat4&) const {
return std::unordered_map<std::string, std::vector<Feature>> {};
}
diff --git a/src/mbgl/renderer/sources/render_image_source.hpp b/src/mbgl/renderer/sources/render_image_source.hpp
index 85ee0ace11..cf14e180fd 100644
--- a/src/mbgl/renderer/sources/render_image_source.hpp
+++ b/src/mbgl/renderer/sources/render_image_source.hpp
@@ -33,7 +33,7 @@ public:
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const final;
+ const mat4& projMatrix) const final;
std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const final;
diff --git a/src/mbgl/renderer/sources/render_raster_dem_source.cpp b/src/mbgl/renderer/sources/render_raster_dem_source.cpp
index b3153622c3..fbf2c09d19 100644
--- a/src/mbgl/renderer/sources/render_raster_dem_source.cpp
+++ b/src/mbgl/renderer/sources/render_raster_dem_source.cpp
@@ -147,7 +147,7 @@ RenderRasterDEMSource::queryRenderedFeatures(const ScreenLineString&,
const TransformState&,
const std::vector<const RenderLayer*>&,
const RenderedQueryOptions&,
- const CollisionIndex& ) const {
+ const mat4&) const {
return std::unordered_map<std::string, std::vector<Feature>> {};
}
diff --git a/src/mbgl/renderer/sources/render_raster_dem_source.hpp b/src/mbgl/renderer/sources/render_raster_dem_source.hpp
index 741214a14d..48c7803e92 100644
--- a/src/mbgl/renderer/sources/render_raster_dem_source.hpp
+++ b/src/mbgl/renderer/sources/render_raster_dem_source.hpp
@@ -28,7 +28,7 @@ public:
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const final;
+ const mat4& projMatrix) const final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
diff --git a/src/mbgl/renderer/sources/render_raster_source.cpp b/src/mbgl/renderer/sources/render_raster_source.cpp
index 60b3fa9a3b..f97ce4e65b 100644
--- a/src/mbgl/renderer/sources/render_raster_source.cpp
+++ b/src/mbgl/renderer/sources/render_raster_source.cpp
@@ -77,7 +77,7 @@ RenderRasterSource::queryRenderedFeatures(const ScreenLineString&,
const TransformState&,
const std::vector<const RenderLayer*>&,
const RenderedQueryOptions&,
- const CollisionIndex& ) const {
+ const mat4&) const {
return std::unordered_map<std::string, std::vector<Feature>> {};
}
diff --git a/src/mbgl/renderer/sources/render_raster_source.hpp b/src/mbgl/renderer/sources/render_raster_source.hpp
index 78eda199ac..32539a046d 100644
--- a/src/mbgl/renderer/sources/render_raster_source.hpp
+++ b/src/mbgl/renderer/sources/render_raster_source.hpp
@@ -28,7 +28,7 @@ public:
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const final;
+ const mat4& projMatrix) const final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
diff --git a/src/mbgl/renderer/sources/render_vector_source.cpp b/src/mbgl/renderer/sources/render_vector_source.cpp
index e87bea5dcd..4de4f01e3f 100644
--- a/src/mbgl/renderer/sources/render_vector_source.cpp
+++ b/src/mbgl/renderer/sources/render_vector_source.cpp
@@ -80,8 +80,8 @@ RenderVectorSource::queryRenderedFeatures(const ScreenLineString& geometry,
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const {
- return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, collisionIndex);
+ const mat4& projMatrix) const {
+ return tilePyramid.queryRenderedFeatures(geometry, transformState, layers, options, projMatrix);
}
std::vector<Feature> RenderVectorSource::querySourceFeatures(const SourceQueryOptions& options) const {
diff --git a/src/mbgl/renderer/sources/render_vector_source.hpp b/src/mbgl/renderer/sources/render_vector_source.hpp
index 592160dc16..6fd2425aa3 100644
--- a/src/mbgl/renderer/sources/render_vector_source.hpp
+++ b/src/mbgl/renderer/sources/render_vector_source.hpp
@@ -28,7 +28,7 @@ public:
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const final;
+ const mat4& projMatrix) const final;
std::vector<Feature>
querySourceFeatures(const SourceQueryOptions&) const final;
diff --git a/src/mbgl/renderer/tile_pyramid.cpp b/src/mbgl/renderer/tile_pyramid.cpp
index 8f83a0f982..d28e95181b 100644
--- a/src/mbgl/renderer/tile_pyramid.cpp
+++ b/src/mbgl/renderer/tile_pyramid.cpp
@@ -242,7 +242,7 @@ std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRendered
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const {
+ const mat4& projMatrix) const {
std::unordered_map<std::string, std::vector<Feature>> result;
if (renderTiles.empty() || geometry.empty()) {
return result;
@@ -264,14 +264,19 @@ std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRendered
std::tie(b.id.canonical.z, b.id.canonical.y, b.id.wrap, b.id.canonical.x);
});
+ auto maxPitchScaleFactor = transformState.maxPitchScaleFactor();
+
for (const RenderTile& renderTile : sortedTiles) {
+ const float scale = std::pow(2, transformState.getZoom() - renderTile.id.canonical.z);
+ auto queryPadding = maxPitchScaleFactor * renderTile.tile.getQueryPadding(layers) * util::EXTENT / util::tileSize / scale;
+
GeometryCoordinate tileSpaceBoundsMin = TileCoordinate::toGeometryCoordinate(renderTile.id, box.min);
- if (tileSpaceBoundsMin.x >= util::EXTENT || tileSpaceBoundsMin.y >= util::EXTENT) {
+ if (tileSpaceBoundsMin.x - queryPadding >= util::EXTENT || tileSpaceBoundsMin.y - queryPadding >= util::EXTENT) {
continue;
}
GeometryCoordinate tileSpaceBoundsMax = TileCoordinate::toGeometryCoordinate(renderTile.id, box.max);
- if (tileSpaceBoundsMax.x < 0 || tileSpaceBoundsMax.y < 0) {
+ if (tileSpaceBoundsMax.x + queryPadding < 0 || tileSpaceBoundsMax.y + queryPadding < 0) {
continue;
}
@@ -286,7 +291,7 @@ std::unordered_map<std::string, std::vector<Feature>> TilePyramid::queryRendered
transformState,
layers,
options,
- collisionIndex);
+ projMatrix);
}
return result;
diff --git a/src/mbgl/renderer/tile_pyramid.hpp b/src/mbgl/renderer/tile_pyramid.hpp
index 2638599c38..0cef9e2c40 100644
--- a/src/mbgl/renderer/tile_pyramid.hpp
+++ b/src/mbgl/renderer/tile_pyramid.hpp
@@ -54,7 +54,7 @@ public:
const TransformState& transformState,
const std::vector<const RenderLayer*>&,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) const;
+ const mat4& projMatrix) const;
std::vector<Feature> querySourceFeatures(const SourceQueryOptions&) const;
diff --git a/src/mbgl/shaders/line.cpp b/src/mbgl/shaders/line.cpp
index c700295a15..68d2dcc468 100644
--- a/src/mbgl/shaders/line.cpp
+++ b/src/mbgl/shaders/line.cpp
@@ -31,6 +31,7 @@ uniform vec2 u_gl_units_to_pixels;
varying vec2 v_normal;
varying vec2 v_width2;
varying float v_gamma_scale;
+varying highp float v_linesofar;
#ifndef HAS_UNIFORM_u_color
@@ -131,6 +132,8 @@ void main() {
vec2 a_extrude = a_data.xy - 128.0;
float a_direction = mod(a_data.z, 4.0) - 1.0;
+ v_linesofar = (floor(a_data.z / 4.0) + a_data.w * 64.0) * 2.0;
+
vec2 pos = a_pos_normal.xy;
// x is 1 if it's a round cap, 0 otherwise
diff --git a/src/mbgl/style/expression/compound_expression.cpp b/src/mbgl/style/expression/compound_expression.cpp
index 4739d50168..4226756fe4 100644
--- a/src/mbgl/style/expression/compound_expression.cpp
+++ b/src/mbgl/style/expression/compound_expression.cpp
@@ -3,6 +3,7 @@
#include <mbgl/style/expression/util.hpp>
#include <mbgl/tile/geometry_tile_data.hpp>
#include <mbgl/math/log2.hpp>
+#include <mbgl/util/i18n.hpp>
#include <mbgl/util/ignore.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/platform.hpp>
@@ -472,8 +473,8 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
}
return result;
});
-
- define("round", [](double x) -> Result<double> { return std::round(x); });
+
+ define("round", [](double x) -> Result<double> { return ::round(x); });
define("floor", [](double x) -> Result<double> { return std::floor(x); });
define("ceil", [](double x) -> Result<double> { return std::ceil(x); });
define("abs", [](double x) -> Result<double> { return std::abs(x); });
@@ -488,6 +489,10 @@ std::unordered_map<std::string, CompoundExpressionRegistry::Definition> initiali
define("<=", [](const std::string& lhs, const std::string& rhs) -> Result<bool> { return lhs <= rhs; });
define("!", [](bool e) -> Result<bool> { return !e; });
+
+ define("is-supported-script", [](const std::string& x) -> Result<bool> {
+ return util::i18n::isStringInSupportedScript(x);
+ });
define("upcase", [](const std::string& input) -> Result<std::string> {
return platform::uppercase(input);
diff --git a/src/mbgl/text/collision_index.cpp b/src/mbgl/text/collision_index.cpp
index 833658c33e..091840a371 100644
--- a/src/mbgl/text/collision_index.cpp
+++ b/src/mbgl/text/collision_index.cpp
@@ -219,7 +219,7 @@ std::pair<bool,bool> CollisionIndex::placeLineFeature(CollisionFeature& feature,
}
-void CollisionIndex::insertFeature(CollisionFeature& feature, bool ignorePlacement) {
+void CollisionIndex::insertFeature(CollisionFeature& feature, bool ignorePlacement, uint32_t bucketInstanceId) {
if (feature.alongLine) {
for (auto& circle : feature.boxes) {
if (!circle.used) {
@@ -227,18 +227,18 @@ void CollisionIndex::insertFeature(CollisionFeature& feature, bool ignorePlaceme
}
if (ignorePlacement) {
- ignoredGrid.insert(IndexedSubfeature(feature.indexedFeature), {{ circle.px, circle.py }, circle.radius});
+ ignoredGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId), {{ circle.px, circle.py }, circle.radius});
} else {
- collisionGrid.insert(IndexedSubfeature(feature.indexedFeature), {{ circle.px, circle.py }, circle.radius});
+ collisionGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId), {{ circle.px, circle.py }, circle.radius});
}
}
} else {
assert(feature.boxes.size() == 1);
auto& box = feature.boxes[0];
if (ignorePlacement) {
- ignoredGrid.insert(IndexedSubfeature(feature.indexedFeature), {{ box.px1, box.py1 }, { box.px2, box.py2 }});
+ ignoredGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId), {{ box.px1, box.py1 }, { box.px2, box.py2 }});
} else {
- collisionGrid.insert(IndexedSubfeature(feature.indexedFeature), {{ box.px1, box.py1 }, { box.px2, box.py2 }});
+ collisionGrid.insert(IndexedSubfeature(feature.indexedFeature, bucketInstanceId), {{ box.px1, box.py1 }, { box.px2, box.py2 }});
}
}
}
@@ -262,66 +262,41 @@ bool polygonIntersectsBox(const LineString<float>& polygon, const GridIndex<Inde
return util::polygonIntersectsPolygon(integerPolygon, bboxPoints);
}
-std::vector<IndexedSubfeature> CollisionIndex::queryRenderedSymbols(const GeometryCoordinates& queryGeometry, const UnwrappedTileID& tileID, const std::string& sourceID) const {
- std::vector<IndexedSubfeature> result;
+std::unordered_map<uint32_t, std::vector<IndexedSubfeature>> CollisionIndex::queryRenderedSymbols(const ScreenLineString& queryGeometry) const {
+ std::unordered_map<uint32_t, std::vector<IndexedSubfeature>> result;
if (queryGeometry.empty() || (collisionGrid.empty() && ignoredGrid.empty())) {
return result;
}
-
- mat4 posMatrix;
- mat4 projMatrix;
- transformState.getProjMatrix(projMatrix);
- transformState.matrixFor(posMatrix, tileID);
- matrix::multiply(posMatrix, projMatrix, posMatrix);
-
- // queryGeometry is specified in integer tile units, but in projecting we switch to float pixels
- LineString<float> projectedQuery;
+
+ LineString<float> gridQuery;
for (const auto& point : queryGeometry) {
- auto projected = projectPoint(posMatrix, convertPoint<float>(point));
- projectedQuery.push_back(projected);
+ gridQuery.emplace_back(point.x + viewportPadding, point.y + viewportPadding);
}
- auto envelope = mapbox::geometry::envelope(projectedQuery);
+ auto envelope = mapbox::geometry::envelope(gridQuery);
using QueryResult = std::pair<IndexedSubfeature, GridIndex<IndexedSubfeature>::BBox>;
- std::vector<QueryResult> thisTileFeatures;
std::vector<QueryResult> features = collisionGrid.queryWithBoxes(envelope);
-
- for (auto& queryResult : features) {
- auto& feature = queryResult.first;
- if (feature.sourceID == sourceID && feature.tileID == tileID.canonical) {
- // We only have to filter on the canonical ID because even if the feature is showing multiple times
- // we treat it as one feature.
- thisTileFeatures.push_back(queryResult);
- }
- }
-
std::vector<QueryResult> ignoredFeatures = ignoredGrid.queryWithBoxes(envelope);
- for (auto& queryResult : ignoredFeatures) {
- auto& feature = queryResult.first;
- if (feature.sourceID == sourceID && feature.tileID == tileID.canonical) {
- thisTileFeatures.push_back(queryResult);
- }
- }
+ features.insert(features.end(), ignoredFeatures.begin(), ignoredFeatures.end());
- std::unordered_map<std::string, std::unordered_map<std::string, std::unordered_set<std::size_t>>> sourceLayerFeatures;
- for (auto& queryResult : thisTileFeatures) {
+ std::unordered_map<uint32_t, std::unordered_set<size_t>> seenBuckets;
+ for (auto& queryResult : features) {
auto& feature = queryResult.first;
auto& bbox = queryResult.second;
// Skip already seen features.
- auto& seenFeatures = sourceLayerFeatures[feature.sourceLayerName][feature.bucketName];
+ auto& seenFeatures = seenBuckets[feature.bucketInstanceId];
if (seenFeatures.find(feature.index) != seenFeatures.end())
continue;
-
- seenFeatures.insert(feature.index);
- if (!polygonIntersectsBox(projectedQuery, bbox)) {
+ if (!polygonIntersectsBox(gridQuery, bbox)) {
continue;
}
- result.push_back(feature);
+ seenFeatures.insert(feature.index);
+ result[feature.bucketInstanceId].push_back(feature);
}
return result;
diff --git a/src/mbgl/text/collision_index.hpp b/src/mbgl/text/collision_index.hpp
index 8653c1d76c..b2be4c6ade 100644
--- a/src/mbgl/text/collision_index.hpp
+++ b/src/mbgl/text/collision_index.hpp
@@ -28,11 +28,10 @@ public:
const bool pitchWithMap,
const bool collisionDebug);
- void insertFeature(CollisionFeature& feature, bool ignorePlacement);
+ void insertFeature(CollisionFeature& feature, bool ignorePlacement, uint32_t bucketInstanceId);
- std::vector<IndexedSubfeature> queryRenderedSymbols(const GeometryCoordinates&, const UnwrappedTileID& tileID, const std::string& sourceID) const;
+ std::unordered_map<uint32_t, std::vector<IndexedSubfeature>> queryRenderedSymbols(const ScreenLineString&) const;
-
private:
bool isOffscreen(const CollisionBox&) const;
bool isInsideGrid(const CollisionBox&) const;
diff --git a/src/mbgl/text/cross_tile_symbol_index.cpp b/src/mbgl/text/cross_tile_symbol_index.cpp
index 01a4a02b4e..b0c3511ce3 100644
--- a/src/mbgl/text/cross_tile_symbol_index.cpp
+++ b/src/mbgl/text/cross_tile_symbol_index.cpp
@@ -153,6 +153,10 @@ bool CrossTileSymbolIndex::addLayer(RenderSymbolLayer& symbolLayer) {
auto bucket = renderTile.tile.getBucket(*symbolLayer.baseImpl);
assert(dynamic_cast<SymbolBucket*>(bucket));
SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket);
+ if (symbolBucket.bucketLeaderID != symbolLayer.getID()) {
+ // Only add this layer if it's the "group leader" for the bucket
+ continue;
+ }
if (!symbolBucket.bucketInstanceId) {
symbolBucket.bucketInstanceId = ++maxBucketInstanceId;
diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp
index 54b2b7539b..9883a1f456 100644
--- a/src/mbgl/text/placement.cpp
+++ b/src/mbgl/text/placement.cpp
@@ -49,17 +49,25 @@ void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatri
if (!renderTile.tile.isRenderable()) {
continue;
}
-
- auto bucket = renderTile.tile.getBucket(*symbolLayer.baseImpl);
+ assert(dynamic_cast<GeometryTile*>(&renderTile.tile));
+ GeometryTile& geometryTile = static_cast<GeometryTile&>(renderTile.tile);
+
+
+ auto bucket = geometryTile.getBucket(*symbolLayer.baseImpl);
assert(dynamic_cast<SymbolBucket*>(bucket));
SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket);
+
+ if (symbolBucket.bucketLeaderID != symbolLayer.getID()) {
+ // Only place this layer if it's the "group leader" for the bucket
+ continue;
+ }
auto& layout = symbolBucket.layout;
const float pixelsToTileUnits = renderTile.id.pixelsToTileUnits(1, state.getZoom());
- const float scale = std::pow(2, state.getZoom() - renderTile.tile.id.overscaledZ);
- const float textPixelRatio = (util::tileSize * renderTile.tile.id.overscaleFactor()) / util::EXTENT;
+ const float scale = std::pow(2, state.getZoom() - geometryTile.id.overscaledZ);
+ const float textPixelRatio = (util::tileSize * geometryTile.id.overscaleFactor()) / util::EXTENT;
mat4 posMatrix;
state.matrixFor(posMatrix, renderTile.id);
@@ -76,7 +84,14 @@ void Placement::placeLayer(RenderSymbolLayer& symbolLayer, const mat4& projMatri
layout.get<style::IconRotationAlignment>() == style::AlignmentType::Map,
state,
pixelsToTileUnits);
-
+
+
+ // As long as this placement lives, we have to hold onto this bucket's
+ // matching FeatureIndex/data for querying purposes
+ retainedQueryData.emplace(std::piecewise_construct,
+ std::forward_as_tuple(symbolBucket.bucketInstanceId),
+ std::forward_as_tuple(symbolBucket.bucketInstanceId, geometryTile.getFeatureIndex(), geometryTile.id));
+
placeLayerBucket(symbolBucket, posMatrix, textLabelPlaneMatrix, iconLabelPlaneMatrix, scale, textPixelRatio, showCollisionBoxes, seenCrossTileIDs, renderTile.tile.holdForFade());
}
}
@@ -150,11 +165,11 @@ void Placement::placeLayerBucket(
}
if (placeText) {
- collisionIndex.insertFeature(symbolInstance.textCollisionFeature, bucket.layout.get<style::TextIgnorePlacement>());
+ collisionIndex.insertFeature(symbolInstance.textCollisionFeature, bucket.layout.get<style::TextIgnorePlacement>(), bucket.bucketInstanceId);
}
if (placeIcon) {
- collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, bucket.layout.get<style::IconIgnorePlacement>());
+ collisionIndex.insertFeature(symbolInstance.iconCollisionFeature, bucket.layout.get<style::IconIgnorePlacement>(), bucket.bucketInstanceId);
}
assert(symbolInstance.crossTileID != 0);
@@ -220,6 +235,10 @@ void Placement::updateLayerOpacities(RenderSymbolLayer& symbolLayer) {
auto bucket = renderTile.tile.getBucket(*symbolLayer.baseImpl);
assert(dynamic_cast<SymbolBucket*>(bucket));
SymbolBucket& symbolBucket = *reinterpret_cast<SymbolBucket*>(bucket);
+ if (symbolBucket.bucketLeaderID != symbolLayer.getID()) {
+ // Only update opacities this layer if it's the "group leader" for the bucket
+ continue;
+ }
updateBucketOpacities(symbolBucket, seenCrossTileIDs);
}
}
@@ -305,6 +324,10 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, std::set<uint32_t>&
bucket.updateOpacity();
bucket.sortFeatures(state.getAngle());
+ auto retainedData = retainedQueryData.find(bucket.bucketInstanceId);
+ if (retainedData != retainedQueryData.end()) {
+ retainedData->second.featureSortOrder = bucket.featureSortOrder;
+ }
}
float Placement::symbolFadeChange(TimePoint now) const {
@@ -337,5 +360,13 @@ void Placement::setStale() {
const CollisionIndex& Placement::getCollisionIndex() const {
return collisionIndex;
}
+
+const RetainedQueryData& Placement::getQueryData(uint32_t bucketInstanceId) const {
+ auto it = retainedQueryData.find(bucketInstanceId);
+ if (it == retainedQueryData.end()) {
+ throw std::runtime_error("Placement::getQueryData with unrecognized bucketInstanceId");
+ }
+ return it->second;
+}
} // namespace mbgl
diff --git a/src/mbgl/text/placement.hpp b/src/mbgl/text/placement.hpp
index 653ae352ed..0e1751b127 100644
--- a/src/mbgl/text/placement.hpp
+++ b/src/mbgl/text/placement.hpp
@@ -44,7 +44,21 @@ public:
// visible right away.
const bool skipFade;
};
-
+
+struct RetainedQueryData {
+ uint32_t bucketInstanceId;
+ std::shared_ptr<FeatureIndex> featureIndex;
+ OverscaledTileID tileID;
+ std::shared_ptr<std::vector<size_t>> featureSortOrder;
+
+ RetainedQueryData(uint32_t bucketInstanceId_,
+ std::shared_ptr<FeatureIndex> featureIndex_,
+ OverscaledTileID tileID_)
+ : bucketInstanceId(bucketInstanceId_)
+ , featureIndex(std::move(featureIndex_))
+ , tileID(std::move(tileID_)) {}
+};
+
class Placement {
public:
Placement(const TransformState&, MapMode mapMode);
@@ -59,6 +73,8 @@ public:
bool stillRecent(TimePoint now) const;
void setRecent(TimePoint now);
void setStale();
+
+ const RetainedQueryData& getQueryData(uint32_t bucketInstanceId) const;
private:
void placeLayerBucket(
@@ -85,6 +101,8 @@ private:
TimePoint recentUntil;
bool stale = false;
+
+ std::unordered_map<uint32_t, RetainedQueryData> retainedQueryData;
};
} // namespace mbgl
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index 28f46f6f54..af28fe3963 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -132,7 +132,7 @@ void GeometryTile::onLayout(LayoutResult result, const uint64_t resultCorrelatio
buckets = std::move(result.buckets);
- featureIndexPendingCommit = { std::move(result.featureIndex) };
+ latestFeatureIndex = std::move(result.featureIndex);
if (result.glyphAtlasImage) {
glyphAtlasImage = std::move(*result.glyphAtlasImage);
@@ -200,13 +200,15 @@ Bucket* GeometryTile::getBucket(const Layer::Impl& layer) const {
return it->second.get();
}
-void GeometryTile::commitFeatureIndex() {
- // We commit our pending FeatureIndex when a global placement has run,
- // synchronizing the global CollisionIndex with the latest buckets/FeatureIndex
- if (featureIndexPendingCommit) {
- featureIndex = std::move(*featureIndexPendingCommit);
- featureIndexPendingCommit = nullopt;
+float GeometryTile::getQueryPadding(const std::vector<const RenderLayer*>& layers) {
+ float queryPadding = 0;
+ for (const RenderLayer* layer : layers) {
+ auto bucket = getBucket(*layer->baseImpl);
+ if (bucket && bucket->hasData()) {
+ queryPadding = std::max(queryPadding, bucket->getQueryRadius(*layer));
+ }
}
+ return queryPadding;
}
void GeometryTile::queryRenderedFeatures(
@@ -215,30 +217,26 @@ void GeometryTile::queryRenderedFeatures(
const TransformState& transformState,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) {
+ const mat4& projMatrix) {
if (!getData()) return;
- // Determine the additional radius needed factoring in property functions
- float additionalRadius = 0;
- for (const RenderLayer* layer : layers) {
- auto bucket = getBucket(*layer->baseImpl);
- if (bucket) {
- additionalRadius = std::max(additionalRadius, bucket->getQueryRadius(*layer));
- }
- }
-
- featureIndex->query(result,
- queryGeometry,
- transformState.getAngle(),
- util::tileSize * id.overscaleFactor(),
- std::pow(2, transformState.getZoom() - id.overscaledZ),
- options,
- id.toUnwrapped(),
- sourceID,
- layers,
- collisionIndex,
- additionalRadius);
+ const float queryPadding = getQueryPadding(layers);
+
+ mat4 posMatrix;
+ transformState.matrixFor(posMatrix, id.toUnwrapped());
+ matrix::multiply(posMatrix, projMatrix, posMatrix);
+
+ latestFeatureIndex->query(result,
+ queryGeometry,
+ transformState,
+ posMatrix,
+ util::tileSize * id.overscaleFactor(),
+ std::pow(2, transformState.getZoom() - id.overscaledZ),
+ options,
+ id.toUnwrapped(),
+ layers,
+ queryPadding * transformState.maxPitchScaleFactor());
}
void GeometryTile::querySourceFeatures(
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index 418db4a0b2..af122474c2 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -5,7 +5,6 @@
#include <mbgl/renderer/image_manager.hpp>
#include <mbgl/text/glyph_manager.hpp>
#include <mbgl/util/feature.hpp>
-#include <mbgl/util/throttler.hpp>
#include <mbgl/actor/actor.hpp>
#include <mbgl/geometry/feature_index.hpp>
@@ -55,12 +54,14 @@ public:
const TransformState&,
const std::vector<const RenderLayer*>& layers,
const RenderedQueryOptions& options,
- const CollisionIndex& collisionIndex) override;
+ const mat4& projMatrix) override;
void querySourceFeatures(
std::vector<Feature>& result,
const SourceQueryOptions&) override;
+ float getQueryPadding(const std::vector<const RenderLayer*>&) override;
+
void cancel() override;
class LayoutResult {
@@ -88,11 +89,11 @@ public:
void markRenderedPreviously() override;
void performedFadePlacement() override;
- void commitFeatureIndex() override;
+ const std::shared_ptr<FeatureIndex> getFeatureIndex() const { return latestFeatureIndex; }
protected:
const GeometryTileData* getData() {
- return featureIndex ? featureIndex->getData() : nullptr;
+ return latestFeatureIndex ? latestFeatureIndex->getData() : nullptr;
}
private:
@@ -113,8 +114,7 @@ private:
std::unordered_map<std::string, std::shared_ptr<Bucket>> buckets;
- optional<std::unique_ptr<FeatureIndex>> featureIndexPendingCommit;
- std::unique_ptr<FeatureIndex> featureIndex;
+ std::shared_ptr<FeatureIndex> latestFeatureIndex;
optional<AlphaImage> glyphAtlasImage;
optional<PremultipliedImage> iconAtlasImage;
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index 61bc0cb597..ca20c4b8ab 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -440,8 +440,7 @@ void GeometryTileWorker::performSymbolLayout() {
}
symbolLayout->prepare(glyphMap, glyphAtlas.positions,
- imageMap, imageAtlas.positions,
- id, sourceID);
+ imageMap, imageAtlas.positions);
}
symbolLayoutsNeedPreparation = false;
diff --git a/src/mbgl/tile/tile.cpp b/src/mbgl/tile/tile.cpp
index 88db2ba07c..b95944f10e 100644
--- a/src/mbgl/tile/tile.cpp
+++ b/src/mbgl/tile/tile.cpp
@@ -38,7 +38,11 @@ void Tile::queryRenderedFeatures(
const TransformState&,
const std::vector<const RenderLayer*>&,
const RenderedQueryOptions&,
- const CollisionIndex&) {}
+ const mat4&) {}
+
+float Tile::getQueryPadding(const std::vector<const RenderLayer*>&) {
+ return 0;
+}
void Tile::querySourceFeatures(
std::vector<Feature>&,
diff --git a/src/mbgl/tile/tile.hpp b/src/mbgl/tile/tile.hpp
index 23365c6ae3..23d6864205 100644
--- a/src/mbgl/tile/tile.hpp
+++ b/src/mbgl/tile/tile.hpp
@@ -58,12 +58,14 @@ public:
const TransformState&,
const std::vector<const RenderLayer*>&,
const RenderedQueryOptions& options,
- const CollisionIndex&);
+ const mat4& projMatrix);
virtual void querySourceFeatures(
std::vector<Feature>& result,
const SourceQueryOptions&);
+ virtual float getQueryPadding(const std::vector<const RenderLayer*>&);
+
void setTriedCache();
// Returns true when the tile source has received a first response, regardless of whether a load
@@ -109,11 +111,6 @@ public:
// and will have time to finish by the second placement.
virtual void performedFadePlacement() {}
- // FeatureIndexes are loaded asynchronously, but must be used with a CollisionIndex
- // generated from the same data. Calling commitFeatureIndex signals the current
- // CollisionIndex is up-to-date and allows us to start using the last loaded FeatureIndex
- virtual void commitFeatureIndex() {}
-
void dumpDebugLogs() const;
const OverscaledTileID id;
diff --git a/src/mbgl/util/compression.cpp b/src/mbgl/util/compression.cpp
index 30e813cbb8..ee3ebe7cae 100644
--- a/src/mbgl/util/compression.cpp
+++ b/src/mbgl/util/compression.cpp
@@ -1,6 +1,6 @@
#include <mbgl/util/compression.hpp>
-#if defined(__QT__) && defined(_WINDOWS)
+#if defined(__QT__) && defined(_WINDOWS) && !defined(__GNUC__)
#include <QtZlib/zlib.h>
#else
#include <zlib.h>
diff --git a/src/mbgl/util/i18n.cpp b/src/mbgl/util/i18n.cpp
index 1fc13bfb7d..5530796915 100644
--- a/src/mbgl/util/i18n.cpp
+++ b/src/mbgl/util/i18n.cpp
@@ -1,4 +1,5 @@
-#include "i18n.hpp"
+#include <mbgl/util/i18n.hpp>
+#include <mbgl/util/utf.hpp>
#include <algorithm>
#include <map>
@@ -65,7 +66,7 @@ DEFINE_IS_IN_UNICODE_BLOCK(UnifiedCanadianAboriginalSyllabics, 0x1400, 0x167F)
// DEFINE_IS_IN_UNICODE_BLOCK(Hanunoo, 0x1720, 0x173F)
// DEFINE_IS_IN_UNICODE_BLOCK(Buhid, 0x1740, 0x175F)
// DEFINE_IS_IN_UNICODE_BLOCK(Tagbanwa, 0x1760, 0x177F)
-// DEFINE_IS_IN_UNICODE_BLOCK(Khmer, 0x1780, 0x17FF)
+DEFINE_IS_IN_UNICODE_BLOCK(Khmer, 0x1780, 0x17FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Mongolian, 0x1800, 0x18AF)
DEFINE_IS_IN_UNICODE_BLOCK(UnifiedCanadianAboriginalSyllabicsExtended, 0x18B0, 0x18FF)
// DEFINE_IS_IN_UNICODE_BLOCK(Limbu, 0x1900, 0x194F)
@@ -581,6 +582,38 @@ std::u16string verticalizePunctuation(const std::u16string& input) {
char16_t verticalizePunctuation(char16_t chr) {
return verticalPunctuation.count(chr) ? verticalPunctuation.at(chr) : 0;
}
+
+bool charInSupportedScript(char16_t chr) {
+ // This is a rough heuristic: whether we "can render" a script
+ // actually depends on the properties of the font being used
+ // and whether differences from the ideal rendering are considered
+ // semantically significant.
+
+ // Even in Latin script, we "can't render" combinations such as the fi
+ // ligature, but we don't consider that semantically significant.n false;
+ if ((chr >= 0x0900 && chr <= 0x0DFF) ||
+ // Main blocks for Indic scripts and Sinhala
+ (chr >= 0x0F00 && chr <= 0x109F) ||
+ // Main blocks for Tibetan and Myanmar
+ isInKhmer(chr)) {
+ // These blocks cover common scripts that require
+ // complex text shaping, based on unicode script metadata:
+ // http://www.unicode.org/repos/cldr/trunk/common/properties/scriptMetadata.txt
+ // where "Web Rank <= 32" "Shaping Required = YES"
+ return false;
+ }
+ return true;
+}
+
+bool isStringInSupportedScript(const std::string& input) {
+ auto u16string = util::utf8_to_utf16::convert(input);
+ for (char16_t chr : u16string) {
+ if (!charInSupportedScript(chr)) {
+ return false;
+ }
+ }
+ return true;
+}
} // namespace i18n
} // namespace util
diff --git a/src/mbgl/util/i18n.hpp b/src/mbgl/util/i18n.hpp
index b3960c743c..a74215a134 100644
--- a/src/mbgl/util/i18n.hpp
+++ b/src/mbgl/util/i18n.hpp
@@ -72,6 +72,8 @@ std::u16string verticalizePunctuation(const std::u16string& input);
@return The character’s specialized vertical form; 0 if not applicable. */
char16_t verticalizePunctuation(char16_t chr);
+
+bool isStringInSupportedScript(const std::string& input);
} // namespace i18n
} // namespace util
diff --git a/src/mbgl/util/intersection_tests.cpp b/src/mbgl/util/intersection_tests.cpp
index e6ce245c0e..780fce98f9 100644
--- a/src/mbgl/util/intersection_tests.cpp
+++ b/src/mbgl/util/intersection_tests.cpp
@@ -82,11 +82,16 @@ bool lineIntersectsBufferedLine(const GeometryCoordinates& lineA, const Geometry
return false;
}
+bool polygonIntersectsBufferedPoint(const GeometryCoordinates& polygon, const GeometryCoordinate& point, float radius) {
+ if (polygonContainsPoint(polygon, point)) return true;
+ if (pointIntersectsBufferedLine(point, polygon, radius)) return true;
+ return false;
+}
+
bool polygonIntersectsBufferedMultiPoint(const GeometryCoordinates& polygon, const GeometryCollection& rings, float radius) {
for (auto& ring : rings) {
for (auto& point : ring) {
- if (polygonContainsPoint(polygon, point)) return true;
- if (pointIntersectsBufferedLine(point, polygon, radius)) return true;
+ if (polygonIntersectsBufferedPoint(polygon, point, radius)) return true;
}
}
return false;
diff --git a/src/mbgl/util/intersection_tests.hpp b/src/mbgl/util/intersection_tests.hpp
index 5bcb29c767..c105fe4dd0 100644
--- a/src/mbgl/util/intersection_tests.hpp
+++ b/src/mbgl/util/intersection_tests.hpp
@@ -9,6 +9,7 @@ bool polygonIntersectsBufferedMultiPoint(const GeometryCoordinates&, const Geome
bool polygonIntersectsBufferedMultiLine(const GeometryCoordinates&, const GeometryCollection&, float radius);
bool polygonIntersectsPolygon(const GeometryCoordinates&, const GeometryCoordinates&);
bool polygonIntersectsMultiPolygon(const GeometryCoordinates&, const GeometryCollection&);
+bool polygonIntersectsBufferedPoint(const GeometryCoordinates& polygon, const GeometryCoordinate& point, float radius);
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/throttler.cpp b/src/mbgl/util/throttler.cpp
deleted file mode 100644
index 910810ce2f..0000000000
--- a/src/mbgl/util/throttler.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#include <mbgl/util/throttler.hpp>
-
-namespace mbgl {
-namespace util {
-
-Throttler::Throttler(Duration frequency_, std::function<void()>&& function_)
- : frequency(frequency_)
- , function(std::move(function_))
- , pendingInvocation(false)
- , lastInvocation(TimePoint::min())
-{}
-
-void Throttler::invoke() {
- if (pendingInvocation) {
- return;
- }
-
- Duration timeToNextInvocation = lastInvocation == TimePoint::min()
- ? Duration::zero()
- : (lastInvocation + frequency) - Clock::now();
-
- if (timeToNextInvocation <= Duration::zero()) {
- lastInvocation = Clock::now();
- function();
- } else {
- pendingInvocation = true;
- timer.start(timeToNextInvocation, Duration::zero(), [this]{
- pendingInvocation = false;
- lastInvocation = Clock::now();
- function();
- });
- }
-}
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/throttler.hpp b/src/mbgl/util/throttler.hpp
deleted file mode 100644
index 175de7ccaf..0000000000
--- a/src/mbgl/util/throttler.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <mbgl/util/chrono.hpp>
-#include <mbgl/util/timer.hpp>
-
-namespace mbgl {
-namespace util {
-
-class Throttler {
-public:
- Throttler(Duration frequency, std::function<void()>&& function);
-
- void invoke();
-private:
- Duration frequency;
- std::function<void()> function;
-
- Timer timer;
- bool pendingInvocation;
- TimePoint lastInvocation;
-};
-
-} // namespace util
-} // namespace mbgl
diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp
index 39b562d811..488e6b88ce 100644
--- a/src/mbgl/util/tile_cover.cpp
+++ b/src/mbgl/util/tile_cover.cpp
@@ -2,13 +2,18 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/interpolate.hpp>
#include <mbgl/map/transform_state.hpp>
+#include <mbgl/util/tile_cover_impl.hpp>
+#include <mbgl/util/tile_coordinate.hpp>
#include <functional>
+#include <list>
namespace mbgl {
namespace {
+using ScanLine = const std::function<void(int32_t x0, int32_t x1, int32_t y)>;
+
// Taken from polymaps src/Layer.js
// https://github.com/simplegeo/polymaps/blob/master/src/Layer.js#L333-L383
struct edge {
@@ -27,8 +32,6 @@ struct edge {
}
};
-using ScanLine = const std::function<void(int32_t x0, int32_t x1, int32_t y)>;
-
// scan-line conversion
static void scanSpans(edge e0, edge e1, int32_t ymin, int32_t ymax, ScanLine scanLine) {
double y0 = ::fmax(ymin, std::floor(e1.y0));
@@ -147,11 +150,11 @@ std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, int32_t z) {
{ std::min(bounds_.north(), util::LATITUDE_MAX), bounds_.east() });
return tileCover(
- TileCoordinate::fromLatLng(z, bounds.northwest()).p,
- TileCoordinate::fromLatLng(z, bounds.northeast()).p,
- TileCoordinate::fromLatLng(z, bounds.southeast()).p,
- TileCoordinate::fromLatLng(z, bounds.southwest()).p,
- TileCoordinate::fromLatLng(z, bounds.center()).p,
+ Projection::project(bounds.northwest(), z),
+ Projection::project(bounds.northeast(), z),
+ Projection::project(bounds.southeast(), z),
+ Projection::project(bounds.southwest(), z),
+ Projection::project(bounds.center(), z),
z);
}
@@ -169,25 +172,80 @@ std::vector<UnwrappedTileID> tileCover(const TransformState& state, int32_t z) {
z);
}
+std::vector<UnwrappedTileID> tileCover(const Geometry<double>& geometry, int32_t z) {
+ std::vector<UnwrappedTileID> result;
+ TileCover tc(geometry, z, true);
+ while (tc.hasNext()) {
+ result.push_back(*tc.next());
+ };
+
+ return result;
+}
+
// Taken from https://github.com/mapbox/sphericalmercator#xyzbbox-zoom-tms_style-srs
// Computes the projected tiles for the lower left and upper right points of the bounds
// and uses that to compute the tile cover count
-uint64_t tileCount(const LatLngBounds& bounds, uint8_t zoom, uint16_t tileSize_){
-
- auto sw = Projection::project(bounds.southwest().wrapped(), zoom, tileSize_);
- auto ne = Projection::project(bounds.northeast().wrapped(), zoom, tileSize_);
-
- auto x1 = floor(sw.x/ tileSize_);
- auto x2 = floor((ne.x - 1) / tileSize_);
- auto y1 = floor(sw.y/ tileSize_);
- auto y2 = floor((ne.y - 1) / tileSize_);
-
- auto minX = ::fmax(std::min(x1, x2), 0);
- auto maxX = std::max(x1, x2);
- auto minY = (std::pow(2, zoom) - 1) - std::max(y1, y2);
- auto maxY = (std::pow(2, zoom) - 1) - ::fmax(std::min(y1, y2), 0);
-
- return (maxX - minX + 1) * (maxY - minY + 1);
+uint64_t tileCount(const LatLngBounds& bounds, uint8_t zoom){
+ if (zoom == 0) {
+ return 1;
+ }
+ auto sw = Projection::project(bounds.southwest(), zoom);
+ auto ne = Projection::project(bounds.northeast(), zoom);
+ auto maxTile = std::pow(2.0, zoom);
+ auto x1 = floor(sw.x);
+ auto x2 = ceil(ne.x) - 1;
+ auto y1 = util::clamp(floor(sw.y), 0.0, maxTile - 1);
+ auto y2 = util::clamp(floor(ne.y), 0.0, maxTile - 1);
+
+ auto dx = x1 > x2 ? (maxTile - x1) + x2 : x2 - x1;
+ auto dy = y1 - y2;
+ return (dx + 1) * (dy + 1);
+}
+
+uint64_t tileCount(const Geometry<double>& geometry, uint8_t z) {
+ uint64_t tileCount = 0;
+
+ TileCover tc(geometry, z, true);
+ while (tc.next()) {
+ tileCount++;
+ };
+ return tileCount;
+}
+
+TileCover::TileCover(const LatLngBounds&bounds_, int32_t z) {
+ LatLngBounds bounds = LatLngBounds::hull(
+ { std::max(bounds_.south(), -util::LATITUDE_MAX), bounds_.west() },
+ { std::min(bounds_.north(), util::LATITUDE_MAX), bounds_.east() });
+
+ if (bounds.isEmpty() ||
+ bounds.south() > util::LATITUDE_MAX ||
+ bounds.north() < -util::LATITUDE_MAX) {
+ bounds = LatLngBounds::world();
+ }
+
+ auto sw = Projection::project(bounds.southwest(), z);
+ auto ne = Projection::project(bounds.northeast(), z);
+ auto se = Projection::project(bounds.southeast(), z);
+ auto nw = Projection::project(bounds.northwest(), z);
+
+ Polygon<double> p({ {sw, nw, ne, se, sw} });
+ impl = std::make_unique<TileCover::Impl>(z, p, false);
+}
+
+TileCover::TileCover(const Geometry<double>& geom, int32_t z, bool project/* = true*/)
+ : impl( std::make_unique<TileCover::Impl>(z, geom, project)) {
+}
+
+TileCover::~TileCover() {
+
+}
+
+optional<UnwrappedTileID> TileCover::next() {
+ return impl->next();
+}
+
+bool TileCover::hasNext() {
+ return impl->hasNext();
}
} // namespace util
diff --git a/src/mbgl/util/tile_cover.hpp b/src/mbgl/util/tile_cover.hpp
index b2098b59b8..c953d764d2 100644
--- a/src/mbgl/util/tile_cover.hpp
+++ b/src/mbgl/util/tile_cover.hpp
@@ -2,9 +2,11 @@
#include <mbgl/tile/tile_id.hpp>
#include <mbgl/style/types.hpp>
-#include <mbgl/util/tile_coordinate.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/optional.hpp>
#include <vector>
+#include <memory>
namespace mbgl {
@@ -13,13 +15,31 @@ class LatLngBounds;
namespace util {
+// Helper class to stream tile-cover results per row
+class TileCover {
+public:
+ TileCover(const LatLngBounds&, int32_t z);
+ // When project == true, projects the geometry points to tile coordinates
+ TileCover(const Geometry<double>&, int32_t z, bool project = true);
+ ~TileCover();
+
+ optional<UnwrappedTileID> next();
+ bool hasNext();
+
+private:
+ class Impl;
+ std::unique_ptr<Impl> impl;
+};
+
int32_t coveringZoomLevel(double z, style::SourceType type, uint16_t tileSize);
std::vector<UnwrappedTileID> tileCover(const TransformState&, int32_t z);
std::vector<UnwrappedTileID> tileCover(const LatLngBounds&, int32_t z);
+std::vector<UnwrappedTileID> tileCover(const Geometry<double>&, int32_t z);
// Compute only the count of tiles needed for tileCover
-uint64_t tileCount(const LatLngBounds&, uint8_t z, uint16_t tileSize);
+uint64_t tileCount(const LatLngBounds&, uint8_t z);
+uint64_t tileCount(const Geometry<double>&, uint8_t z);
} // namespace util
} // namespace mbgl
diff --git a/src/mbgl/util/tile_cover_impl.cpp b/src/mbgl/util/tile_cover_impl.cpp
new file mode 100644
index 0000000000..b3fc07f7dd
--- /dev/null
+++ b/src/mbgl/util/tile_cover_impl.cpp
@@ -0,0 +1,365 @@
+#include <mbgl/util/tile_cover_impl.hpp>
+#include <mbgl/util/tile_coordinate.hpp>
+
+#include <functional>
+#include <cmath>
+#include <assert.h>
+#include <limits.h>
+#include <algorithm>
+
+namespace mbgl {
+namespace util {
+
+using PointList = std::vector<Point<double>>;
+
+struct TileSpan {
+ int32_t xmin, xmax;
+ bool winding;
+};
+
+
+// Find the first local minimum going forward in the list.
+void start_list_on_local_minimum(PointList& points) {
+ auto prev_pt = std::prev(points.end(), 2);
+ auto pt = points.begin();
+ auto next_pt = std::next(pt);
+ while (pt != points.end()) {
+ if ((pt->y <= prev_pt->y) &&
+ (pt->y < next_pt->y)) {
+ break;
+ }
+ prev_pt = pt;
+ pt++;
+ next_pt++;
+ if (next_pt == points.end()) { next_pt = std::next(points.begin()); }
+ }
+ //Re-close linear rings with first_pt = last_pt
+ if (points.back() == points.front()) {
+ points.pop_back();
+ }
+ std::rotate(points.begin(), pt, points.end());
+ points.push_back(*points.begin());
+}
+
+//Create a bound towards a local maximum point, starting from pt.
+Bound create_bound_towards_maximum(PointList& points, PointList::iterator& pt) {
+ if (std::distance(pt, points.end()) < 2) { return {}; }
+ if (std::distance(pt, points.end()) == 2) {
+ Bound bnd;
+ if (pt->y < std::next(pt)->y) {
+ std::copy(pt, points.end(), std::back_inserter(bnd.points));
+ bnd.winding = true;
+ }
+ else {
+ std::reverse_copy(pt, points.end(), std::back_inserter(bnd.points));
+ bnd.winding = false;
+ }
+ pt = points.end();
+ return bnd;
+ }
+ const auto begin = pt;
+ auto prev_pt = pt == points.begin() ? std::prev(points.end(), 2) : std::prev(pt);
+ auto next_pt = std::next(pt) == points.end() ? std::next(points.begin()) : std::next(pt);
+ while (pt != points.end()) {
+ if ((pt->y >= prev_pt->y) &&
+ (pt->y > next_pt->y )) {
+ break;
+ }
+ prev_pt = pt;
+ pt++;
+ next_pt++;
+ if (next_pt == points.end()) { next_pt = std::next(points.begin()); }
+ }
+
+ Bound bnd;
+ if (std::next(pt) == points.end()) { next_pt = points.end(); pt++; };
+ bnd.points.reserve(static_cast<std::size_t>(std::distance(begin, next_pt)));
+ std::copy(begin, next_pt, std::back_inserter(bnd.points));
+ bnd.winding = true;
+ return bnd;
+}
+
+//Create a bound towards a local minimum point, starting from pt.
+Bound create_bound_towards_minimum(PointList& points, PointList::iterator& pt) {
+ if (std::distance(pt, points.end()) < 2) { return {}; }
+ if (std::distance(pt, points.end()) == 2) {
+ Bound bnd;
+ if (pt->y < std::next(pt)->y) {
+ std::copy(pt, points.end(), std::back_inserter(bnd.points));
+ bnd.winding = true;
+ }
+ else {
+ std::reverse_copy(pt, points.end(), std::back_inserter(bnd.points));
+ bnd.winding = false;
+ }
+ pt = points.end();
+ return bnd;
+ }
+ auto begin = pt;
+ auto prev_pt = pt == points.begin() ? std::prev(points.end(), 2) : std::prev(pt);
+ auto next_pt = std::next(pt) == points.end() ? std::next(points.begin()) : std::next(pt);
+ while (pt != points.end()) {
+ if ((pt->y <= prev_pt->y) &&
+ (pt->y < next_pt->y)) {
+ break;
+ }
+ prev_pt = pt;
+ pt++;
+ next_pt++;
+ if (next_pt == points.end()) { next_pt = std::next(points.begin()); }
+ }
+
+ Bound bnd;
+ if (std::next(pt) == points.end()) { next_pt = points.end(); pt++; };
+ bnd.points.reserve(static_cast<std::size_t>(std::distance(begin, next_pt)));
+ //For bounds that start at a max, reverse copy so that all bounds start at a min
+ std::reverse_copy(begin, next_pt, std::back_inserter(bnd.points));
+ bnd.winding = false;
+ return bnd;
+}
+
+//Build a map of bounds and their starting Y tile coordinate.
+void build_bounds_map(PointList& points, uint32_t maxTile, BoundsMap& et, bool closed = false) {
+ if (points.size() < 2) return;
+ //While traversing closed rings, start the bounds at a local minimum
+ if (closed) {
+ start_list_on_local_minimum(points);
+ }
+
+ auto pointsIter = points.begin();
+ while (pointsIter != points.end()) {
+ Bound to_max = create_bound_towards_maximum(points, pointsIter);
+ Bound to_min = create_bound_towards_minimum(points, pointsIter);
+
+ if (to_max.points.size() > 0) {
+ // Projections may result in values beyond the bounds, clamp to max tile coordinates
+ const auto y = static_cast<uint32_t>(std::floor(clamp(to_max.points.front().y, 0.0, (double)maxTile)));
+ et[y].push_back(to_max);
+ }
+ if (to_min.points.size() > 0) {
+ const auto y = static_cast<uint32_t>(std::floor(clamp(to_min.points.front().y, 0.0, (double)maxTile)));
+ et[y].push_back(to_min);
+ }
+ }
+ assert(pointsIter == points.end());
+}
+
+void update_span(TileSpan& xp, double x) {
+ xp.xmin = std::min(xp.xmin, static_cast<int32_t>(std::floor(x)));
+ xp.xmax = std::max(xp.xmax, static_cast<int32_t>(std::ceil(x)));
+}
+
+//Build a vector of X tile-coordinates spanned by each bound.
+std::vector<TileSpan> scan_row(uint32_t y, Bounds& aet) {
+ std::vector<TileSpan> tile_range;
+ tile_range.reserve(aet.size());
+
+ for(Bound& b: aet) {
+ TileSpan xp = { INT_MAX, 0, b.winding };
+ double x;
+ const auto numEdges = b.points.size() - 1;
+ assert(numEdges >= 1);
+ while (b.currentPoint < numEdges) {
+ x = b.interpolate(y);
+ update_span(xp, x);
+
+ // If this edge ends beyond the current row, find the x-intercept where
+ // it exits the row
+ auto& p1 = b.points[b.currentPoint + 1];
+ if (p1.y > y+1) {
+ x = b.interpolate(y+1);
+ update_span(xp, x);
+ break;
+ } else if(b.currentPoint == numEdges - 1) {
+ // For last edge, consider x-intercept at the end of the edge.
+ x = p1.x;
+ update_span(xp, x);
+ }
+ b.currentPoint++;
+ }
+ tile_range.push_back(xp);
+ }
+ // Erase bounds in the active table whose current edge ends inside this row,
+ // or there are no more edges
+ auto bound = aet.begin();
+ while (bound != aet.end()) {
+ if ( bound->currentPoint == bound->points.size() - 1 &&
+ bound->points[bound->currentPoint].y <= y+1) {
+ bound = aet.erase(bound);
+ } else {
+ bound++;
+ }
+ }
+ // Sort the X-extents of each crossing bound by x_min, x_max
+ std::sort(tile_range.begin(), tile_range.end(), [] (TileSpan& a, TileSpan& b) {
+ return std::tie(a.xmin, a.xmax) < std::tie(b.xmin, b.xmax);
+ });
+
+ return tile_range;
+}
+
+struct BuildBoundsMap {
+ int32_t zoom;
+ bool project = false;
+ BuildBoundsMap(int32_t z, bool p): zoom(z), project(p) {}
+
+ void buildTable(const std::vector<Point<double>>& points, BoundsMap& et, bool closed = false) const {
+ PointList projectedPoints;
+ if (project) {
+ projectedPoints.reserve(points.size());
+ for(const auto&p : points) {
+ projectedPoints.push_back(
+ Projection::project(LatLng{ p.y, p.x }, zoom));
+ }
+ } else {
+ projectedPoints.insert(projectedPoints.end(), points.begin(), points.end());
+ }
+ build_bounds_map(projectedPoints, 1 << zoom, et, closed);
+ }
+
+ void buildPolygonTable(const Polygon<double>& polygon, BoundsMap& et) const {
+ for(const auto&ring : polygon) {
+ buildTable(ring, et, true);
+ }
+ }
+ BoundsMap operator()(const Point<double>&p) const {
+ Bound bnd;
+ auto point = p;
+ if(project) {
+ point = Projection::project(LatLng{p.y, p.x}, zoom);
+ }
+ bnd.points.insert(bnd.points.end(), 2, point);
+ bnd.winding = false;
+ BoundsMap et;
+ const auto y = static_cast<uint32_t>(std::floor(clamp(point.y, 0.0, (double)(1 << zoom))));
+ et[y].push_back(bnd);
+ return et;
+ }
+
+ BoundsMap operator()(const MultiPoint<double>& points) const {
+ BoundsMap et;
+ for (const Point<double>& p: points) {
+ Bound bnd;
+ auto point = p;
+ if(project) {
+ point = Projection::project(LatLng{p.y, p.x}, zoom);
+ }
+ bnd.points.insert(bnd.points.end(), 2, point);
+ bnd.winding = false;
+ const auto y = static_cast<uint32_t>(std::floor(clamp(point.y, 0.0, (double)(1 << zoom))));
+ et[y].push_back(bnd);
+ }
+ return et;
+ }
+
+ BoundsMap operator()(const LineString<double>& lines) const {
+ BoundsMap et;
+ buildTable(lines, et);
+ return et;
+ }
+
+ BoundsMap operator()(const MultiLineString<double>& lines) const {
+ BoundsMap et;
+ for(const auto&line : lines) {
+ buildTable(line, et);
+ }
+ return et;
+ }
+
+ BoundsMap operator()(const Polygon<double>& polygon) const {
+ BoundsMap et;
+ buildPolygonTable(polygon, et);
+ return et;
+ }
+
+ BoundsMap operator()(const MultiPolygon<double>& polygons) const {
+ BoundsMap et;
+ for(const auto& polygon: polygons) {
+ buildPolygonTable(polygon, et);
+ }
+ return et;
+ }
+
+ BoundsMap operator()(const mapbox::geometry::geometry_collection<double>&) const {
+ return {};
+ }
+};
+
+TileCover::Impl::Impl(int32_t z, const Geometry<double>& geom, bool project)
+ : zoom(z) {
+ ToFeatureType toFeatureType;
+ isClosed = apply_visitor(toFeatureType, geom) == FeatureType::Polygon;
+
+ BuildBoundsMap toBoundsMap(z, project);
+ boundsMap = apply_visitor(toBoundsMap, geom);
+ if (boundsMap.size() == 0) return;
+
+ //Iniitalize the active edge table, and current row span
+ currentBounds = boundsMap.begin();
+ tileY = 0;
+ nextRow();
+ if (tileXSpans.empty()) return;
+ tileX = tileXSpans.front().first;
+}
+
+void TileCover::Impl::nextRow() {
+ // Update AET for next row
+ if (currentBounds != boundsMap.end()) {
+ if (activeBounds.size() == 0 && currentBounds->first > tileY) {
+ //For multi-geoms: use the next row with an edge table starting point
+ tileY = currentBounds->first;
+ }
+ if (tileY == currentBounds->first) {
+
+ std::move(currentBounds->second.begin(), currentBounds->second.end(), std::back_inserter(activeBounds));
+ currentBounds++;
+ }
+ }
+ //Scan aet and update currenRange with x_min, x_max pairs
+ auto xps = util::scan_row(tileY, activeBounds);
+ if (xps.size() == 0) {
+ return;
+ }
+
+ auto x_min = xps[0].xmin;
+ auto x_max = xps[0].xmax;
+ int32_t nzRule = xps[0].winding ? 1 : -1;
+ for (size_t i = 1; i < xps.size(); i++) {
+ auto xp = xps[i];
+ if (!(isClosed && nzRule != 0)) {
+ if (xp.xmin > x_max && xp.xmax >= x_max) {
+ tileXSpans.emplace(x_min, x_max);
+ x_min = xp.xmin;
+ }
+ }
+ nzRule += xp.winding ? 1 : -1;
+ x_max = std::max(x_min, xp.xmax);
+ }
+ tileXSpans.emplace(x_min, x_max);
+}
+
+bool TileCover::Impl::hasNext() const {
+ return (!tileXSpans.empty() && tileX < tileXSpans.front().second && tileY < (1u << zoom));
+}
+
+optional<UnwrappedTileID> TileCover::Impl::next() {
+ if (!hasNext()) return {};
+
+ const auto x = tileX;
+ const auto y = tileY;
+ tileX++;
+ if (tileX >= tileXSpans.front().second) {
+ tileXSpans.pop();
+ if(tileXSpans.empty()) {
+ tileY++;
+ nextRow();
+ }
+ if (!tileXSpans.empty()) {
+ tileX = tileXSpans.front().first;
+ }
+ }
+ return UnwrappedTileID(zoom, x, y);
+}
+
+} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/tile_cover_impl.hpp b/src/mbgl/util/tile_cover_impl.hpp
new file mode 100644
index 0000000000..7c16718984
--- /dev/null
+++ b/src/mbgl/util/tile_cover_impl.hpp
@@ -0,0 +1,90 @@
+#pragma once
+
+#include <mbgl/util/tile_cover.hpp>
+#include <mbgl/util/geometry.hpp>
+#include <mbgl/util/optional.hpp>
+
+#include <vector>
+#include <map>
+#include <queue>
+
+namespace mbgl {
+
+class TransformState;
+class LatLngBounds;
+
+namespace util {
+
+struct Bound;
+
+using Bounds = std::vector<Bound>;
+using BoundsMap = std::map<uint32_t, Bounds>;
+
+// A chain of points from a local minimum to a local maximum. `winding` indicates
+// the direction of the original geometry.
+struct Bound {
+ std::vector<Point<double>> points;
+ size_t currentPoint = 0;
+ bool winding = false;
+
+ Bound() = default;
+ Bound(const Bound& rhs) {
+ points = rhs.points;
+ currentPoint = rhs.currentPoint;
+ winding = rhs.winding;
+ }
+ Bound& operator=(Bound&& rhs) {
+ points = std::move(rhs.points);
+ currentPoint = rhs.currentPoint;
+ winding = rhs.winding;
+ return *this;
+ }
+
+ // Compute the interpolated x coordinate at y for the current edge
+ double interpolate(uint32_t y) {
+ const auto& p0 = points[currentPoint];
+ const auto& p1 = points[currentPoint + 1];
+
+ const auto dx = p1.x - p0.x;
+ const auto dy = p1.y - p0.y;
+ auto x = p0.x;
+ if (dx == 0) {
+ return x;
+ } else if (dy == 0){
+ return y <= p0.y ? p0.x : p1.x;
+ }
+ if (y < p0.y) return x;
+ if (y > p1.y) return p1.x;
+ x = (dx / dy) * (y - p0.y) + p0.x;
+ return x;
+ }
+};
+
+class TileCover::Impl {
+public:
+ Impl(int32_t z, const Geometry<double>& geom, bool project = true);
+ ~Impl() = default;
+
+ optional<UnwrappedTileID> next();
+ bool hasNext() const;
+
+private:
+ using TileSpans = std::queue<std::pair<int32_t, int32_t>>;
+
+ void nextRow();
+
+ const int32_t zoom;
+ bool isClosed;
+
+ BoundsMap boundsMap;
+ BoundsMap::iterator currentBounds;
+ // List of bounds that begin at or before `tileY`
+ Bounds activeBounds;
+
+ TileSpans tileXSpans;
+ uint32_t tileY;
+ int32_t tileX;
+};
+
+} // namespace util
+} // namespace mbgl
diff --git a/src/mbgl/util/tiny_sdf.cpp b/src/mbgl/util/tiny_sdf.cpp
index 60839357d5..6edcd83bc2 100644
--- a/src/mbgl/util/tiny_sdf.cpp
+++ b/src/mbgl/util/tiny_sdf.cpp
@@ -95,7 +95,7 @@ AlphaImage transformRasterToSDF(const AlphaImage& rasterInput, double radius, do
for (uint32_t i = 0; i < size; i++) {
double distance = gridOuter[i] - gridInner[i];
- sdf.data[i] = std::max(0l, std::min(255l, std::lround(255.0 - 255.0 * (distance / radius + cutoff))));
+ sdf.data[i] = std::max(0l, std::min(255l, ::lround(255.0 - 255.0 * (distance / radius + cutoff))));
}
return sdf;
diff --git a/test/fixtures/offline_database/satellite_test.db b/test/fixtures/offline_database/satellite_test.db
new file mode 100644
index 0000000000..95dd8617ff
--- /dev/null
+++ b/test/fixtures/offline_database/satellite_test.db
Binary files differ
diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp
index 8393fd130d..9b28b2e01a 100644
--- a/test/gl/bucket.test.cpp
+++ b/test/gl/bucket.test.cpp
@@ -110,10 +110,11 @@ TEST(Buckets, SymbolBucket) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
+ std::string bucketLeaderID = "test";
std::vector<SymbolInstance> symbolInstances;
gl::Context context;
- SymbolBucket bucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(symbolInstances) };
+ SymbolBucket bucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances) };
ASSERT_FALSE(bucket.hasIconData());
ASSERT_FALSE(bucket.hasTextData());
ASSERT_FALSE(bucket.hasCollisionBoxData());
diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp
index 94daf59c02..656231eebe 100644
--- a/test/storage/offline_database.test.cpp
+++ b/test/storage/offline_database.test.cpp
@@ -38,6 +38,10 @@ void writeFile(const char* name, const std::string& data) {
mbgl::util::write_file(name, data);
}
+void copyFile(const char* orig, const char* dest) {
+ mbgl::util::write_file(dest, mbgl::util::read_file(orig));
+}
+
} // namespace
TEST(OfflineDatabase, TEST_REQUIRES_WRITE(Create)) {
@@ -62,7 +66,7 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(SchemaVersion)) {
std::string path("test/fixtures/offline_database/offline.db");
{
- mapbox::sqlite::Database db(path, mapbox::sqlite::Create | mapbox::sqlite::ReadWrite);
+ mapbox::sqlite::Database db = mapbox::sqlite::Database::open(path, mapbox::sqlite::Create | mapbox::sqlite::ReadWrite);
db.exec("PRAGMA user_version = 1");
}
@@ -143,6 +147,36 @@ TEST(OfflineDatabase, PutResource) {
EXPECT_EQ("second", *updateGetResult->data);
}
+TEST(OfflineDatabase, TEST_REQUIRES_WRITE(GetResourceFromOfflineRegion)) {
+ using namespace mbgl;
+
+ createDir("test/fixtures/offline_database");
+ deleteFile("test/fixtures/offline_database/satellite.db");
+ copyFile("test/fixtures/offline_database/satellite_test.db", "test/fixtures/offline_database/satellite.db");
+
+ OfflineDatabase db("test/fixtures/offline_database/satellite.db", mapbox::sqlite::ReadOnly);
+
+ Resource resource = Resource::style("mapbox://styles/mapbox/satellite-v9");
+ ASSERT_TRUE(db.get(resource));
+}
+
+TEST(OfflineDatabase, PutAndGetResource) {
+ using namespace mbgl;
+
+ OfflineDatabase db(":memory:");
+
+ Response response1;
+ response1.data = std::make_shared<std::string>("foobar");
+
+ Resource resource = Resource::style("mapbox://example.com/style");
+
+ db.put(resource, response1);
+
+ auto response2 = db.get(resource);
+
+ ASSERT_EQ(*response1.data, *(*response2).data);
+}
+
TEST(OfflineDatabase, PutTile) {
using namespace mbgl;
@@ -565,40 +599,45 @@ TEST(OfflineDatabase, OfflineMapboxTileCount) {
}
static int databasePageCount(const std::string& path) {
- mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly);
- mapbox::sqlite::Statement stmt = db.prepare("pragma page_count");
- stmt.run();
- return stmt.get<int>(0);
+ 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<int>(0);
}
static int databaseUserVersion(const std::string& path) {
- mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly);
- mapbox::sqlite::Statement stmt = db.prepare("pragma user_version");
- stmt.run();
- return stmt.get<int>(0);
+ 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<int>(0);
}
static std::string databaseJournalMode(const std::string& path) {
- mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly);
- mapbox::sqlite::Statement stmt = db.prepare("pragma journal_mode");
- stmt.run();
- return stmt.get<std::string>(0);
+ 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<std::string>(0);
}
static int databaseSyncMode(const std::string& path) {
- mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly);
- mapbox::sqlite::Statement stmt = db.prepare("pragma synchronous");
- stmt.run();
- return stmt.get<int>(0);
+ 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<int>(0);
}
static std::vector<std::string> databaseTableColumns(const std::string& path, const std::string& name) {
- mapbox::sqlite::Database db(path, mapbox::sqlite::ReadOnly);
+ 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.prepare(sql.c_str());
+ mapbox::sqlite::Statement stmt{ db, sql.c_str() };
+ mapbox::sqlite::Query query{ stmt };
std::vector<std::string> columns;
- while (stmt.run()) {
- columns.push_back(stmt.get<std::string>(1));
+ while (query.run()) {
+ columns.push_back(query.get<std::string>(1));
}
return columns;
}
diff --git a/test/storage/sqlite.test.cpp b/test/storage/sqlite.test.cpp
index 36715a2fd0..553736a0b1 100644
--- a/test/storage/sqlite.test.cpp
+++ b/test/storage/sqlite.test.cpp
@@ -6,33 +6,32 @@
TEST(SQLite, Statement) {
using namespace mbgl;
- mapbox::sqlite::Database db(":memory:", mapbox::sqlite::Create | mapbox::sqlite::ReadWrite);
+ mapbox::sqlite::Database db = mapbox::sqlite::Database::open(":memory:", mapbox::sqlite::Create | mapbox::sqlite::ReadWrite);
db.exec("CREATE TABLE test (id INTEGER);");
- mapbox::sqlite::Statement stmt1 = db.prepare("INSERT INTO test (id) VALUES (?1);");
- ASSERT_EQ(stmt1.lastInsertRowId(), 0);
- ASSERT_EQ(stmt1.changes(), 0u);
- stmt1.bind(1, 10);
- stmt1.run();
- ASSERT_EQ(stmt1.lastInsertRowId(), 1);
- ASSERT_EQ(stmt1.changes(), 1u);
+ mapbox::sqlite::Statement stmt1{ db, "INSERT INTO test (id) VALUES (?1);" };
+ mapbox::sqlite::Query query1{ stmt1 };
+ ASSERT_EQ(query1.lastInsertRowId(), 0);
+ ASSERT_EQ(query1.changes(), 0u);
+ query1.bind(1, 10);
+ query1.run();
+ ASSERT_EQ(query1.lastInsertRowId(), 1);
+ ASSERT_EQ(query1.changes(), 1u);
- mapbox::sqlite::Statement stmt2 = db.prepare("INSERT INTO test (id) VALUES (?1);");
- ASSERT_EQ(stmt2.lastInsertRowId(), 0);
- ASSERT_EQ(stmt2.changes(), 0u);
- stmt2.bind(1, 20);
- stmt2.run();
- ASSERT_EQ(stmt2.lastInsertRowId(), 2);
- ASSERT_EQ(stmt2.changes(), 1u);
+ mapbox::sqlite::Statement stmt2{ db, "INSERT INTO test (id) VALUES (?1);" };
+ mapbox::sqlite::Query query2{ stmt2 };
+ ASSERT_EQ(query2.lastInsertRowId(), 0);
+ ASSERT_EQ(query2.changes(), 0u);
+ query2.bind(1, 20);
+ query2.run();
+ ASSERT_EQ(query2.lastInsertRowId(), 2);
+ ASSERT_EQ(query2.changes(), 1u);
}
-TEST(SQLite, TEST_REQUIRES_WRITE(CantOpenException)) {
- try {
- // Should throw a CANTOPEN when the database doesn't exist,
- // make sure all the backends behave the same way.
- mapbox::sqlite::Database("test/fixtures/offline_database/foobar123.db", mapbox::sqlite::ReadOnly);
- FAIL();
- } catch (mapbox::sqlite::Exception& ex) {
- ASSERT_EQ(ex.code, mapbox::sqlite::Exception::Code::CANTOPEN);
- }
+TEST(SQLite, TEST_REQUIRES_WRITE(TryOpen)) {
+ // Should return a CANTOPEN exception when the database doesn't exist,
+ // make sure all the backends behave the same way.
+ auto result = mapbox::sqlite::Database::tryOpen("test/fixtures/offline_database/foobar123.db", mapbox::sqlite::ReadOnly);
+ ASSERT_TRUE(result.is<mapbox::sqlite::Exception>());
+ ASSERT_EQ(result.get<mapbox::sqlite::Exception>().code, mapbox::sqlite::ResultCode::CantOpen);
}
diff --git a/test/style/expression/expression.test.cpp b/test/style/expression/expression.test.cpp
index fe5c261be1..709624a50f 100644
--- a/test/style/expression/expression.test.cpp
+++ b/test/style/expression/expression.test.cpp
@@ -24,11 +24,15 @@ TEST(Expression, IsExpression) {
spec["expression_name"].IsObject() &&
spec["expression_name"].HasMember("values") &&
spec["expression_name"]["values"].IsObject());
-
+
const auto& allExpressions = spec["expression_name"]["values"];
-
+
for(auto& entry : allExpressions.GetObject()) {
const std::string name { entry.name.GetString(), entry.name.GetStringLength() };
+ if (name == "collator" || name == "line-progress" || name == "resolved-locale" || name == "feature-state") {
+ // Not yet implemented
+ continue;
+ }
JSDocument document;
document.Parse<0>(R"([")" + name + R"("])");
diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp
index 794c2b59a1..5d255a6105 100644
--- a/test/text/cross_tile_symbol_index.test.cpp
+++ b/test/text/cross_tile_symbol_index.test.cpp
@@ -25,12 +25,13 @@ TEST(CrossTileSymbolLayerIndex, addBucket) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
+ std::string bucketLeaderID = "test";
OverscaledTileID mainID(6, 0, 6, 8, 8);
std::vector<SymbolInstance> mainInstances;
mainInstances.push_back(makeSymbolInstance(1000, 1000, u"Detroit"));
mainInstances.push_back(makeSymbolInstance(2000, 2000, u"Toronto"));
- SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(mainInstances) };
+ SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) };
mainBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(mainID, mainBucket, maxCrossTileID);
@@ -45,7 +46,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) {
childInstances.push_back(makeSymbolInstance(2000, 2000, u"Windsor"));
childInstances.push_back(makeSymbolInstance(3000, 3000, u"Toronto"));
childInstances.push_back(makeSymbolInstance(4001, 4001, u"Toronto"));
- SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(childInstances) };
+ SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) };
childBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(childID, childBucket, maxCrossTileID);
@@ -61,7 +62,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) {
OverscaledTileID parentID(5, 0, 5, 4, 4);
std::vector<SymbolInstance> parentInstances;
parentInstances.push_back(makeSymbolInstance(500, 500, u"Detroit"));
- SymbolBucket parentBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(parentInstances) };
+ SymbolBucket parentBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(parentInstances) };
parentBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(parentID, parentBucket, maxCrossTileID);
@@ -77,7 +78,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) {
std::vector<SymbolInstance> grandchildInstances;
grandchildInstances.push_back(makeSymbolInstance(4000, 4000, u"Detroit"));
grandchildInstances.push_back(makeSymbolInstance(4000, 4000, u"Windsor"));
- SymbolBucket grandchildBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(grandchildInstances) };
+ SymbolBucket grandchildBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(grandchildInstances) };
grandchildBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(grandchildID, grandchildBucket, maxCrossTileID);
@@ -98,17 +99,18 @@ TEST(CrossTileSymbolLayerIndex, resetIDs) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
+ std::string bucketLeaderID = "test";
OverscaledTileID mainID(6, 0, 6, 8, 8);
std::vector<SymbolInstance> mainInstances;
mainInstances.push_back(makeSymbolInstance(1000, 1000, u"Detroit"));
- SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(mainInstances) };
+ SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) };
mainBucket.bucketInstanceId = ++maxBucketInstanceId;
OverscaledTileID childID(7, 0, 7, 16, 16);
std::vector<SymbolInstance> childInstances;
childInstances.push_back(makeSymbolInstance(2000, 2000, u"Detroit"));
- SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(childInstances) };
+ SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) };
childBucket.bucketInstanceId = ++maxBucketInstanceId;
// assigns a new id
@@ -137,12 +139,13 @@ TEST(CrossTileSymbolLayerIndex, noDuplicatesWithinZoomLevel) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
+ std::string bucketLeaderID = "test";
OverscaledTileID mainID(6, 0, 6, 8, 8);
std::vector<SymbolInstance> mainInstances;
mainInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A
mainInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B
- SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(mainInstances) };
+ SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances) };
mainBucket.bucketInstanceId = ++maxBucketInstanceId;
OverscaledTileID childID(7, 0, 7, 16, 16);
@@ -150,7 +153,7 @@ TEST(CrossTileSymbolLayerIndex, noDuplicatesWithinZoomLevel) {
childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // A'
childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // B'
childInstances.push_back(makeSymbolInstance(2000, 2000, u"")); // C'
- SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(childInstances) };
+ SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances) };
childBucket.bucketInstanceId = ++maxBucketInstanceId;
// assigns new ids
@@ -174,19 +177,20 @@ TEST(CrossTileSymbolLayerIndex, bucketReplacement) {
bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
+ std::string bucketLeaderID = "test";
OverscaledTileID tileID(6, 0, 6, 8, 8);
std::vector<SymbolInstance> firstInstances;
firstInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A
firstInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B
- SymbolBucket firstBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(firstInstances) };
+ SymbolBucket firstBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(firstInstances) };
firstBucket.bucketInstanceId = ++maxBucketInstanceId;
std::vector<SymbolInstance> secondInstances;
secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // A'
secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // B'
secondInstances.push_back(makeSymbolInstance(1000, 1000, u"")); // C'
- SymbolBucket secondBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, std::move(secondInstances) };
+ SymbolBucket secondBucket { layout, {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(secondInstances) };
secondBucket.bucketInstanceId = ++maxBucketInstanceId;
// assigns new ids
diff --git a/test/util/tile_cover.test.cpp b/test/util/tile_cover.test.cpp
index 933c18b5ea..7defa761af 100644
--- a/test/util/tile_cover.test.cpp
+++ b/test/util/tile_cover.test.cpp
@@ -2,6 +2,8 @@
#include <mbgl/util/geo.hpp>
#include <mbgl/map/transform.hpp>
+#include <algorithm>
+
#include <gtest/gtest.h>
using namespace mbgl;
@@ -22,8 +24,8 @@ TEST(TileCover, Antarctic) {
TEST(TileCover, WorldZ0) {
EXPECT_EQ((std::vector<UnwrappedTileID>{
- { 0, 0, 0 },
- }),
+ { 0, 0, 0 },
+ }),
util::tileCover(LatLngBounds::world(), 0));
}
@@ -37,15 +39,15 @@ TEST(TileCover, Pitch) {
transform.setPitch(40.0 * M_PI / 180.0);
EXPECT_EQ((std::vector<UnwrappedTileID>{
- { 2, 1, 2 }, { 2, 1, 1 }, { 2, 2, 2 }, { 2, 2, 1 }, { 2, 3, 2 }
- }),
+ { 2, 1, 2 }, { 2, 1, 1 }, { 2, 2, 2 }, { 2, 2, 1 }, { 2, 3, 2 }
+ }),
util::tileCover(transform.getState(), 2));
}
TEST(TileCover, WorldZ1) {
EXPECT_EQ((std::vector<UnwrappedTileID>{
- { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 },
- }),
+ { 1, 0, 0 }, { 1, 0, 1 }, { 1, 1, 0 }, { 1, 1, 1 },
+ }),
util::tileCover(LatLngBounds::world(), 1));
}
@@ -59,21 +61,44 @@ TEST(TileCover, SingletonZ1) {
util::tileCover(LatLngBounds::singleton({ 0, 0 }), 1));
}
+TEST(TileCoverStream, Arctic) {
+ auto bounds = LatLngBounds::hull({ 84, -180 }, { 70, 180 });
+ auto zoom = 3;
+ util::TileCover tc(bounds, zoom);
+ auto results = util::tileCover(bounds, zoom);
+ std::vector<UnwrappedTileID> t;
+ while(tc.hasNext()) {
+ t.push_back(*tc.next());
+ };
+ EXPECT_EQ(t.size(), results.size());
+}
+
+TEST(TileCoverStream, WorldZ1) {
+ auto zoom = 1;
+ util::TileCover tc(LatLngBounds::world(), zoom);
+ std::vector<UnwrappedTileID> t;
+ while(tc.hasNext()) {
+ t.push_back(*tc.next());
+ };
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ { 1, 0, 0 }, { 1, 1, 0 }, { 1, 0, 1 }, { 1, 1, 1 },
+ }), t);
+}
+
static const LatLngBounds sanFrancisco =
LatLngBounds::hull({ 37.6609, -122.5744 }, { 37.8271, -122.3204 });
TEST(TileCover, SanFranciscoZ0) {
EXPECT_EQ((std::vector<UnwrappedTileID>{
- { 0, 0, 0 },
- }),
+ { 0, 0, 0 },
+ }),
util::tileCover(sanFrancisco, 0));
}
TEST(TileCover, SanFranciscoZ10) {
EXPECT_EQ((std::vector<UnwrappedTileID>{
- { 10, 163, 395 }, { 10, 163, 396 }, { 10, 164, 395 }, { 10, 164, 396 },
-
- }),
+ { 10, 163, 395 }, { 10, 163, 396 }, { 10, 164, 395 }, { 10, 164, 396 },
+ }),
util::tileCover(sanFrancisco, 10));
}
@@ -85,11 +110,192 @@ TEST(TileCover, SanFranciscoZ0Wrapped) {
util::tileCover(sanFranciscoWrapped, 0));
}
+TEST(TileCover, GeomPoint) {
+ auto point = Point<double>{ -122.5744, 37.6609 };
+
+ EXPECT_EQ((std::vector<UnwrappedTileID>{ {2 ,0 ,1 } }),
+ util::tileCover(point, 2));
+}
+
+TEST(TileCover, GeomMultiPoint) {
+ auto points = MultiPoint<double>{ { -122.5, 37.76 }, { -122.4, 37.76} };
+
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ {20, 167480, 405351}, {20, 167772, 405351} }),
+ util::tileCover(points, 20));
+}
+
+TEST(TileCover, GeomLineZ10) {
+ auto lineCover = util::tileCover(LineString<double>{
+ {-121.49368286132812,38.57903714667459},
+ {-122.4422836303711,37.773157169570695}
+ }, 10);
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ { 10, 166, 392}, {10, 165, 393}, {10, 166, 393},
+ {10, 164, 394}, {10, 165, 394}, {10,163,395}, {10, 164, 395}
+ }),lineCover);
+
+}
+
+TEST(TileCover, WrappedGeomLineZ10) {
+ auto lineCover = util::tileCover(LineString<double>{
+ {-179.93342914581299,38.892101707724315},
+ {-180.02394485473633,38.89203490311832}
+ }, 10);
+ EXPECT_EQ((std::vector<UnwrappedTileID>{ { 10, -1, 391 }, { 10, 0, 391 } }),
+ lineCover);
+
+ lineCover = util::tileCover(LineString<double>{
+ {179.93342914581299,38.892101707724315},
+ {180.02394485473633,38.89203490311832}
+ }, 10);
+ EXPECT_EQ((std::vector<UnwrappedTileID>{ { 10, 1023, 391 }, { 10, 1024, 391 } }),
+ lineCover);
+}
+
+TEST(TileCover, GeomMultiLineString) {
+ auto geom = MultiLineString<double>{
+ { { -122.5, 37.76 }, { -122.4, 37.76} },
+ { { -122.5, 37.72 }, { -122.4, 37.72} } };
+
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ {14, 2616, 6333}, {14, 2617, 6333}, {14, 2618, 6333},
+ {14, 2619, 6333}, {14, 2620, 6333}, {14, 2621, 6333},
+ {14, 2616, 6335}, {14, 2617, 6335}, {14, 2618, 6335},
+ {14, 2619, 6335}, {14, 2620, 6335}, {14, 2621, 6335}}),
+ util::tileCover(geom, 14));
+}
+
+TEST(TileCover, GeomPolygon) {
+ auto polygon = Polygon<double>{
+ {
+ {5.09765625,53.067626642387374},
+ {2.373046875,43.389081939117496},
+ {-4.74609375,48.45835188280866},
+ {-1.494140625,37.09023980307208},
+ {22.587890625,36.24427318493909},
+ {31.640625,46.13417004624326},
+ {17.841796875,54.7246201949245},
+ {5.09765625,53.067626642387374},
+ },{
+ {19.6875,49.66762782262194},
+ {22.8515625,43.51668853502906},
+ {13.623046875,45.089035564831036},
+ {16.34765625,39.095962936305476},
+ {5.185546875,41.244772343082076},
+ {8.701171874999998,50.233151832472245},
+ {19.6875,49.66762782262194}
+ }
+ };
+
+ auto results = util::tileCover(polygon, 8);
+
+ EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 134, 87}), results.end());
+ EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 139, 87}), results.end());
+ // Should have a hole
+ EXPECT_EQ(std::find(results.begin(), results.end(), UnwrappedTileID{8, 136, 87}), results.end());
+}
+
+TEST(TileCover, GeomMultiPolygon) {
+ auto multiPolygon = MultiPolygon<double>{
+ {{
+ {5.09765625,53.067626642387374},
+ {2.373046875,43.389081939117496},
+ {-4.74609375,48.45835188280866},
+ {-1.494140625,37.09023980307208},
+ {22.587890625,36.24427318493909},
+ {31.640625,46.13417004624326},
+ {17.841796875,54.7246201949245},
+ {5.09765625,53.067626642387374},
+ }},{{
+ {59.150390625,45.460130637921004},
+ {65.126953125,41.11246878918088},
+ {69.169921875,47.45780853075031},
+ {63.896484375,50.064191736659104},
+ {59.150390625,45.460130637921004}
+ }}
+ };
+ auto results = util::tileCover(multiPolygon, 8);
+
+ EXPECT_EQ(424u, results.size());
+ EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 139, 87}), results.end());
+ EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 136, 87}), results.end());
+ EXPECT_NE(std::find(results.begin(), results.end(), UnwrappedTileID{8, 174, 94}), results.end());
+}
+
+TEST(TileCover, GeomSanFranciscoPoly) {
+ auto sanFranciscoGeom = Polygon<double>{
+ {
+ {-122.5143814086914,37.779127216982424},
+ {-122.50811576843262,37.72721239056709},
+ {-122.50313758850099,37.70820178063929},
+ {-122.3938751220703,37.707454835665274},
+ {-122.37567901611328,37.70663997801684},
+ {-122.36297607421874,37.71343018466285},
+ {-122.354736328125,37.727280276860036},
+ {-122.36469268798828,37.73868429065797},
+ {-122.38014221191408,37.75442980295571},
+ {-122.38391876220702,37.78753873820529},
+ {-122.35919952392578,37.8065289741725},
+ {-122.35679626464844,37.820632846207864},
+ {-122.3712158203125,37.835276322922695},
+ {-122.3818588256836,37.82958198283902},
+ {-122.37190246582031,37.80788523279169},
+ {-122.38735198974608,37.791337175930686},
+ {-122.40966796874999,37.812767557570204},
+ {-122.46425628662108,37.807071480609274},
+ {-122.46803283691405,37.810326435534755},
+ {-122.47901916503906,37.81168262440736},
+ {-122.48966217041016,37.78916666399649},
+ {-122.50579833984375,37.78781006166096},
+ {-122.5143814086914,37.779127216982424}
+ }
+ };
+
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ { 12, 654, 1582 }, { 12, 655, 1582 },
+ { 12, 654, 1583 }, { 12, 655, 1583 },
+ { 12, 654, 1584 }, { 12, 655, 1584 }
+ }), util::tileCover(sanFranciscoGeom, 12));
+}
+
+TEST(TileCover, GeomInvalid) {
+ auto point = Point<double>{ -122.5744, 97.6609 };
+ EXPECT_THROW(util::tileCover(point, 2), std::domain_error);
+
+ auto badPoly = Polygon<double> { { {1.0, 35.0} } };
+ EXPECT_EQ((std::vector<UnwrappedTileID>{ }), util::tileCover(badPoly, 16));
+
+ //Should handle open polygons.
+ badPoly = Polygon<double> { { {1.0, 34.2}, {1.0, 34.4}, {0.5, 34.3} } };
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ { 10, 513, 407 }, { 10, 514, 407},
+ { 10, 513, 408 }, { 10, 514, 408}
+ }), util::tileCover(badPoly, 10));
+}
+
+
+TEST(TileCount, World) {
+ EXPECT_EQ(1u, util::tileCount(LatLngBounds::world(), 0));
+ EXPECT_EQ(4u, util::tileCount(LatLngBounds::world(), 1));
+}
+
TEST(TileCount, SanFranciscoZ10) {
- EXPECT_EQ(4u, util::tileCount(sanFrancisco, 10, util::tileSize));
+ EXPECT_EQ(4u, util::tileCount(sanFrancisco, 10));
+}
+
+TEST(TileCount, SanFranciscoWrappedZ10) {
+ EXPECT_EQ(4u, util::tileCount(sanFranciscoWrapped, 10));
}
TEST(TileCount, SanFranciscoZ22) {
- EXPECT_EQ(7254450u, util::tileCount(sanFrancisco, 22, util::tileSize));
+ EXPECT_EQ(7254450u, util::tileCount(sanFrancisco, 22));
}
+TEST(TileCount, BoundsCrossingAntimeridian) {
+ auto crossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830});
+
+ EXPECT_EQ(1u, util::tileCount(crossingBounds, 0));
+ EXPECT_EQ(4u, util::tileCount(crossingBounds, 3));
+ EXPECT_EQ(8u, util::tileCount(crossingBounds, 4));
+}
diff --git a/test/util/tile_range.test.cpp b/test/util/tile_range.test.cpp
index c4c37c74d7..83ac5096a5 100644
--- a/test/util/tile_range.test.cpp
+++ b/test/util/tile_range.test.cpp
@@ -52,14 +52,14 @@ TEST(TileRange, ContainsWrappedBounds) {
TEST(TileRange, ContainsBoundsCrossingAntimeridian) {
{
- auto cossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830});
- auto range = util::TileRange::fromLatLngBounds(cossingBounds, 1);
+ auto crossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830});
+ auto range = util::TileRange::fromLatLngBounds(crossingBounds, 1);
EXPECT_TRUE(range.contains(CanonicalTileID(1, 1, 1)));
EXPECT_TRUE(range.contains(CanonicalTileID(1, 0, 0)));
}
{
- auto cossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830});
- auto range = util::TileRange::fromLatLngBounds(cossingBounds, 6);
+ auto crossingBounds = LatLngBounds::hull({-20.9615, -214.309}, {19.477, -155.830});
+ auto range = util::TileRange::fromLatLngBounds(crossingBounds, 6);
EXPECT_FALSE(range.contains(CanonicalTileID(6, 55, 34)));
EXPECT_FALSE(range.contains(CanonicalTileID(6, 5, 28)));
EXPECT_TRUE(range.contains(CanonicalTileID(6, 63, 28)));