summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTobrun <tobrun.van.nuland@gmail.com>2019-08-29 19:38:27 +0200
committerGitHub <noreply@github.com>2019-08-29 19:38:27 +0200
commit520c59c11a632e54233d615fba0960c7f4144714 (patch)
tree5178fb23f61db793fc1fb750d59edc776c711369
parent3321bde94e20ed5ebc43c0051d93a72e9afc2515 (diff)
parent544aabd0204235579e99fe4d9b8c2de16f70e897 (diff)
downloadqtlocation-mapboxgl-520c59c11a632e54233d615fba0960c7f4144714.tar.gz
Merge branch 'master' into tvn-number-format-expression
-rw-r--r--Makefile4
-rw-r--r--bin/offline.cpp2
-rw-r--r--circle.yml2
-rw-r--r--cmake/render-test.cmake1
-rw-r--r--include/mbgl/map/map.hpp2
-rw-r--r--include/mbgl/map/map_observer.hpp2
-rw-r--r--include/mbgl/renderer/renderer.hpp1
-rw-r--r--include/mbgl/renderer/renderer_observer.hpp4
-rw-r--r--include/mbgl/storage/offline.hpp5
-rw-r--r--platform/android/.gitignore2
-rw-r--r--platform/android/CHANGELOG.md42
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle.properties2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java97
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java80
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java12
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java16
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java81
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java10
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java79
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java5
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java7
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java21
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java27
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java42
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java35
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt101
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleTest.kt18
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt6
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt4
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt253
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapInstrumentationTest.kt41
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt38
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt64
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java296
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java290
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java292
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraTest.java307
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraAnimatorActivity.java7
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java8
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml1
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml5
-rw-r--r--platform/android/core-files.json2
-rw-r--r--platform/android/gradle/dependencies.gradle2
-rw-r--r--platform/android/src/android_renderer_frontend.cpp4
-rw-r--r--platform/android/src/java_types.cpp8
-rw-r--r--platform/android/src/java_types.hpp6
-rwxr-xr-xplatform/android/src/jni.cpp157
-rw-r--r--platform/android/src/jni.hpp3
-rwxr-xr-xplatform/android/src/jni_native.cpp164
-rw-r--r--platform/android/src/jni_native.hpp11
-rw-r--r--platform/android/src/main.cpp2
-rw-r--r--platform/android/src/map/camera_position.cpp22
-rw-r--r--platform/android/src/map/camera_position.hpp4
-rw-r--r--platform/android/src/map_renderer.cpp6
-rw-r--r--platform/android/src/map_renderer.hpp2
-rwxr-xr-xplatform/android/src/native_map_view.cpp65
-rwxr-xr-xplatform/android/src/native_map_view.hpp15
-rw-r--r--platform/android/src/snapshotter/map_snapshotter.cpp8
-rw-r--r--platform/android/src/snapshotter/map_snapshotter.hpp1
-rw-r--r--platform/android/src/style/android_conversion.hpp15
-rw-r--r--platform/android/src/style/value.cpp6
-rw-r--r--platform/android/src/style/value.hpp1
m---------platform/android/vendor/mapbox-gestures-android0
-rw-r--r--platform/darwin/src/MGLAccountManager.m2
-rw-r--r--platform/darwin/src/MGLAccountManager_Private.h3
-rw-r--r--platform/darwin/src/MGLMapSnapshotter.mm2
-rw-r--r--platform/darwin/src/MGLOfflineStorage.h10
-rw-r--r--platform/darwin/src/MGLRendererConfiguration.h3
-rw-r--r--platform/darwin/src/MGLRendererConfiguration.mm4
-rw-r--r--platform/darwin/src/http_file_source.mm19
-rw-r--r--platform/darwin/test/MGLResourceTests.mm23
-rw-r--r--platform/darwin/test/MGLTileSetTests.mm19
-rw-r--r--platform/default/include/mbgl/gfx/headless_frontend.hpp2
-rw-r--r--platform/default/include/mbgl/map/map_snapshotter.hpp1
-rw-r--r--platform/default/include/mbgl/storage/offline_database.hpp5
-rw-r--r--platform/default/include/mbgl/storage/offline_download.hpp4
-rw-r--r--platform/default/src/mbgl/gfx/headless_frontend.cpp6
-rw-r--r--platform/default/src/mbgl/map/map_snapshotter.cpp7
-rw-r--r--platform/default/src/mbgl/storage/offline_database.cpp33
-rw-r--r--platform/default/src/mbgl/storage/offline_download.cpp62
-rw-r--r--platform/ios/CHANGELOG.md19
-rw-r--r--platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.mm (renamed from platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m)273
-rw-r--r--platform/ios/Integration Tests/MGLMapViewIntegrationTest.h1
-rw-r--r--platform/ios/Integration Tests/MGLMapViewIntegrationTest.m11
-rw-r--r--platform/ios/Integration Tests/MGLMapViewPendingBlockTests.m367
-rw-r--r--platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK-stripped.podspec2
-rw-r--r--platform/ios/Mapbox-iOS-SDK.podspec2
-rw-r--r--platform/ios/app/MBXState.h2
-rw-r--r--platform/ios/app/MBXState.m9
-rw-r--r--platform/ios/app/MBXViewController.m53
-rw-r--r--platform/ios/app/Main.storyboard14
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj28
-rwxr-xr-xplatform/ios/scripts/deploy-packages.sh6
-rwxr-xr-xplatform/ios/scripts/install-packaging-dependencies.sh9
-rwxr-xr-xplatform/ios/scripts/publish.sh44
-rw-r--r--platform/ios/src/MGLMapView+Impl.h2
-rw-r--r--platform/ios/src/MGLMapView+Impl.mm2
-rw-r--r--platform/ios/src/MGLMapView.h24
-rw-r--r--platform/ios/src/MGLMapView.mm389
-rw-r--r--platform/ios/src/MGLMapView_Private.h2
-rw-r--r--platform/ios/src/MGLMapboxEvents.h3
-rw-r--r--platform/ios/src/MGLMapboxEvents.m66
-rw-r--r--platform/ios/src/MGLScaleBar.mm15
-rw-r--r--platform/ios/test/MGLMapViewDirectionTests.mm7
-rw-r--r--platform/ios/test/MGLMapViewPitchTests.m39
-rw-r--r--platform/ios/test/MGLMapViewZoomTests.mm (renamed from platform/ios/test/MGLMapViewZoomTests.m)68
-rw-r--r--platform/ios/test/MGLMockGestureRecognizers.h10
-rw-r--r--platform/ios/test/MGLMockGestureRecognizers.m11
-rw-r--r--platform/macos/CHANGELOG.md6
-rw-r--r--platform/macos/src/MGLMapView+Impl.h2
-rw-r--r--platform/macos/src/MGLMapView+Impl.mm2
-rw-r--r--platform/macos/src/MGLMapView.mm2
-rw-r--r--platform/node/CHANGELOG.md9
-rw-r--r--platform/node/test/ignores.json8
-rw-r--r--platform/qt/src/local_glyph_rasterizer.cpp25
-rw-r--r--platform/qt/src/qmapboxgl_map_observer.cpp2
-rw-r--r--platform/qt/src/qmapboxgl_map_observer.hpp2
-rw-r--r--platform/qt/src/qmapboxgl_map_renderer.cpp2
-rw-r--r--platform/qt/src/qmapboxgl_renderer_observer.hpp4
-rw-r--r--render-test/allocation_index.cpp101
-rw-r--r--render-test/allocation_index.hpp53
-rw-r--r--render-test/expected/debug/collision-lines-overscaled/expected.pngbin0 -> 7774 bytes
-rw-r--r--render-test/expected/debug/collision-lines-pitched/expected.pngbin0 -> 165500 bytes
-rw-r--r--render-test/expected/debug/collision-lines/expected.pngbin0 -> 196454 bytes
-rw-r--r--render-test/expected/debug/collision-pitched-wrapped/expected.pngbin0 -> 69725 bytes
-rw-r--r--render-test/expected/symbol-visibility/visible/expected.pngbin0 -> 14729 bytes
-rw-r--r--render-test/expected/text-pitch-alignment/auto-text-rotation-alignment-map/expected.pngbin0 -> 26157 bytes
-rw-r--r--render-test/expected/text-pitch-alignment/map-text-rotation-alignment-map/expected.pngbin0 -> 26157 bytes
-rw-r--r--render-test/expected/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.pngbin0 -> 26866 bytes
-rw-r--r--render-test/main.cpp46
-rw-r--r--render-test/metadata.hpp23
-rw-r--r--render-test/parser.cpp115
-rw-r--r--render-test/parser.hpp13
-rw-r--r--render-test/runner.cpp102
-rw-r--r--render-test/runner.hpp2
-rw-r--r--src/mbgl/layout/symbol_instance.cpp22
-rw-r--r--src/mbgl/layout/symbol_instance.hpp31
-rw-r--r--src/mbgl/layout/symbol_layout.cpp54
-rw-r--r--src/mbgl/layout/symbol_layout.hpp4
-rw-r--r--src/mbgl/map/map.cpp2
-rw-r--r--src/mbgl/map/map_impl.cpp4
-rw-r--r--src/mbgl/map/map_impl.hpp2
-rw-r--r--src/mbgl/map/transform.cpp2
-rw-r--r--src/mbgl/map/transform.hpp2
-rw-r--r--src/mbgl/map/transform_state.cpp17
-rw-r--r--src/mbgl/map/transform_state.hpp5
-rw-r--r--src/mbgl/programs/program_parameters.cpp22
-rw-r--r--src/mbgl/programs/program_parameters.hpp4
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.cpp45
-rw-r--r--src/mbgl/renderer/buckets/symbol_bucket.hpp6
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.cpp43
-rw-r--r--src/mbgl/renderer/layers/render_symbol_layer.hpp6
-rw-r--r--src/mbgl/renderer/render_orchestrator.cpp10
-rw-r--r--src/mbgl/renderer/render_static_data.cpp6
-rw-r--r--src/mbgl/renderer/render_static_data.hpp2
-rw-r--r--src/mbgl/renderer/render_tree.hpp1
-rw-r--r--src/mbgl/renderer/renderer.cpp2
-rw-r--r--src/mbgl/renderer/renderer_impl.cpp9
-rw-r--r--src/mbgl/renderer/renderer_impl.hpp2
-rw-r--r--src/mbgl/renderer/sources/render_geojson_source.cpp2
-rw-r--r--src/mbgl/style/layers/fill_layer_impl.cpp1
-rw-r--r--src/mbgl/text/glyph_manager.cpp6
-rw-r--r--src/mbgl/text/placement.cpp80
-rw-r--r--src/mbgl/tile/geojson_tile.cpp4
-rw-r--r--src/mbgl/tile/geojson_tile.hpp2
-rw-r--r--src/mbgl/tile/geometry_tile.cpp4
-rw-r--r--src/mbgl/tile/geometry_tile.hpp2
-rw-r--r--src/mbgl/tile/geometry_tile_worker.cpp3
-rw-r--r--src/mbgl/tile/geometry_tile_worker.hpp2
-rw-r--r--src/mbgl/util/tile_coordinate.hpp5
-rw-r--r--src/mbgl/util/tile_cover.cpp12
-rw-r--r--src/mbgl/util/tile_cover.hpp10
-rw-r--r--test/fixtures/local_glyphs/mixed.json4
-rw-r--r--test/fixtures/local_glyphs/no_local/expected.pngbin6963 -> 8855 bytes
-rw-r--r--test/fixtures/local_glyphs/no_local_with_content_insets/expected.pngbin6784 -> 8823 bytes
-rw-r--r--test/fixtures/local_glyphs/no_local_with_content_insets_and_pitch/expected.pngbin6026 -> 7537 bytes
-rw-r--r--test/fixtures/local_glyphs/noto_sans_cjk_kr_regular_qt/expected.pngbin0 -> 27980 bytes
-rw-r--r--test/fixtures/local_glyphs/ping_fang/expected.pngbin18019 -> 18174 bytes
-rw-r--r--test/fixtures/local_glyphs/ping_fang_qt/expected.pngbin25026 -> 28524 bytes
-rw-r--r--test/fixtures/resources/glyphs-12244-12543.pbfbin0 -> 134697 bytes
-rw-r--r--test/gl/bucket.test.cpp4
-rw-r--r--test/gl/context.test.cpp2
-rw-r--r--test/src/mbgl/test/stub_map_observer.hpp2
-rw-r--r--test/storage/offline_database.test.cpp38
-rw-r--r--test/storage/offline_download.test.cpp11
-rw-r--r--test/text/cross_tile_symbol_index.test.cpp24
-rw-r--r--test/text/glyph_manager.test.cpp53
-rw-r--r--test/text/local_glyph_rasterizer.test.cpp22
-rw-r--r--test/util/tile_cover.test.cpp14
200 files changed, 3580 insertions, 2105 deletions
diff --git a/Makefile b/Makefile
index 9002542eee..51956cae6b 100644
--- a/Makefile
+++ b/Makefile
@@ -801,7 +801,7 @@ test-code-android:
# Runs checkstyle and lint on the java code
.PHONY: android-check
-android-check : android-checkstyle run-android-nitpick android-lint-sdk android-lint-test-app android-ktlint
+android-check : android-ktlint android-checkstyle android-lint-sdk android-lint-test-app run-android-nitpick
# Runs checkstyle on the java code
.PHONY: android-checkstyle
@@ -810,7 +810,7 @@ android-checkstyle: platform/android/gradle/configuration.gradle
# Runs checkstyle on the kotlin code
.PHONY: android-ktlint
-android-ktlint:
+android-ktlint: platform/android/gradle/configuration.gradle
cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none ktlint
# Runs lint on the Android SDK java code
diff --git a/bin/offline.cpp b/bin/offline.cpp
index fc8b0f1bd4..fcc6adc3ef 100644
--- a/bin/offline.cpp
+++ b/bin/offline.cpp
@@ -217,6 +217,8 @@ int main(int argc, char *argv[]) {
std::cout << status.completedResourceCount << " / " << status.requiredResourceCount
<< " resources"
+ << status.completedTileCount << " / " << status.requiredTileCount
+ << "tiles"
<< (status.requiredResourceCountIsPrecise ? "; " : " (indeterminate); ")
<< status.completedResourceSize << " bytes downloaded"
<< " (" << bytesPerSecond << " bytes/sec)"
diff --git a/circle.yml b/circle.yml
index 47bc1e9bdb..3293de1aca 100644
--- a/circle.yml
+++ b/circle.yml
@@ -1295,7 +1295,7 @@ jobs:
# ------------------------------------------------------------------------------
qt5-linux-gcc5-release:
docker:
- - image: mbgl/linux-gcc-5-qt-5.9:5132cfd29f
+ - image: mbgl/linux-gcc-5-qt-5.9:5cd92d7d1c
resource_class: large
working_directory: /src
environment:
diff --git a/cmake/render-test.cmake b/cmake/render-test.cmake
index 6505cc73f8..acb8f8bc24 100644
--- a/cmake/render-test.cmake
+++ b/cmake/render-test.cmake
@@ -1,4 +1,5 @@
add_executable(mbgl-render-test
+ render-test/allocation_index.cpp
render-test/main.cpp
render-test/parser.cpp
render-test/runner.cpp
diff --git a/include/mbgl/map/map.hpp b/include/mbgl/map/map.hpp
index b1d4b14e4f..ac0a398d25 100644
--- a/include/mbgl/map/map.hpp
+++ b/include/mbgl/map/map.hpp
@@ -60,7 +60,7 @@ public:
bool isPanning() const;
// Camera
- CameraOptions getCameraOptions(const EdgeInsets& = {}) const;
+ CameraOptions getCameraOptions(optional<EdgeInsets> = {}) const;
void jumpTo(const CameraOptions&);
void easeTo(const CameraOptions&, const AnimationOptions&);
void flyTo(const CameraOptions&, const AnimationOptions&);
diff --git a/include/mbgl/map/map_observer.hpp b/include/mbgl/map/map_observer.hpp
index a79f5ac82d..7de6a3fa84 100644
--- a/include/mbgl/map/map_observer.hpp
+++ b/include/mbgl/map/map_observer.hpp
@@ -41,7 +41,7 @@ public:
virtual void onDidFinishLoadingMap() {}
virtual void onDidFailLoadingMap(MapLoadError, const std::string&) {}
virtual void onWillStartRenderingFrame() {}
- virtual void onDidFinishRenderingFrame(RenderMode) {}
+ virtual void onDidFinishRenderingFrame(RenderMode, bool /*placementChanged*/) {}
virtual void onWillStartRenderingMap() {}
virtual void onDidFinishRenderingMap(RenderMode) {}
virtual void onDidFinishLoadingStyle() {}
diff --git a/include/mbgl/renderer/renderer.hpp b/include/mbgl/renderer/renderer.hpp
index 787f9dceee..f1800dbfb8 100644
--- a/include/mbgl/renderer/renderer.hpp
+++ b/include/mbgl/renderer/renderer.hpp
@@ -24,7 +24,6 @@ class RendererBackend;
class Renderer {
public:
Renderer(gfx::RendererBackend&, float pixelRatio_,
- const optional<std::string> programCacheDir = {},
const optional<std::string> localFontFamily = {});
~Renderer();
diff --git a/include/mbgl/renderer/renderer_observer.hpp b/include/mbgl/renderer/renderer_observer.hpp
index 4d21a0aaee..e0fc84215e 100644
--- a/include/mbgl/renderer/renderer_observer.hpp
+++ b/include/mbgl/renderer/renderer_observer.hpp
@@ -26,8 +26,8 @@ public:
// Start of frame, initial is the first frame for this map
virtual void onWillStartRenderingFrame() {}
- // End of frame, boolean flags that a repaint is required
- virtual void onDidFinishRenderingFrame(RenderMode, bool) {}
+ // End of frame, booleans flags that a repaint is required and that placement changed.
+ virtual void onDidFinishRenderingFrame(RenderMode, bool /*repaint*/, bool /*placementChanged*/) {}
// Final frame
virtual void onDidFinishRenderingMap() {}
diff --git a/include/mbgl/storage/offline.hpp b/include/mbgl/storage/offline.hpp
index f702f47edc..baf43dc5f5 100644
--- a/include/mbgl/storage/offline.hpp
+++ b/include/mbgl/storage/offline.hpp
@@ -129,6 +129,11 @@ public:
uint64_t completedTileCount = 0;
/**
+ * The number of tiles that are known to be required for this region.
+ */
+ uint64_t requiredTileCount = 0;
+
+ /**
* The cumulative size, in bytes, of all tiles that have been fully downloaded.
* This is a subset of `completedResourceSize`.
*/
diff --git a/platform/android/.gitignore b/platform/android/.gitignore
index f37dc37ea6..a4c2b818fa 100644
--- a/platform/android/.gitignore
+++ b/platform/android/.gitignore
@@ -30,3 +30,5 @@ MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/acti
# Input files for running render tests
MapboxGLAndroidSDKTestApp/src/main/assets/integration/
+# Local AS configuration file
+gradle.properties \ No newline at end of file
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 6a87e8e49e..8a10edd169 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -3,18 +3,54 @@
Mapbox welcomes participation and contributions from everyone. If you'd like to do so please see the [`Contributing Guide`](https://github.com/mapbox/mapbox-gl-native/blob/master/CONTRIBUTING.md) first to get started.
## master
-
### Features
+ - Introduce `clusterProperties` option for aggregated cluster properties. [#15425](https://github.com/mapbox/mapbox-gl-native/pull/15425)
+ - Expose the `CameraPosition#padding` field and associated utility camera position builders. This gives a choice to set a persisting map padding immediately during a transition instead of setting it lazily `MapboxMap#setPadding`, which required scheduling additional transition to be applied. This also deprecates `MapboxMap#setPadding` as there should be no need for a lazy padding setter. [#15444](https://github.com/mapbox/mapbox-gl-native/pull/15444)
- Add number-format expression [#15424](https://github.com/mapbox/mapbox-gl-native/pull/15424)
+ ### Performance improvements
+ - Mark used offline region resources in batches. [#15521](https://github.com/mapbox/mapbox-gl-native/pull/15521)
+
+## 8.3.0 - August 28, 2019
+[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0-beta.1...android-v8.3.0) since [Mapbox Maps SDK for Android v8.3.0-beta.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0-beta.1):
+
+This release changes how offline tile requests are billed — they are now billed on a pay-as-you-go basis and all developers are able raise the offline tile limit for their users. Offline requests were previously exempt from monthly active user (MAU) billing and increasing the offline per-user tile limit to more than 6,000 tiles required the purchase of an enterprise license. By upgrading to this release, you are opting into the changes outlined in [this blog post](https://blog.mapbox.com/offline-maps-for-all-bb0fc51827be) and [#15380](https://github.com/mapbox/mapbox-gl-native/pull/15380).
+
+### Features
+ - Allow ability to pass a string array resource into `localIdeographFontFamily` for enabling/disabling the feature and specifying fallback fonts. [#15488](https://github.com/mapbox/mapbox-gl-native/pull/15488)
+
+### Bug fixes
+ - Fixed a rendering issue caused by all icons being treated as SDFs if an SDF and non-SDF icon were in the same layer. [#15456](https://github.com/mapbox/mapbox-gl-native/pull/15456)
+ - Fixed an issue where changing location's render mode when the`LocationComponent` is disable wouldn't invalidate the foreground icon when it's back enabled. [#15507](https://github.com/mapbox/mapbox-gl-native/pull/15507)
+
+## 8.2.2 - August 23, 2019
+[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.2.1...android-v8.2.2) since [Mapbox Maps SDK for Android v8.2.1](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.2.1):
+
### Bug fixes
+ - Fixed a possible crash that could be caused by invoking the wrong layer implementation casting function. [#15398](https://github.com/mapbox/mapbox-gl-native/pull/15398)
- Fixed use of objects after moving, potentially causing crashes. [#15408](https://github.com/mapbox/mapbox-gl-native/pull/1540)
+ - Fixed a wrong calculation of visibility in high pitch scenarios which might've led to tiles in the viewport not being rendered. [#15461](https://github.com/mapbox/mapbox-gl-native/pull/15461)
+
+### Other Changes
+ - Do not invalidate the camera immediately when map padding is set. Reverts a change introduced in the `v8.2.0`. [#15437](https://github.com/mapbox/mapbox-gl-native/pull/15437)
+
+## 8.3.0-beta.1 - August 22, 2019
+[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0-alpha.3...android-v8.3.0-beta.1) since [Mapbox Maps SDK for Android v8.3.0-alpha.3](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0-alpha.3):
+
+### Bug fixes
+ - Fixed a bug where glyphs generated through the LocalGlyphRasterizer interface were changing fonts during some zoom changes. [#15407](https://github.com/mapbox/mapbox-gl-native/pull/15407)
+ - Fixed use of objects after moving, potentially causing crashes. [#15408](https://github.com/mapbox/mapbox-gl-native/pull/15408)
- Fixed a possible crash that could be caused by invoking the wrong layer implementation casting function [#15398](https://github.com/mapbox/mapbox-gl-native/pull/15398).
- Font lookup on pre lollipop devices failed, provide default font list instead [#15410](https://github.com/mapbox/mapbox-gl-native/pull/15410).
- Fixed rendering and collision detection issues with using `text-variable-anchor` and `icon-text-fit` properties on the same layer [#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367).
+ - Fixed a bug where quick-scale was registered during a move gesture that followed a double-tap. Bumped gestures library to `v0.5.1`. [#15427](https://github.com/mapbox/mapbox-gl-native/pull/15427)
+ - Fixed symbol overlap when zooming out quickly. [#15416](https://github.com/mapbox/mapbox-gl-native/pull/15416)
+
+### Other Changes
+ - Do not invalidate the camera immediately when map padding is set. Reverts a change introduced in the `v8.2.0`. [#15437](https://github.com/mapbox/mapbox-gl-native/pull/15437)
### Docs
- - Add javadoc to OnStyleImageMissingListener indicating the required synchronous addition images, document workaround [#15418](https://github.com/mapbox/mapbox-gl-native/pull/15418)
+ - Add javadoc to OnStyleImageMissingListener indicating the required synchronous addition images, document workaround [#15418](https://github.com/mapbox/mapbox-gl-native/pull/15418)
## 8.3.0-alpha.3 - August 15, 2019
[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.3.0-alpha.2...android-v8.3.0-alpha.3) since [Mapbox Maps SDK for Android v8.3.0-alpha.2](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.3.0-alpha.2):
@@ -62,7 +98,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
[Changes](https://github.com/mapbox/mapbox-gl-native/compare/android-v8.2.0...android-v8.3.0-alpha.1) since [Mapbox Maps SDK for Android v8.2.0](https://github.com/mapbox/mapbox-gl-native/releases/tag/android-v8.2.0):
### Features
- - Do not include CJK ideographs in the offline packs by default. This decreases overall offline download size but changes appereance by a default set local glyph generation [#14269](https://github.com/mapbox/mapbox-gl-native/pull/14269)
+ - Do not include CJK ideographs in the offline packs by default. This decreases overall offline download size but changes appearance by a default set local glyph generation [#14269](https://github.com/mapbox/mapbox-gl-native/pull/14269)
- Update target SDK to 28, update support library and fix gradle warnings [#15135](https://github.com/mapbox/mapbox-gl-native/pull/15135)
- Introduce VertexVector::extend() and use it in placement code [#15194](https://github.com/mapbox/mapbox-gl-native/pull/15194)
diff --git a/platform/android/MapboxGLAndroidSDK/gradle.properties b/platform/android/MapboxGLAndroidSDK/gradle.properties
index 989a56fd63..f906453f56 100644
--- a/platform/android/MapboxGLAndroidSDK/gradle.properties
+++ b/platform/android/MapboxGLAndroidSDK/gradle.properties
@@ -1,4 +1,4 @@
-VERSION_NAME=8.3.0-SNAPSHOT
+VERSION_NAME=8.4.0-SNAPSHOT
# Only build native dependencies for the current ABI
# See https://code.google.com/p/android/issues/detail?id=221098#c20
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
index f44c0f1904..e2341029ff 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java
@@ -5,20 +5,23 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.FloatRange;
import android.support.annotation.Keep;
-
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.Size;
+
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.utils.MathUtils;
+import java.util.Arrays;
+
/**
* Resembles the position, angle, zoom and tilt of the user's viewpoint.
*/
public final class CameraPosition implements Parcelable {
- public static final CameraPosition DEFAULT = new CameraPosition(new LatLng(), 0, 0, 0);
+ public static final CameraPosition DEFAULT = new CameraPosition(new LatLng(), 0, 0, 0, new double[] {0, 0, 0, 0});
public static final Parcelable.Creator<CameraPosition> CREATOR =
new Parcelable.Creator<CameraPosition>() {
@@ -27,7 +30,9 @@ public final class CameraPosition implements Parcelable {
LatLng target = in.readParcelable(LatLng.class.getClassLoader());
double tilt = in.readDouble();
double zoom = in.readDouble();
- return new CameraPosition(target, zoom, tilt, bearing);
+ double[] padding = new double[4];
+ in.readDoubleArray(padding);
+ return new CameraPosition(target, zoom, tilt, bearing, padding);
}
public CameraPosition[] newArray(int size) {
@@ -49,19 +54,26 @@ public final class CameraPosition implements Parcelable {
/**
* The angle, in degrees, of the camera angle from the nadir (directly facing the Earth).
- * See tilt(float) for details of restrictions on the range of values.
+ * See {@link Builder#tilt(double)} for details of restrictions on the range of values.
*/
@Keep
public final double tilt;
/**
- * Zoom level near the center of the screen. See zoom(float) for the definition of the camera's
+ * Zoom level near the center of the screen. See {@link Builder#zoom(double)} for the definition of the camera's
* zoom level.
*/
@Keep
public final double zoom;
/**
+ * Padding in pixels. Specified in left, top, right, bottom order.
+ * See {@link Builder#padding(double[])} for the definition of the camera's padding.
+ */
+ @Keep
+ public final double[] padding;
+
+ /**
* Constructs a CameraPosition.
*
* @param target The target location to align with the center of the screen.
@@ -73,13 +85,34 @@ public final class CameraPosition implements Parcelable {
* exclusive.
* @throws NullPointerException if target is null
* @throws IllegalArgumentException if tilt is outside the range of 0 to 90 degrees inclusive.
+ * @deprecated use {@link CameraPosition#CameraPosition(LatLng, double, double, double, double[])} instead.
*/
- @Keep
+ @Deprecated
CameraPosition(LatLng target, double zoom, double tilt, double bearing) {
+ this(target, zoom, tilt, bearing, null);
+ }
+
+ /**
+ * Constructs a CameraPosition.
+ *
+ * @param target The target location to align with the center of the screen.
+ * @param zoom Zoom level at target. See zoom(float) for details of restrictions.
+ * @param tilt The camera angle, in degrees, from the nadir (directly down). See tilt(float)
+ * for details of restrictions.
+ * @param bearing Direction that the camera is pointing in, in degrees clockwise from north.
+ * This value will be normalized to be within 0 degrees inclusive and 360 degrees
+ * exclusive.
+ * @param padding Padding in pixels. Specified in left, top, right, bottom order.
+ * @throws NullPointerException if target is null
+ * @throws IllegalArgumentException if tilt is outside the range of 0 to 90 degrees inclusive.
+ */
+ @Keep
+ CameraPosition(LatLng target, double zoom, double tilt, double bearing, double[] padding) {
this.target = target;
this.bearing = bearing;
this.tilt = tilt;
this.zoom = zoom;
+ this.padding = padding;
}
/**
@@ -106,6 +139,7 @@ public final class CameraPosition implements Parcelable {
out.writeParcelable(target, flags);
out.writeDouble(tilt);
out.writeDouble(zoom);
+ out.writeDoubleArray(padding);
}
/**
@@ -115,7 +149,8 @@ public final class CameraPosition implements Parcelable {
*/
@Override
public String toString() {
- return "Target: " + target + ", Zoom:" + zoom + ", Bearing:" + bearing + ", Tilt:" + tilt;
+ return "Target: " + target + ", Zoom:" + zoom + ", Bearing:" + bearing + ", Tilt:" + tilt
+ + ", Padding:" + Arrays.toString(padding);
}
/**
@@ -145,6 +180,8 @@ public final class CameraPosition implements Parcelable {
return false;
} else if (bearing != cameraPosition.bearing) {
return false;
+ } else if (!Arrays.equals(padding, cameraPosition.padding)) {
+ return false;
}
return true;
}
@@ -159,8 +196,16 @@ public final class CameraPosition implements Parcelable {
*/
@Override
public int hashCode() {
- int result = 1;
+ int result;
+ long temp;
+ temp = Double.doubleToLongBits(bearing);
+ result = (int) (temp ^ (temp >>> 32));
result = 31 * result + (target != null ? target.hashCode() : 0);
+ temp = Double.doubleToLongBits(tilt);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ temp = Double.doubleToLongBits(zoom);
+ result = 31 * result + (int) (temp ^ (temp >>> 32));
+ result = 31 * result + Arrays.hashCode(padding);
return result;
}
@@ -174,6 +219,7 @@ public final class CameraPosition implements Parcelable {
private LatLng target = null;
private double tilt = -1;
private double zoom = -1;
+ private double[] padding = null;
/**
* Create an empty builder.
@@ -194,6 +240,7 @@ public final class CameraPosition implements Parcelable {
this.target = previous.target;
this.tilt = previous.tilt;
this.zoom = previous.zoom;
+ this.padding = previous.padding;
}
}
@@ -226,6 +273,7 @@ public final class CameraPosition implements Parcelable {
target = update.getTarget();
tilt = update.getTilt();
zoom = update.getZoom();
+ padding = update.getPadding();
}
}
@@ -307,12 +355,43 @@ public final class CameraPosition implements Parcelable {
}
/**
+ * Padding in pixels that shifts the viewport by the specified amount.
+ * Applied padding is going to persist and impact following camera transformations.
+ * <p>
+ * Specified in left, top, right, bottom order.
+ * </p>
+ *
+ * @param padding Camera padding
+ * @return this
+ */
+ @NonNull
+ public Builder padding(@Size(4) double[] padding) {
+ this.padding = padding;
+ return this;
+ }
+
+ /**
+ * Padding in pixels that shifts the viewport by the specified amount.
+ * Applied padding is going to persist and impact following camera transformations.
+ * <p>
+ * Specified in left, top, right, bottom order.
+ * </p>
+ *
+ * @return this
+ */
+ @NonNull
+ public Builder padding(double left, double top, double right, double bottom) {
+ this.padding = new double[] {left, top, right, bottom};
+ return this;
+ }
+
+ /**
* Builds the CameraPosition.
*
* @return CameraPosition
*/
public CameraPosition build() {
- return new CameraPosition(target, zoom, tilt, bearing);
+ return new CameraPosition(target, zoom, tilt, bearing, padding);
}
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
index 16285468ee..b611456f43 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java
@@ -5,6 +5,7 @@ import android.graphics.PointF;
import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapboxMap;
@@ -28,7 +29,7 @@ public final class CameraUpdateFactory {
*/
public static CameraUpdate newCameraPosition(@NonNull CameraPosition cameraPosition) {
return new CameraPositionUpdate(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt,
- cameraPosition.zoom);
+ cameraPosition.zoom, cameraPosition.padding);
}
/**
@@ -39,7 +40,7 @@ public final class CameraUpdateFactory {
* @return CameraUpdate Final Camera Position
*/
public static CameraUpdate newLatLng(@NonNull LatLng latLng) {
- return new CameraPositionUpdate(-1, latLng, -1, -1);
+ return new CameraPositionUpdate(-1, latLng, -1, -1, null);
}
/**
@@ -48,6 +49,7 @@ public final class CameraUpdateFactory {
* current camera position bearing and tilt values.
* <p>
* You can specify padding, in order to inset the bounding box from the map view's edges.
+ * The padding will not persist and impact following camera transformations.
* </p>
*
* @param bounds Bounds to match Camera position with
@@ -64,6 +66,7 @@ public final class CameraUpdateFactory {
* provided bearing and tilt values.
* <p>
* You can specify padding, in order to inset the bounding box from the map view's edges.
+ * The padding will not persist and impact following camera transformations.
* </p>
*
* @param bounds Bounds to match Camera position with
@@ -82,6 +85,7 @@ public final class CameraUpdateFactory {
* current camera position bearing and tilt values.
* <p>
* You can specify padding, in order to inset the bounding box from the map view's edges.
+ * The padding will not persist and impact following camera transformations.
* </p>
*
* @param bounds Bounds to base the Camera position out of
@@ -102,6 +106,7 @@ public final class CameraUpdateFactory {
* provided bearing and tilt values.
* <p>
* You can specify padding, in order to inset the bounding box from the map view's edges.
+ * The padding will not persist and impact following camera transformations.
* </p>
*
* @param bounds Bounds to base the Camera position out of
@@ -120,14 +125,31 @@ public final class CameraUpdateFactory {
/**
* Returns a CameraUpdate that moves the center of the screen to a latitude and longitude
- * specified by a LatLng object, and moves to the given zoom level.
+ * specified by a LatLng object taking the specified padding into account.
*
* @param latLng Target location to change to
* @param zoom Zoom level to change to
* @return CameraUpdate Final Camera Position
*/
public static CameraUpdate newLatLngZoom(@NonNull LatLng latLng, double zoom) {
- return new CameraPositionUpdate(-1, latLng, -1, zoom);
+ return new CameraPositionUpdate(-1, latLng, -1, zoom, null);
+ }
+
+ /**
+ * Returns a CameraUpdate that moves the center of the screen to a latitude and longitude
+ * specified by a LatLng object, and moves to the given zoom level.
+ * Applied padding is going to persist and impact following camera transformations.
+ *
+ * @param latLng Target location to change to
+ * @param left Left padding
+ * @param top Top padding
+ * @param right Right padding
+ * @param bottom Bottom padding
+ * @return CameraUpdate Final Camera Position
+ */
+ public static CameraUpdate newLatLngPadding(@NonNull LatLng latLng,
+ double left, double top, double right, double bottom) {
+ return new CameraPositionUpdate(-1, latLng, -1, -1, new double[] {left, top, right, bottom});
}
/**
@@ -188,7 +210,7 @@ public final class CameraUpdateFactory {
* @return CameraUpdate Final Camera Position
*/
public static CameraUpdate bearingTo(double bearing) {
- return new CameraPositionUpdate(bearing, null, -1, -1);
+ return new CameraPositionUpdate(bearing, null, -1, -1, null);
}
/**
@@ -198,7 +220,34 @@ public final class CameraUpdateFactory {
* @return CameraUpdate Final Camera Position
*/
public static CameraUpdate tiltTo(double tilt) {
- return new CameraPositionUpdate(-1, null, tilt, -1);
+ return new CameraPositionUpdate(-1, null, tilt, -1, null);
+ }
+
+ /**
+ * Returns a CameraUpdate that when animated changes the camera padding.
+ * Applied padding is going to persist and impact following camera transformations.
+ * <p>
+ * Specified in left, top, right, bottom order.
+ * </p>
+ *
+ * @param padding Padding to change to
+ * @return CameraUpdate Final Camera Position
+ */
+ public static CameraUpdate paddingTo(double[] padding) {
+ return new CameraPositionUpdate(-1, null, -1, -1, padding);
+ }
+
+ /**
+ * Returns a CameraUpdate that when animated changes the camera padding.
+ * Applied padding is going to persist and impact following camera transformations.
+ * <p>
+ * Specified in left, top, right, bottom order.
+ * </p>
+ *
+ * @return CameraUpdate Final Camera Position
+ */
+ public static CameraUpdate paddingTo(double left, double top, double right, double bottom) {
+ return paddingTo(new double[] {left, top, right, bottom});
}
//
@@ -211,12 +260,14 @@ public final class CameraUpdateFactory {
private final LatLng target;
private final double tilt;
private final double zoom;
+ private final double[] padding;
- CameraPositionUpdate(double bearing, LatLng target, double tilt, double zoom) {
+ CameraPositionUpdate(double bearing, LatLng target, double tilt, double zoom, double[] padding) {
this.bearing = bearing;
this.target = target;
this.tilt = tilt;
this.zoom = zoom;
+ this.padding = padding;
}
public LatLng getTarget() {
@@ -235,10 +286,14 @@ public final class CameraUpdateFactory {
return zoom;
}
+ public double[] getPadding() {
+ return padding;
+ }
+
@Override
public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) {
- CameraPosition previousPosition = mapboxMap.getCameraPosition();
if (target == null) {
+ CameraPosition previousPosition = mapboxMap.getCameraPosition();
return new CameraPosition.Builder(this)
.target(previousPosition.target)
.build();
@@ -247,7 +302,7 @@ public final class CameraUpdateFactory {
}
@Override
- public boolean equals(@Nullable Object o) {
+ public boolean equals(Object o) {
if (this == o) {
return true;
}
@@ -266,7 +321,10 @@ public final class CameraUpdateFactory {
if (Double.compare(that.zoom, zoom) != 0) {
return false;
}
- return target != null ? target.equals(that.target) : that.target == null;
+ if (target != null ? !target.equals(that.target) : that.target != null) {
+ return false;
+ }
+ return Arrays.equals(padding, that.padding);
}
@Override
@@ -280,6 +338,7 @@ public final class CameraUpdateFactory {
result = 31 * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(zoom);
result = 31 * result + (int) (temp ^ (temp >>> 32));
+ result = 31 * result + Arrays.hashCode(padding);
return result;
}
@@ -290,6 +349,7 @@ public final class CameraUpdateFactory {
+ ", target=" + target
+ ", tilt=" + tilt
+ ", zoom=" + zoom
+ + ", padding=" + Arrays.toString(padding)
+ '}';
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java
index 706f57ce9c..1faf8f5e5e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HttpRequestUrl.java
@@ -10,7 +10,10 @@ public class HttpRequestUrl {
}
/**
- * Adapts a resource request url based on the host and query size.
+ * Adapts a resource request url based on the host, query size, and offline requirement.
+ * Mapbox resources downloaded for offline use are subject to separate Vector Tile and
+ * Raster Tile API pricing and are not included in the Maps SDK’s “unlimited” requests.
+ * See <a href="https://www.mapbox.com/pricing">our pricing page</a> for more information.
*
* @param host the host used as endpoint
* @param resourceUrl the resource to download
@@ -25,10 +28,11 @@ public class HttpRequestUrl {
} else {
resourceUrl = resourceUrl + "&";
}
- resourceUrl = resourceUrl + "sku=" + Mapbox.getSkuToken();
-
+ // Only add SKU token to requests not tagged as "offline" usage.
if (offline) {
- resourceUrl = resourceUrl + "&offline=true";
+ resourceUrl = resourceUrl + "offline=true";
+ } else {
+ resourceUrl = resourceUrl + "sku=" + Mapbox.getSkuToken();
}
}
return resourceUrl;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
index 5b2dcd8554..46de3673e4 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponent.java
@@ -1182,7 +1182,6 @@ public final class LocationComponent {
}
isLayerReady = false;
- locationLayerController.hide();
staleStateManager.onStop();
if (compassEngine != null) {
updateCompassListenerState(false);
@@ -1289,6 +1288,7 @@ public final class LocationComponent {
private void disableLocationComponent() {
isEnabled = false;
+ locationLayerController.hide();
onLocationLayerStop();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java
index 8ab03e7acd..48c89622cd 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationComponentOptions.java
@@ -1530,8 +1530,11 @@ public class LocationComponentOptions implements Parcelable {
* </p>
*
* @param padding The margins for the map in pixels (left, top, right, bottom).
+ * @deprecated Use {@link CameraPosition.Builder#padding(double, double, double, double)}
+ * or {@link CameraUpdateFactory#paddingTo(double, double, double, double)} instead.
*/
@NonNull
+ @Deprecated
public LocationComponentOptions.Builder padding(@Nullable int[] padding) {
if (padding == null) {
throw new NullPointerException("Null padding");
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java
index b18a7c4742..54f8ee6d1a 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationLayerController.java
@@ -140,11 +140,11 @@ final class LocationLayerController {
}
this.renderMode = renderMode;
+ styleForeground(options);
+ determineIconsSource(options);
if (!isHidden) {
- styleForeground(options);
show();
}
- determineIconsSource(options);
internalRenderModeChangedListener.onRenderModeChanged(renderMode);
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
index 8e1019b379..acd5093dad 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java
@@ -1540,24 +1540,38 @@ public final class MapboxMap {
* frame from the viewport. For instance, if the only the top edge is inset, the
* map center is effectively shifted downward.
* </p>
+ * <p>
+ * This method sets the padding "lazily".
+ * This means that the <b>padding is going to be applied with the next camera transformation.</b>
+ * To apply the padding immediately use {@link CameraPosition.Builder#padding(double, double, double, double)}
+ * or {@link CameraUpdateFactory#paddingTo(double, double, double, double)}.
+ * </p>
*
* @param left The left margin in pixels.
* @param top The top margin in pixels.
* @param right The right margin in pixels.
* @param bottom The bottom margin in pixels.
+ * @deprecated Use {@link CameraPosition.Builder#padding(double, double, double, double)}
+ * or {@link CameraUpdateFactory#paddingTo(double, double, double, double)} instead.
*/
+ @Deprecated
public void setPadding(int left, int top, int right, int bottom) {
+ // TODO padding should be passed as doubles
projection.setContentPadding(new int[] {left, top, right, bottom});
uiSettings.invalidate();
}
/**
- * Returns the current configured content padding on map view.
+ * Returns the current configured content padding on map view. This might return the currently visible padding
+ * or the padding cached but not yet applied by {@link #setPadding(int, int, int, int)}.
*
* @return An array with length 4 in the LTRB order.
+ * @deprecated Use {@link CameraPosition#padding} instead.
*/
+ @Deprecated
@NonNull
public int[] getPadding() {
+ // TODO this should return double[] (semver major change)
return projection.getContentPadding();
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
index f922117dd0..6cd3271d12 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMapOptions.java
@@ -10,6 +10,7 @@ import android.os.Parcelable;
import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
import android.support.v4.content.res.ResourcesCompat;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -70,7 +71,11 @@ public class MapboxMapOptions implements Parcelable {
private boolean prefetchesTiles = true;
private boolean zMediaOverlay = false;
+
+ private boolean localIdeographFontFamilyEnabled = true;
private String localIdeographFontFamily;
+ private String[] localIdeographFontFamilies;
+
private String apiBaseUri;
private boolean textureMode;
@@ -130,7 +135,9 @@ public class MapboxMapOptions implements Parcelable {
translucentTextureSurface = in.readByte() != 0;
prefetchesTiles = in.readByte() != 0;
zMediaOverlay = in.readByte() != 0;
+ localIdeographFontFamilyEnabled = in.readByte() != 0;
localIdeographFontFamily = in.readString();
+ localIdeographFontFamilies = in.createStringArray();
pixelRatio = in.readFloat();
foregroundLoadColor = in.readInt();
crossSourceCollisions = in.readByte() != 0;
@@ -156,9 +163,15 @@ public class MapboxMapOptions implements Parcelable {
*/
@NonNull
public static MapboxMapOptions createFromAttributes(@NonNull Context context, @Nullable AttributeSet attrs) {
- MapboxMapOptions mapboxMapOptions = new MapboxMapOptions();
- float pxlRatio = context.getResources().getDisplayMetrics().density;
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.mapbox_MapView, 0, 0);
+ return createFromAttributes(new MapboxMapOptions(), context, typedArray);
+ }
+
+ @VisibleForTesting
+ static MapboxMapOptions createFromAttributes(@NonNull MapboxMapOptions mapboxMapOptions,
+ @NonNull Context context,
+ @Nullable TypedArray typedArray) {
+ float pxlRatio = context.getResources().getDisplayMetrics().density;
try {
mapboxMapOptions.camera(new CameraPosition.Builder(typedArray).build());
@@ -247,12 +260,24 @@ public class MapboxMapOptions implements Parcelable {
mapboxMapOptions.renderSurfaceOnTop(
typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_enableZMediaOverlay, false));
- String localIdeographFontFamily =
- typedArray.getString(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamily);
- if (localIdeographFontFamily == null) {
- localIdeographFontFamily = MapboxConstants.DEFAULT_FONT;
+ mapboxMapOptions.localIdeographFontFamilyEnabled =
+ typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_localIdeographEnabled, true);
+
+ int localIdeographFontFamiliesResId =
+ typedArray.getResourceId(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamilies, 0);
+ if (localIdeographFontFamiliesResId != 0) {
+ String[] localIdeographFontFamilies =
+ context.getResources().getStringArray(localIdeographFontFamiliesResId);
+ mapboxMapOptions.localIdeographFontFamily(localIdeographFontFamilies);
+ } else {
+ // did user provide xml font string?
+ String localIdeographFontFamily =
+ typedArray.getString(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamily);
+ if (localIdeographFontFamily == null) {
+ localIdeographFontFamily = MapboxConstants.DEFAULT_FONT;
+ }
+ mapboxMapOptions.localIdeographFontFamily(localIdeographFontFamily);
}
- mapboxMapOptions.localIdeographFontFamily(localIdeographFontFamily);
mapboxMapOptions.pixelRatio(
typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_pixelRatio, 0));
@@ -632,6 +657,18 @@ public class MapboxMapOptions implements Parcelable {
}
/**
+ * Enable local ideograph font family, defaults to true.
+ *
+ * @param enabled true to enable, false to disable
+ * @return This
+ */
+ @NonNull
+ public MapboxMapOptions localIdeographFontFamilyEnabled(boolean enabled) {
+ this.localIdeographFontFamilyEnabled = enabled;
+ return this;
+ }
+
+ /**
* Set the font family for generating glyphs locally for ideographs in the &#x27;CJK Unified Ideographs&#x27;
* and &#x27;Hangul Syllables&#x27; ranges.
* <p>
@@ -944,6 +981,11 @@ public class MapboxMapOptions implements Parcelable {
return textureMode;
}
+ /**
+ * Returns true if TextureView supports a translucent surface
+ *
+ * @return True if translucent surface is active
+ */
public boolean getTranslucentTextureSurface() {
return translucentTextureSurface;
}
@@ -962,11 +1004,22 @@ public class MapboxMapOptions implements Parcelable {
* Returns the font-family for locally overriding generation of glyphs in the
* &#x27;CJK Unified Ideographs&#x27; and &#x27;Hangul Syllables&#x27; ranges.
* Default font for local ideograph font family is {@link MapboxConstants#DEFAULT_FONT}.
+ * Returns null if local ideograph font families are disabled.
*
* @return Local ideograph font family name.
*/
+ @Nullable
public String getLocalIdeographFontFamily() {
- return localIdeographFontFamily;
+ return localIdeographFontFamilyEnabled ? localIdeographFontFamily : null;
+ }
+
+ /**
+ * Returns true if local ideograph font family is enabled, defaults to true.
+ *
+ * @return True if local ideograph font family is enabled
+ */
+ public boolean isLocalIdeographFontFamilyEnabled() {
+ return localIdeographFontFamilyEnabled;
}
/**
@@ -1029,7 +1082,9 @@ public class MapboxMapOptions implements Parcelable {
dest.writeByte((byte) (translucentTextureSurface ? 1 : 0));
dest.writeByte((byte) (prefetchesTiles ? 1 : 0));
dest.writeByte((byte) (zMediaOverlay ? 1 : 0));
+ dest.writeByte((byte) (localIdeographFontFamilyEnabled ? 1 : 0));
dest.writeString(localIdeographFontFamily);
+ dest.writeStringArray(localIdeographFontFamilies);
dest.writeFloat(pixelRatio);
dest.writeInt(foregroundLoadColor);
dest.writeByte((byte) (crossSourceCollisions ? 1 : 0));
@@ -1114,7 +1169,6 @@ public class MapboxMapOptions implements Parcelable {
if (!Arrays.equals(attributionMargins, options.attributionMargins)) {
return false;
}
-
if (apiBaseUri != null ? !apiBaseUri.equals(options.apiBaseUri) : options.apiBaseUri != null) {
return false;
}
@@ -1124,9 +1178,16 @@ public class MapboxMapOptions implements Parcelable {
if (zMediaOverlay != options.zMediaOverlay) {
return false;
}
+ if (localIdeographFontFamilyEnabled != options.localIdeographFontFamilyEnabled) {
+ return false;
+ }
if (!localIdeographFontFamily.equals(options.localIdeographFontFamily)) {
return false;
}
+ if (!Arrays.equals(localIdeographFontFamilies, options.localIdeographFontFamilies)) {
+ return false;
+ }
+
if (pixelRatio != options.pixelRatio) {
return false;
}
@@ -1171,7 +1232,9 @@ public class MapboxMapOptions implements Parcelable {
result = 31 * result + (translucentTextureSurface ? 1 : 0);
result = 31 * result + (prefetchesTiles ? 1 : 0);
result = 31 * result + (zMediaOverlay ? 1 : 0);
+ result = 31 * result + (localIdeographFontFamilyEnabled ? 1 : 0);
result = 31 * result + (localIdeographFontFamily != null ? localIdeographFontFamily.hashCode() : 0);
+ result = 31 * result + Arrays.hashCode(localIdeographFontFamilies);
result = 31 * result + (int) pixelRatio;
result = 31 * result + (crossSourceCollisions ? 1 : 0);
return result;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java
index da70013713..7f3017c7ae 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMap.java
@@ -41,12 +41,12 @@ interface NativeMap {
// Camera API
//
- void jumpTo(@NonNull LatLng center, double zoom, double pitch, double bearing);
+ void jumpTo(@NonNull LatLng center, double zoom, double pitch, double bearing, double[] padding);
- void easeTo(@NonNull LatLng center, double zoom, double bearing, double pitch, long duration,
+ void easeTo(@NonNull LatLng center, double zoom, double bearing, double pitch, double[] padding, long duration,
boolean easingInterpolator);
- void flyTo(@NonNull LatLng center, double zoom, double bearing, double pitch, long duration);
+ void flyTo(@NonNull LatLng center, double zoom, double bearing, double pitch, double[] padding, long duration);
void moveBy(double deltaX, double deltaY, long duration);
@@ -161,9 +161,9 @@ interface NativeMap {
// Content padding API
//
- void setContentPadding(float[] padding);
+ void setContentPadding(double[] padding);
- float[] getContentPadding();
+ double[] getContentPadding();
//
// Query API
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 fc68a408fa..8496160c7e 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
@@ -10,6 +10,7 @@ import android.support.annotation.Keep;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
+
import com.mapbox.geojson.Feature;
import com.mapbox.geojson.Geometry;
import com.mapbox.mapboxsdk.LibraryLoader;
@@ -68,6 +69,10 @@ final class NativeMapView implements NativeMap {
// Flag to indicate destroy was called
private boolean destroyed = false;
+ // Cached to enable lazily set padding.
+ // Whenever an animation is schedule, this value is cleared and the source of truth becomes the core transform state.
+ private double[] edgeInsets;
+
// Holds the pointer to JNI NativeMapView
@Keep
private long nativePtr = 0;
@@ -241,7 +246,8 @@ final class NativeMapView implements NativeMap {
if (checkState("setLatLng")) {
return;
}
- nativeSetLatLng(latLng.getLatitude(), latLng.getLongitude(), duration);
+ nativeSetLatLng(latLng.getLatitude(), latLng.getLongitude(),
+ getAnimationPaddingAndClearCachedInsets(null), duration);
}
@Override
@@ -374,30 +380,20 @@ final class NativeMapView implements NativeMap {
}
@Override
- public void setContentPadding(float[] padding) {
+ public void setContentPadding(double[] padding) {
if (checkState("setContentPadding")) {
return;
}
- // TopLeftBottomRight
- nativeSetContentPadding(
- padding[1] / pixelRatio,
- padding[0] / pixelRatio,
- padding[3] / pixelRatio,
- padding[2] / pixelRatio);
+ this.edgeInsets = padding;
}
@Override
- public float[] getContentPadding() {
+ public double[] getContentPadding() {
if (checkState("getContentPadding")) {
- return new float[] {0, 0, 0, 0};
+ return new double[] {0, 0, 0, 0};
}
- float[] topLeftBottomRight = nativeGetContentPadding();
- return new float[] {
- topLeftBottomRight[1] * pixelRatio,
- topLeftBottomRight[0] * pixelRatio,
- topLeftBottomRight[3] * pixelRatio,
- topLeftBottomRight[2] * pixelRatio
- };
+ // if cached insets are not applied yet, return them, otherwise, get the padding from the camera
+ return edgeInsets != null ? edgeInsets : getCameraPosition().padding;
}
@Override
@@ -672,29 +668,31 @@ final class NativeMapView implements NativeMap {
}
@Override
- public void jumpTo(@NonNull LatLng center, double zoom, double pitch, double angle) {
+ public void jumpTo(@NonNull LatLng center, double zoom, double pitch, double angle, double[] padding) {
if (checkState("jumpTo")) {
return;
}
- nativeJumpTo(angle, center.getLatitude(), center.getLongitude(), pitch, zoom);
+ nativeJumpTo(angle, center.getLatitude(), center.getLongitude(), pitch, zoom,
+ getAnimationPaddingAndClearCachedInsets(padding));
}
@Override
- public void easeTo(@NonNull LatLng center, double zoom, double angle, double pitch, long duration,
+ public void easeTo(@NonNull LatLng center, double zoom, double angle, double pitch, double[] padding, long duration,
boolean easingInterpolator) {
if (checkState("easeTo")) {
return;
}
nativeEaseTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom,
- easingInterpolator);
+ getAnimationPaddingAndClearCachedInsets(padding), easingInterpolator);
}
@Override
- public void flyTo(@NonNull LatLng center, double zoom, double angle, double pitch, long duration) {
+ public void flyTo(@NonNull LatLng center, double zoom, double angle, double pitch, double[] padding, long duration) {
if (checkState("flyTo")) {
return;
}
- nativeFlyTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom);
+ nativeFlyTo(angle, center.getLatitude(), center.getLongitude(), duration, pitch, zoom,
+ getAnimationPaddingAndClearCachedInsets(padding));
}
@Override
@@ -703,7 +701,11 @@ final class NativeMapView implements NativeMap {
if (checkState("getCameraValues")) {
return new CameraPosition.Builder().build();
}
- return nativeGetCameraPosition();
+ if (edgeInsets != null) {
+ return new CameraPosition.Builder(nativeGetCameraPosition()).padding(edgeInsets).build();
+ } else {
+ return nativeGetCameraPosition();
+ }
}
@Override
@@ -1126,7 +1128,7 @@ final class NativeMapView implements NativeMap {
private native void nativeMoveBy(double dx, double dy, long duration);
@Keep
- private native void nativeSetLatLng(double latitude, double longitude, long duration);
+ private native void nativeSetLatLng(double latitude, double longitude, double[] padding, long duration);
@NonNull
@Keep
@@ -1176,12 +1178,6 @@ final class NativeMapView implements NativeMap {
private native void nativeRotateBy(double sx, double sy, double ex, double ey, long duration);
@Keep
- private native void nativeSetContentPadding(float top, float left, float bottom, float right);
-
- @Keep
- private native float[] nativeGetContentPadding();
-
- @Keep
private native void nativeSetBearing(double degrees, long duration);
@Keep
@@ -1270,16 +1266,17 @@ final class NativeMapView implements NativeMap {
private native double nativeGetTopOffsetPixelsForAnnotationSymbol(String symbolName);
@Keep
- private native void nativeJumpTo(double angle, double latitude, double longitude, double pitch, double zoom);
+ private native void nativeJumpTo(double angle, double latitude, double longitude, double pitch, double zoom,
+ double[] padding);
@Keep
private native void nativeEaseTo(double angle, double latitude, double longitude,
- long duration, double pitch, double zoom,
+ long duration, double pitch, double zoom, double[] padding,
boolean easingInterpolator);
@Keep
private native void nativeFlyTo(double angle, double latitude, double longitude,
- long duration, double pitch, double zoom);
+ long duration, double pitch, double zoom, double[] padding);
@NonNull
@Keep
@@ -1437,6 +1434,20 @@ final class NativeMapView implements NativeMap {
return destroyed;
}
+ private double[] getAnimationPaddingAndClearCachedInsets(double[] providedPadding) {
+ if (providedPadding == null) {
+ providedPadding = this.edgeInsets;
+ }
+ this.edgeInsets = null;
+ return providedPadding == null ? null :
+ new double[] {
+ providedPadding[1] / pixelRatio,
+ providedPadding[0] / pixelRatio,
+ providedPadding[3] / pixelRatio,
+ providedPadding[2] / pixelRatio
+ };
+ }
+
public interface ViewCallback {
@Nullable
Bitmap getViewContent();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
index 8ed003b821..76395f9564 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Projection.java
@@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.maps;
import android.graphics.PointF;
import android.support.annotation.FloatRange;
import android.support.annotation.NonNull;
+
import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.constants.GeometryConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
@@ -24,7 +25,6 @@ public class Projection {
private final NativeMap nativeMapView;
@NonNull
private final MapView mapView;
- private int[] contentPadding = new int[] {0, 0, 0, 0};
Projection(@NonNull NativeMap nativeMapView, @NonNull MapView mapView) {
this.nativeMapView = nativeMapView;
@@ -32,8 +32,7 @@ public class Projection {
}
void setContentPadding(int[] contentPadding) {
- this.contentPadding = contentPadding;
- float[] output = new float[contentPadding.length];
+ double[] output = new double[contentPadding.length];
for (int i = 0; i < contentPadding.length; i++) {
output[i] = contentPadding[i];
}
@@ -41,11 +40,15 @@ public class Projection {
}
int[] getContentPadding() {
- return contentPadding;
+ double[] padding = nativeMapView.getCameraPosition().padding;
+ return new int[] {(int) padding[0], (int) padding[1], (int) padding[2], (int) padding[3]};
}
+ /**
+ * @deprecated unused
+ */
+ @Deprecated
public void invalidateContentPadding() {
- setContentPadding(contentPadding);
}
/**
@@ -126,10 +129,11 @@ public class Projection {
top = 0;
bottom = mapView.getHeight();
} else {
- left = (float) contentPadding[0];
- right = (float) (mapView.getWidth() - contentPadding[2]);
- top = (float) contentPadding[1];
- bottom = (float) (mapView.getHeight() - contentPadding[3]);
+ int[] contentPadding = getContentPadding();
+ left = contentPadding[0];
+ right = mapView.getWidth() - contentPadding[2];
+ top = contentPadding[1];
+ bottom = mapView.getHeight() - contentPadding[3];
}
LatLng center = fromScreenLocation(new PointF(left + (right - left) / 2, top + (bottom - top) / 2));
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java
index a707ab13da..b21186050b 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Style.java
@@ -523,14 +523,12 @@ public class Style {
for (Layer layer : layers.values()) {
if (layer != null) {
layer.setDetached();
- nativeMap.removeLayer(layer);
}
}
for (Source source : sources.values()) {
if (source != null) {
source.setDetached();
- nativeMap.removeSource(source);
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
index 1961cf0450..02cd05545d 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Transform.java
@@ -108,7 +108,8 @@ public final class Transform implements MapView.OnCameraDidChangeListener {
if (isValidCameraPosition(cameraPosition)) {
cancelTransitions();
cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
- nativeMap.jumpTo(cameraPosition.target, cameraPosition.zoom, cameraPosition.tilt, cameraPosition.bearing);
+ nativeMap.jumpTo(cameraPosition.target, cameraPosition.zoom, cameraPosition.tilt, cameraPosition.bearing,
+ cameraPosition.padding);
cameraChangeDispatcher.onCameraIdle();
invalidateCameraPosition();
handler.post(new Runnable() {
@@ -135,7 +136,7 @@ public final class Transform implements MapView.OnCameraDidChangeListener {
}
mapView.addOnCameraDidChangeListener(this);
nativeMap.easeTo(cameraPosition.target, cameraPosition.zoom, cameraPosition.bearing, cameraPosition.tilt,
- durationMs, easingInterpolator);
+ cameraPosition.padding, durationMs, easingInterpolator);
}
}
@@ -155,7 +156,7 @@ public final class Transform implements MapView.OnCameraDidChangeListener {
}
mapView.addOnCameraDidChangeListener(this);
nativeMap.flyTo(cameraPosition.target, cameraPosition.zoom, cameraPosition.bearing,
- cameraPosition.tilt, durationMs);
+ cameraPosition.tilt, cameraPosition.padding, durationMs);
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java
index 833a875a09..947ed35555 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/renderer/MapRenderer.java
@@ -8,7 +8,6 @@ import android.support.annotation.NonNull;
import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.log.Logger;
import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.storage.FileSource;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
@@ -36,10 +35,9 @@ public abstract class MapRenderer implements MapRendererScheduler {
public MapRenderer(@NonNull Context context, String localIdeographFontFamily) {
float pixelRatio = context.getResources().getDisplayMetrics().density;
- String programCacheDir = FileSource.getInternalCachePath(context);
// Initialise native peer
- nativeInitialize(this, pixelRatio, programCacheDir, localIdeographFontFamily);
+ nativeInitialize(this, pixelRatio, localIdeographFontFamily);
}
public void onStart() {
@@ -119,7 +117,6 @@ public abstract class MapRenderer implements MapRendererScheduler {
private native void nativeInitialize(MapRenderer self,
float pixelRatio,
- String programCacheDir,
String localIdeographFontFamily);
@CallSuper
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
index 4c70d13b17..1e0069c25f 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/snapshotter/MapSnapshotter.java
@@ -339,11 +339,9 @@ public class MapSnapshotter {
fileSource.setApiBaseUrl(apiBaseUrl);
}
- String programCacheDir = FileSource.getInternalCachePath(context);
-
nativeInitialize(this, fileSource, options.pixelRatio, options.width,
options.height, options.styleUri, options.styleJson, options.region, options.cameraPosition,
- options.showLogo, programCacheDir, options.localIdeographFontFamily);
+ options.showLogo, options.localIdeographFontFamily);
}
/**
@@ -625,8 +623,7 @@ public class MapSnapshotter {
FileSource fileSource, float pixelRatio,
int width, int height, String styleUrl, String styleJson,
LatLngBounds region, CameraPosition position,
- boolean showLogo, String programCacheDir,
- String localIdeographFontFamily);
+ boolean showLogo, String localIdeographFontFamily);
@Keep
protected native void nativeStart();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
index d10c96d81f..34b3308809 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/expressions/Expression.java
@@ -1435,6 +1435,27 @@ public class Expression {
}
/**
+ * Gets the value of a cluster property accumulated so far. Can only be used in the clusterProperties
+ * option of a clustered GeoJSON source.
+ * <p>
+ * Example usage:
+ * </p>
+ * <pre>
+ * {@code
+ * GeoJsonOptions options = new GeoJsonOptions()
+ * .withCluster(true)
+ * .withClusterProperty("max", max(accumulated(), get("max")).toArray(), get("mag").toArray());
+ * }
+ * </pre>
+ *
+ * @return expression
+ * @see <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/#expressions-accumulated">Style specification</a>
+ */
+ public static Expression accumulated() {
+ return new Expression("accumulated");
+ }
+
+ /**
* Gets the kernel density estimation of a pixel in a heatmap layer,
* which is a relative measure of how many data points are crowded around a particular pixel.
* Can only be used in the `heatmap-color` property.
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java
index 1e1b9bafa6..091079ab92 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/GeoJsonOptions.java
@@ -1,9 +1,12 @@
package com.mapbox.mapboxsdk.style.sources;
import android.support.annotation.NonNull;
+import com.mapbox.mapboxsdk.style.expressions.Expression;
import java.util.HashMap;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.ExpressionLiteral;
+
/**
* Builder class for composing GeoJsonSource objects.
*
@@ -109,4 +112,28 @@ public class GeoJsonOptions extends HashMap<String, Object> {
this.put("clusterRadius", clusterRadius);
return this;
}
+
+ /**
+ * An object defining custom properties on the generated clusters if clustering is enabled,
+ * aggregating values from clustered points. Has the form {"property_name": [operator, [map_expression]]} or
+ * {"property_name": [[operator, accumulated, expression], [map_expression]]}
+ *
+ * @param propertyName name of the property
+ * @param operatorExpr operatorExpr is any expression function that accepts at least 2 operands (e.g. "+" or "max").
+ * It accumulates the property value from clusters/points the cluster contains. It can either be
+ * a literal with single operator, or be a valid expression
+ * @param mapExpr map expression produces the value of a single point, it shall be a valid expression
+ * @return the current instance for chaining
+ */
+ @NonNull
+ public GeoJsonOptions withClusterProperty(String propertyName, Expression operatorExpr, Expression mapExpr) {
+ HashMap<String, Object[]> properties = containsKey("clusterProperties")
+ ? (HashMap<String, Object[]>) get("clusterProperties") : new HashMap<String, Object[]>();
+ Object operator = (operatorExpr instanceof ExpressionLiteral)
+ ? ((ExpressionLiteral)operatorExpr).toValue() : operatorExpr.toArray();
+ Object map = mapExpr.toArray();
+ properties.put(propertyName, new Object[]{operator, map});
+ this.put("clusterProperties", properties);
+ return this;
+ }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
index 3e7124a414..ff8a32ac64 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
+++ b/platform/android/MapboxGLAndroidSDK/src/main/res/values/attrs.xml
@@ -7,7 +7,9 @@
<!--Configuration-->
<attr name="mapbox_apiBaseUri" format="string"/>
+ <attr name="mapbox_localIdeographEnabled" format="boolean"/>
<attr name="mapbox_localIdeographFontFamily" format="string"/>
+ <attr name="mapbox_localIdeographFontFamilies" format="reference"/>
<attr name="mapbox_cross_source_collisions" format="boolean"/>
<!--Camera-->
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
index 0c5f3a4be2..6974705fae 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
@@ -1,21 +1,24 @@
package com.mapbox.mapboxsdk.camera;
import android.content.res.TypedArray;
-import android.os.Parcelable;
+import android.os.Parcel;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.utils.MockParcel;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+@RunWith(RobolectricTestRunner.class)
public class CameraPositionTest {
private static final double DELTA = 1e-15;
@@ -23,7 +26,7 @@ public class CameraPositionTest {
@Test
public void testSanity() {
LatLng latLng = new LatLng(1, 2);
- CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0});
assertNotNull("cameraPosition should not be null", cameraPosition);
}
@@ -32,9 +35,10 @@ public class CameraPositionTest {
TypedArray typedArray = null;
CameraPosition cameraPosition = new CameraPosition.Builder(typedArray).build();
assertEquals("bearing should match", -1, cameraPosition.bearing, DELTA);
- assertEquals("latlng should match", null, cameraPosition.target);
+ assertNull("latlng should be null", cameraPosition.target);
assertEquals("tilt should match", -1, cameraPosition.tilt, DELTA);
assertEquals("zoom should match", -1, cameraPosition.zoom, DELTA);
+ assertNull("padding should be null", cameraPosition.padding);
}
@Test
@@ -63,16 +67,16 @@ public class CameraPositionTest {
@Test
public void testToString() {
LatLng latLng = new LatLng(1, 2);
- CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0});
assertEquals("toString should match", "Target: LatLng [latitude=1.0, longitude=2.0, altitude=0.0], Zoom:3.0, "
- + "Bearing:5.0, Tilt:4.0", cameraPosition.toString());
+ + "Bearing:5.0, Tilt:4.0, Padding:[0.0, 500.0, 0.0, 0.0]", cameraPosition.toString());
}
@Test
public void testHashcode() {
LatLng latLng = new LatLng(1, 2);
- CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
- assertEquals("hashCode should match", -1007681505, cameraPosition.hashCode());
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0});
+ assertEquals("hashCode should match", -420915327, cameraPosition.hashCode());
}
@Test
@@ -86,11 +90,12 @@ public class CameraPositionTest {
@Test
public void testEquals() {
LatLng latLng = new LatLng(1, 2);
- CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5);
- CameraPosition cameraPositionBearing = new CameraPosition(latLng, 3, 4, 9);
- CameraPosition cameraPositionTilt = new CameraPosition(latLng, 3, 9, 5);
- CameraPosition cameraPositionZoom = new CameraPosition(latLng, 9, 4, 5);
- CameraPosition cameraPositionTarget = new CameraPosition(new LatLng(), 3, 4, 5);
+ CameraPosition cameraPosition = new CameraPosition(latLng, 3, 4, 5, new double[] {0, 500, 0, 0});
+ CameraPosition cameraPositionBearing = new CameraPosition(latLng, 3, 4, 9, new double[] {0, 500, 0, 0});
+ CameraPosition cameraPositionTilt = new CameraPosition(latLng, 3, 9, 5, new double[] {0, 500, 0, 0});
+ CameraPosition cameraPositionZoom = new CameraPosition(latLng, 9, 4, 5, new double[] {0, 500, 0, 0});
+ CameraPosition cameraPositionTarget = new CameraPosition(new LatLng(), 3, 4, 5, new double[] {0, 500, 0, 0});
+ CameraPosition cameraPositionPadding = new CameraPosition(new LatLng(), 3, 4, 5, new double[] {0, 501, 0, 0});
assertEquals("cameraPosition should match itself", cameraPosition, cameraPosition);
assertNotEquals("cameraPosition should not match null", null, cameraPosition);
@@ -99,12 +104,17 @@ public class CameraPositionTest {
assertNotEquals("cameraPosition should not match for tilt", cameraPositionTilt, cameraPosition);
assertNotEquals("cameraPosition should not match for zoom", cameraPositionZoom, cameraPosition);
assertNotEquals("cameraPosition should not match for target", cameraPositionTarget, cameraPosition);
+ assertNotEquals("cameraPosition should not match for padding", cameraPositionPadding, cameraPosition);
}
@Test
public void testParcelable() {
- CameraPosition object = new CameraPosition(new LatLng(1, 2), 3, 4, 5);
- Parcelable parcelable = MockParcel.obtain(object);
- assertEquals("Parcel should match original object", parcelable, object);
+ CameraPosition cameraPosition1 = new CameraPosition(new LatLng(1, 2), 3, 4, 5, new double[] {0, 500, 0, 0});
+ Parcel parcel = Parcel.obtain();
+ cameraPosition1.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ CameraPosition cameraPosition2 = CameraPosition.CREATOR.createFromParcel(parcel);
+ assertEquals("Parcel should match original object", cameraPosition1, cameraPosition2);
}
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java
index 0fbc47df55..ed2d015d85 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/location/LocationLayerControllerTest.java
@@ -632,6 +632,41 @@ public class LocationLayerControllerTest {
verify(internalRenderModeChangedListener, times(1)).onRenderModeChanged(RenderMode.GPS);
}
+ @Test
+ public void layerHidden_renderModeChanged_layerShown_foregroundIconUpdated() {
+ OnRenderModeChangedListener internalRenderModeChangedListener = mock(OnRenderModeChangedListener.class);
+ LayerSourceProvider sourceProvider = buildLayerProvider();
+ when(sourceProvider.generateSource(any(Feature.class))).thenReturn(mock(GeoJsonSource.class));
+ LocationComponentOptions options = mock(LocationComponentOptions.class);
+ int drawableResId = 123;
+ int tintColor = 456;
+ when(options.foregroundDrawable()).thenReturn(drawableResId);
+ when(options.foregroundTintColor()).thenReturn(tintColor);
+ LayerBitmapProvider bitmapProvider = mock(LayerBitmapProvider.class);
+ Bitmap bitmap = mock(Bitmap.class);
+ when(bitmapProvider.generateBitmap(drawableResId, tintColor)).thenReturn(bitmap);
+
+ LocationLayerController controller =
+ new LocationLayerController(mapboxMap, mapboxMap.getStyle(), sourceProvider, buildFeatureProvider(options),
+ bitmapProvider, options, internalRenderModeChangedListener);
+
+ verify(style).addImage(FOREGROUND_ICON, bitmap);
+
+ int drawableGpsResId = 789;
+ when(options.gpsDrawable()).thenReturn(drawableGpsResId);
+
+ Bitmap bitmapGps = mock(Bitmap.class);
+ when(bitmapProvider.generateBitmap(drawableGpsResId, tintColor)).thenReturn(bitmapGps);
+
+ controller.hide();
+
+ controller.setRenderMode(RenderMode.GPS);
+
+ controller.show();
+
+ verify(style).addImage(FOREGROUND_ICON, bitmapGps);
+ }
+
private LayerFeatureProvider buildFeatureProvider(@NonNull LocationComponentOptions options) {
LayerFeatureProvider provider = mock(LayerFeatureProvider.class);
when(provider.generateLocationFeature(null, options)).thenReturn(mock(Feature.class));
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt
new file mode 100644
index 0000000000..ee8024257f
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsAttrsTest.kt
@@ -0,0 +1,101 @@
+package com.mapbox.mapboxsdk.maps
+
+import android.content.Context
+import android.content.res.Resources
+import android.content.res.TypedArray
+import com.mapbox.mapboxsdk.R
+import io.mockk.MockKAnnotations
+import io.mockk.every
+import io.mockk.impl.annotations.RelaxedMockK
+import io.mockk.verify
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.robolectric.RobolectricTestRunner
+
+@RunWith(RobolectricTestRunner::class)
+class MapboxMapOptionsAttrsTest {
+
+ @RelaxedMockK
+ private lateinit var options: MapboxMapOptions
+
+ @RelaxedMockK
+ private lateinit var typedArray: TypedArray
+
+ @RelaxedMockK
+ private lateinit var context: Context
+
+ @RelaxedMockK
+ private lateinit var resources: Resources
+
+ @Before
+ fun setUp() {
+ MockKAnnotations.init(this)
+ every {
+ context.resources
+ }.returns(resources)
+ }
+
+ @Test
+ fun enabledLocalIdeographFontFamily() {
+ mockEnableLocalIdeograph(enabled = true)
+
+ val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
+
+ verify(exactly = 1) {
+ options.localIdeographFontFamily(any())
+ }
+ }
+
+ @Test
+ fun localIdeographFontFamily() {
+ mockEnableLocalIdeograph(enabled = true)
+
+ val font = "foo"
+ mockLocalIdeographString(font)
+
+ val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
+
+ verify(exactly = 1) {
+ options.localIdeographFontFamily(font)
+ }
+ }
+
+ @Test
+ fun localIdeographFontFamilies() {
+ mockEnableLocalIdeograph(enabled = true)
+
+ val fonts = arrayOf("foo", "bar")
+ mockLocalIdeographStringArray(fonts)
+
+ val options = MapboxMapOptions.createFromAttributes(options, context, typedArray)
+
+ verify(exactly = 1) {
+ options.localIdeographFontFamily(*fonts)
+ }
+ }
+
+ private fun mockEnableLocalIdeograph(enabled: Boolean) {
+ every {
+ typedArray.getBoolean(R.styleable.mapbox_MapView_mapbox_localIdeographEnabled, true)
+ }.returns(enabled)
+ }
+
+ private fun mockLocalIdeographString(font: String) {
+ every {
+ typedArray.getString(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamily)
+ }.returns(font)
+ }
+
+ private fun mockLocalIdeographStringArray(fonts: Array<String>) {
+ val resId = 9000
+
+ every {
+ typedArray.getResourceId(R.styleable.mapbox_MapView_mapbox_localIdeographFontFamilies, 0)
+ }.returns(resId)
+
+ every {
+ resources.getStringArray(resId)
+ }.returns(fonts)
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleTest.kt
index d618f17500..a5070ae5c0 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleTest.kt
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/StyleTest.kt
@@ -405,22 +405,4 @@ class StyleTest {
Assert.assertEquals("Layer that failed to be added shouldn't be cached", layer1, mapboxMap.style!!.getLayer("layer1"))
}
}
-
- @Test
- fun testClearRemovesSourcesFirst() {
- val source1 = mockk<GeoJsonSource>(relaxed = true)
- every { source1.id } returns "source1"
- val layer1 = mockk<SymbolLayer>(relaxed = true)
- every { layer1.id } returns "layer1"
-
- val builder = Style.Builder().withLayer(layer1).withSource(source1)
- mapboxMap.setStyle(builder)
- mapboxMap.notifyStyleLoaded()
- mapboxMap.setStyle(Style.MAPBOX_STREETS)
-
- verifyOrder {
- nativeMapView.removeLayer(layer1)
- nativeMapView.removeSource(source1)
- }
- }
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt
index 4f6e915d1f..511101ecb2 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TransformTest.kt
@@ -25,8 +25,8 @@ class TransformTest {
every { nativeMapView.isDestroyed } returns false
every { nativeMapView.cameraPosition } returns CameraPosition.DEFAULT
every { nativeMapView.cancelTransitions() } answers {}
- every { nativeMapView.jumpTo(any(), any(), any(), any()) } answers {}
- every { nativeMapView.flyTo(any(), any(), any(), any(), any()) } answers {}
+ every { nativeMapView.jumpTo(any(), any(), any(), any(), any()) } answers {}
+ every { nativeMapView.flyTo(any(), any(), any(), any(), any(), any()) } answers {}
every { nativeMapView.minZoom = any() } answers {}
every { nativeMapView.maxZoom = any() } answers {}
}
@@ -44,7 +44,7 @@ class TransformTest {
val update = CameraUpdateFactory.newCameraPosition(expected)
transform.moveCamera(mapboxMap, update, callback)
- verify { nativeMapView.jumpTo(target, -1.0, -1.0, -1.0) }
+ verify { nativeMapView.jumpTo(target, -1.0, -1.0, -1.0, null) }
verify { callback.onFinish() }
}
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt
index 994a41938b..5db7b0b0f9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/module/http/HttpRequestUrlTest.kt
@@ -20,14 +20,14 @@ class HttpRequestUrlTest {
@Test
fun testOfflineFlagMapboxCom() {
- val expected = "http://mapbox.com/path/of/no/return.pbf?sku=foobar&offline=true"
+ val expected = "http://mapbox.com/path/of/no/return.pbf?offline=true"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.com", "http://mapbox.com/path/of/no/return.pbf", 0, true)
assertEquals(expected, actual)
}
@Test
fun testOfflineFlagMapboxCn() {
- val expected = "http://mapbox.cn/path/of/no/return.pbf?sku=foobar&offline=true"
+ val expected = "http://mapbox.cn/path/of/no/return.pbf?offline=true"
val actual = HttpRequestUrl.buildResourceUrl("mapbox.cn", "http://mapbox.cn/path/of/no/return.pbf", 0, true)
assertEquals(expected, actual)
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt
index 50b9626edc..f840e970d1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactoryTest.kt
@@ -1,11 +1,15 @@
package com.mapbox.mapboxsdk.camera
+import android.graphics.PointF
+import android.support.test.annotation.UiThreadTest
import android.support.test.runner.AndroidJUnit4
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.geometry.LatLngBounds
import com.mapbox.mapboxsdk.testapp.activity.BaseTest
import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity
+import org.junit.Assert
import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
@@ -17,127 +21,166 @@ class CameraUpdateFactoryTest : BaseTest() {
}
@Test
+ @UiThreadTest
fun testLatLngBoundsUntiltedUnrotated() {
- rule.runOnUiThread {
- mapboxMap.cameraPosition = CameraPosition.Builder()
- .target(LatLng(60.0, 24.0))
- .bearing(0.0)
- .tilt(0.0)
- .build()
-
- val bounds: LatLngBounds = LatLngBounds.Builder()
- .include(LatLng(62.0, 26.0))
- .include(LatLng(58.0, 22.0))
- .build()
-
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
-
- val cameraPosition = mapboxMap.cameraPosition
- assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
- assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
- assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
- assertEquals("zoom should match", 5.5, cameraPosition.zoom, 0.1)
- assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
- }
+ mapboxMap.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(60.0, 24.0))
+ .bearing(0.0)
+ .tilt(0.0)
+ .build()
+
+ val bounds: LatLngBounds = LatLngBounds.Builder()
+ .include(LatLng(62.0, 26.0))
+ .include(LatLng(58.0, 22.0))
+ .build()
+
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
+
+ val cameraPosition = mapboxMap.cameraPosition
+ assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
+ assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
+ assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
+ assertEquals("zoom should match", 5.5, cameraPosition.zoom, 0.1)
+ assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
}
@Test
+ @UiThreadTest
fun testLatLngBoundsTilted() {
- rule.runOnUiThread {
- mapboxMap.cameraPosition = CameraPosition.Builder()
- .target(LatLng(60.0, 24.0))
- .bearing(0.0)
- .tilt(45.0)
- .build()
-
- val bounds: LatLngBounds = LatLngBounds.Builder()
- .include(LatLng(62.0, 26.0))
- .include(LatLng(58.0, 22.0))
- .build()
-
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
-
- val cameraPosition = mapboxMap.cameraPosition
- assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
- assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
- assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
- assertEquals("zoom should match", 6.0, cameraPosition.zoom, 0.1)
- assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
- }
+ mapboxMap.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(60.0, 24.0))
+ .bearing(0.0)
+ .tilt(45.0)
+ .build()
+
+ val bounds: LatLngBounds = LatLngBounds.Builder()
+ .include(LatLng(62.0, 26.0))
+ .include(LatLng(58.0, 22.0))
+ .build()
+
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
+
+ val cameraPosition = mapboxMap.cameraPosition
+ assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
+ assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
+ assertEquals("bearing should match:", 0.0, cameraPosition.bearing, 0.1)
+ assertEquals("zoom should match", 6.0, cameraPosition.zoom, 0.1)
+ assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
}
@Test
+ @UiThreadTest
fun testLatLngBoundsRotated() {
- rule.runOnUiThread {
- mapboxMap.cameraPosition = CameraPosition.Builder()
- .target(LatLng(60.0, 24.0))
- .bearing(30.0)
- .tilt(0.0)
- .build()
-
- val bounds: LatLngBounds = LatLngBounds.Builder()
- .include(LatLng(62.0, 26.0))
- .include(LatLng(58.0, 22.0))
- .build()
-
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
-
- val cameraPosition = mapboxMap.cameraPosition
- assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
- assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
- assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
- assertEquals("zoom should match", 5.3, cameraPosition.zoom, 0.1)
- assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
- }
+ mapboxMap.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(60.0, 24.0))
+ .bearing(30.0)
+ .tilt(0.0)
+ .build()
+
+ val bounds: LatLngBounds = LatLngBounds.Builder()
+ .include(LatLng(62.0, 26.0))
+ .include(LatLng(58.0, 22.0))
+ .build()
+
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
+
+ val cameraPosition = mapboxMap.cameraPosition
+ assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
+ assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
+ assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
+ assertEquals("zoom should match", 5.3, cameraPosition.zoom, 0.1)
+ assertEquals("tilt should match:", 0.0, cameraPosition.tilt, 0.1)
}
@Test
+ @UiThreadTest
fun testLatLngBoundsTiltedRotated() {
- rule.runOnUiThread {
- mapboxMap.cameraPosition = CameraPosition.Builder()
- .target(LatLng(60.0, 24.0))
- .bearing(30.0)
- .tilt(45.0)
- .build()
-
- val bounds: LatLngBounds = LatLngBounds.Builder()
- .include(LatLng(62.0, 26.0))
- .include(LatLng(58.0, 22.0))
- .build()
-
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
-
- val cameraPosition = mapboxMap.cameraPosition
- assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
- assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
- assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
- assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
- assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
- }
+ mapboxMap.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(60.0, 24.0))
+ .bearing(30.0)
+ .tilt(45.0)
+ .build()
+
+ val bounds: LatLngBounds = LatLngBounds.Builder()
+ .include(LatLng(62.0, 26.0))
+ .include(LatLng(58.0, 22.0))
+ .build()
+
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0))
+
+ val cameraPosition = mapboxMap.cameraPosition
+ assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
+ assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
+ assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
+ assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
+ assertEquals("tilt should match:", 45.0, cameraPosition.tilt, 0.1)
}
@Test
+ @UiThreadTest
fun testLatLngBoundsWithProvidedTiltAndRotation() {
- rule.runOnUiThread {
- mapboxMap.cameraPosition = CameraPosition.Builder()
- .target(LatLng(60.0, 24.0))
- .bearing(0.0)
- .tilt(0.0)
- .build()
-
- val bounds: LatLngBounds = LatLngBounds.Builder()
- .include(LatLng(62.0, 26.0))
- .include(LatLng(58.0, 22.0))
- .build()
-
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30.0, 40.0, 0))
-
- val cameraPosition = mapboxMap.cameraPosition
- assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
- assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
- assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
- assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
- assertEquals("tilt should match:", 40.0, cameraPosition.tilt, 0.1)
- }
+ mapboxMap.cameraPosition = CameraPosition.Builder()
+ .target(LatLng(60.0, 24.0))
+ .bearing(0.0)
+ .tilt(0.0)
+ .build()
+
+ val bounds: LatLngBounds = LatLngBounds.Builder()
+ .include(LatLng(62.0, 26.0))
+ .include(LatLng(58.0, 22.0))
+ .build()
+
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 30.0, 40.0, 0))
+
+ val cameraPosition = mapboxMap.cameraPosition
+ assertEquals("latitude should match:", 60.0, cameraPosition.target.latitude, 0.1)
+ assertEquals("longitude should match:", 24.0, cameraPosition.target.longitude, 0.1)
+ assertEquals("bearing should match:", 30.0, cameraPosition.bearing, 0.1)
+ assertEquals("zoom should match", 5.6, cameraPosition.zoom, 0.1)
+ assertEquals("tilt should match:", 40.0, cameraPosition.tilt, 0.1)
+ }
+
+ @Test
+ @UiThreadTest
+ fun withPadding_cameraInvalidated_paddingPersisting() {
+ val initialCameraPosition = mapboxMap.cameraPosition
+ val initialPoint = mapboxMap.projection.toScreenLocation(initialCameraPosition.target)
+
+ val bottomPadding = mapView.height / 4
+ val leftPadding = mapView.width / 4
+ val padding = doubleArrayOf(leftPadding.toDouble(), 0.0, 0.0, bottomPadding.toDouble())
+ mapboxMap.moveCamera(CameraUpdateFactory.paddingTo(leftPadding.toDouble(), 0.0, 0.0, bottomPadding.toDouble()))
+
+ Assert.assertArrayEquals(intArrayOf(leftPadding, 0, 0, bottomPadding), mapboxMap.padding)
+
+ val resultingCameraPosition = mapboxMap.cameraPosition
+ assertEquals(initialCameraPosition.target, resultingCameraPosition.target)
+ assertEquals(
+ PointF(initialPoint.x + leftPadding / 2, initialPoint.y - bottomPadding / 2),
+ mapboxMap.projection.toScreenLocation(resultingCameraPosition.target)
+ )
+ Assert.assertArrayEquals(padding, resultingCameraPosition.padding, 0.0001)
+ }
+
+ @Test
+ @UiThreadTest
+ fun withLatLngPadding_cameraInvalidated_paddingPersisting() {
+ val expectedTarget = LatLng(2.0, 2.0)
+
+ val topPadding = mapView.height / 4
+ val rightPadding = mapView.width / 4
+ val padding = doubleArrayOf(0.0, topPadding.toDouble(), rightPadding.toDouble(), 0.0)
+ mapboxMap.moveCamera(CameraUpdateFactory.newLatLngPadding(expectedTarget, 0.0, topPadding.toDouble(), rightPadding.toDouble(), 0.0))
+
+ Assert.assertArrayEquals(intArrayOf(0, topPadding, rightPadding, 0), mapboxMap.padding)
+
+ val resultingCameraPosition = mapboxMap.cameraPosition
+ assertEquals(expectedTarget.latitude, resultingCameraPosition.target.latitude, 0.1)
+ assertEquals(expectedTarget.longitude, resultingCameraPosition.target.longitude, 0.1)
+
+ val centerLatLng = mapboxMap.projection.fromScreenLocation(PointF((mapView.width / 2).toFloat(), (mapView.height / 2).toFloat()))
+ assertTrue(centerLatLng.latitude > resultingCameraPosition.target.latitude)
+ assertTrue(centerLatLng.longitude > resultingCameraPosition.target.longitude)
+ Assert.assertArrayEquals(padding, resultingCameraPosition.padding, 0.0001)
}
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapInstrumentationTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapInstrumentationTest.kt
deleted file mode 100644
index e93f54161e..0000000000
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/MapboxMapInstrumentationTest.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-package com.mapbox.mapboxsdk.maps
-
-import android.graphics.PointF
-import android.support.test.runner.AndroidJUnit4
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory
-import com.mapbox.mapboxsdk.geometry.LatLng
-import com.mapbox.mapboxsdk.testapp.activity.BaseTest
-import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity
-import org.junit.Assert.assertArrayEquals
-import org.junit.Assert.assertEquals
-import org.junit.Test
-import org.junit.runner.RunWith
-
-@RunWith(AndroidJUnit4::class)
-class MapboxMapInstrumentationTest : BaseTest() {
-
- override fun getActivityClass(): Class<*> {
- return DeviceIndependentTestActivity::class.java
- }
-
- @Test
- fun setPadding_cameraInvalidated() {
- rule.runOnUiThread {
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 0.0), 10.0))
- val initialCameraPosition = mapboxMap.cameraPosition
- val initialPoint = mapboxMap.projection.toScreenLocation(initialCameraPosition.target)
-
- val bottomPadding = mapView.height / 4
- val leftPadding = mapView.width / 4
- mapboxMap.setPadding(leftPadding, 0, 0, bottomPadding)
-
- val resultingCameraPosition = mapboxMap.cameraPosition
- assertArrayEquals(intArrayOf(leftPadding, 0, 0, bottomPadding), mapboxMap.padding)
- assertEquals(initialCameraPosition, resultingCameraPosition)
- assertEquals(
- PointF(initialPoint.x + leftPadding / 2, initialPoint.y - bottomPadding / 2),
- mapboxMap.projection.toScreenLocation(resultingCameraPosition.target)
- )
- }
- }
-} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt
index d5834db553..b13bb6b796 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/NativeMapViewTest.kt
@@ -15,6 +15,7 @@ import com.mapbox.mapboxsdk.style.layers.TransitionOptions
import com.mapbox.mapboxsdk.testapp.utils.TestConstants
import junit.framework.Assert.*
import org.junit.After
+import org.junit.Assert
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -30,6 +31,7 @@ class NativeMapViewTest : AppCenter() {
const val BEARING_TEST = 60.0
const val PITCH_TEST = 40.0
const val ZOOM_TEST = 16.0
+ val PADDING_TEST = doubleArrayOf(80.0, 150.0, 0.0, 0.0)
const val WIDTH = 500
const val HEIGHT = WIDTH
val LATLNG_TEST = LatLng(12.0, 34.0)
@@ -88,6 +90,18 @@ class NativeMapViewTest : AppCenter() {
@Test
@UiThreadTest
+ fun testLatLngPadding() {
+ val expected = LATLNG_TEST
+ nativeMapView.contentPadding = PADDING_TEST
+ nativeMapView.setLatLng(expected, 0)
+ val actual = nativeMapView.latLng
+ assertEquals("Latitude should match", expected.latitude, actual.latitude, DELTA)
+ assertEquals("Longitude should match", expected.longitude, actual.longitude, DELTA)
+ Assert.assertArrayEquals(PADDING_TEST, nativeMapView.cameraPosition.padding, DELTA)
+ }
+
+ @Test
+ @UiThreadTest
fun testLatLngDefault() {
val expected = LatLng()
val actual = nativeMapView.latLng
@@ -145,14 +159,18 @@ class NativeMapViewTest : AppCenter() {
.target(LATLNG_TEST)
.tilt(PITCH_TEST)
.zoom(ZOOM_TEST)
+ .padding(PADDING_TEST)
.build()
- nativeMapView.jumpTo(LATLNG_TEST, ZOOM_TEST, PITCH_TEST, BEARING_TEST)
+ // verify that the lazily set padding is ignored when a value is provided with the camera
+ nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
+ nativeMapView.jumpTo(LATLNG_TEST, ZOOM_TEST, PITCH_TEST, BEARING_TEST, PADDING_TEST)
val actual = nativeMapView.cameraPosition
assertEquals("Latitude should match", expected.target.latitude, actual.target.latitude, DELTA)
assertEquals("Longitude should match", expected.target.longitude, actual.target.longitude, DELTA)
assertEquals("Bearing should match", expected.bearing, actual.bearing, DELTA)
assertEquals("Pitch should match", expected.tilt, actual.tilt, DELTA)
assertEquals("Zoom should match", expected.zoom, actual.zoom, DELTA)
+ Assert.assertArrayEquals(expected.padding, actual.padding, DELTA)
}
@Test
@@ -206,7 +224,7 @@ class NativeMapViewTest : AppCenter() {
@Test
@UiThreadTest
fun testSetContentPadding() {
- val expected = floatArrayOf(1.0f, 2.0f, 3.0f, 4.0f)
+ val expected = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
nativeMapView.contentPadding = expected
val actual = nativeMapView.contentPadding
assertEquals("Left should match", expected[0], actual[0])
@@ -258,14 +276,18 @@ class NativeMapViewTest : AppCenter() {
.tilt(30.0)
.target(LatLng(12.0, 14.0))
.bearing(20.0)
+ .padding(PADDING_TEST)
.build()
- nativeMapView.flyTo(expected.target, expected.zoom, expected.bearing, expected.tilt, 0)
+ // verify that the lazily set padding is ignored when a value is provided with the camera
+ nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
+ nativeMapView.flyTo(expected.target, expected.zoom, expected.bearing, expected.tilt, PADDING_TEST, 0)
val actual = nativeMapView.cameraPosition
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
assertEquals("Latitude should match", expected.target.latitude, actual.target.latitude, TestConstants.LAT_LNG_DELTA)
assertEquals("Longitude should match", expected.target.longitude, actual.target.longitude, TestConstants.LAT_LNG_DELTA)
assertEquals("Tilt should match", expected.tilt, actual.tilt, TestConstants.TILT_DELTA)
assertEquals("Zoom should match", expected.zoom, actual.zoom, TestConstants.ZOOM_DELTA)
+ Assert.assertArrayEquals(expected.padding, actual.padding, DELTA)
}
@Test
@@ -276,14 +298,18 @@ class NativeMapViewTest : AppCenter() {
.tilt(30.0)
.target(LatLng(12.0, 14.0))
.bearing(20.0)
+ .padding(PADDING_TEST)
.build()
- nativeMapView.easeTo(expected.target, expected.zoom, expected.bearing, expected.tilt, 0, false)
+ // verify that the lazily set padding is ignored when a value is provided with the camera
+ nativeMapView.contentPadding = doubleArrayOf(1.0, 2.0, 3.0, 4.0)
+ nativeMapView.easeTo(expected.target, expected.zoom, expected.bearing, expected.tilt, PADDING_TEST, 0, false)
val actual = nativeMapView.cameraPosition
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
assertEquals("Latitude should match", expected.target.latitude, actual.target.latitude, TestConstants.LAT_LNG_DELTA)
assertEquals("Longitude should match", expected.target.longitude, actual.target.longitude, TestConstants.LAT_LNG_DELTA)
assertEquals("Tilt should match", expected.tilt, actual.tilt, TestConstants.TILT_DELTA)
assertEquals("Zoom should match", expected.zoom, actual.zoom, TestConstants.ZOOM_DELTA)
+ Assert.assertArrayEquals(expected.padding, actual.padding, DELTA)
}
@Test
@@ -294,8 +320,9 @@ class NativeMapViewTest : AppCenter() {
.tilt(0.0)
.target(LatLng(0.0, 0.0))
.bearing(0.0)
+ .padding(PADDING_TEST)
.build()
- nativeMapView.jumpTo(LatLng(1.0, 2.0), 12.0, 23.0, 1.0)
+ nativeMapView.jumpTo(LatLng(1.0, 2.0), 12.0, 23.0, 1.0, PADDING_TEST)
nativeMapView.resetPosition()
val actual = nativeMapView.cameraPosition
assertEquals("Bearing should match", expected.bearing, actual.bearing, TestConstants.BEARING_DELTA)
@@ -303,6 +330,7 @@ class NativeMapViewTest : AppCenter() {
assertEquals("Longitude should match", expected.target.longitude, actual.target.longitude, TestConstants.LAT_LNG_DELTA)
assertEquals("Tilt should match", expected.tilt, actual.tilt, TestConstants.TILT_DELTA)
assertEquals("Zoom should match", expected.zoom, actual.zoom, TestConstants.ZOOM_DELTA)
+ Assert.assertArrayEquals(expected.padding, actual.padding, DELTA)
}
@Test
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt
index 14722ea37c..12dff5d452 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/maps/VisibleRegionTest.kt
@@ -7,7 +7,8 @@ import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke
import com.mapbox.mapboxsdk.testapp.activity.BaseTest
import com.mapbox.mapboxsdk.testapp.activity.espresso.PixelTestActivity
-import org.junit.Assert.*
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
import org.junit.Test
class VisibleRegionTest : BaseTest() {
@@ -68,7 +69,7 @@ class VisibleRegionTest : BaseTest() {
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(1, filtered.size)
+ assertTrue(filtered.size == 1)
assertTrue(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)))
}
}
@@ -87,18 +88,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 4f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width * 3f / 4f, 0f)
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(mapView.width / 4, 0, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
- val filtered = latLngs.filter {
- visibleRegion.latLngBounds.contains(it)
- }
- assertEquals(5, filtered.size)
+ val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f)))
}
}
@@ -117,16 +114,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 4f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height * 3f / 4f)
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, mapView.height / 4, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f)))
}
}
@@ -145,16 +140,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 4f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width * 3f / 4f, 0f)
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, mapView.width / 4, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)))
}
}
@@ -173,16 +166,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 4f),
- mapboxMap.getLatLngFromScreenCoords(0f, mapView.height * 3f / 4f)
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, 0, mapView.height / 4)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat())))
}
}
@@ -236,7 +227,7 @@ class VisibleRegionTest : BaseTest() {
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(1, filtered.size)
+ assertTrue(filtered.size == 1)
assertTrue(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)))
}
}
@@ -258,17 +249,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 4f, 0f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width * 3f / 4f, mapView.height / 2f)
- .also { it.longitude += 360 }
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(mapView.width / 4, 0, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f)))
}
}
@@ -278,6 +266,7 @@ class VisibleRegionTest : BaseTest() {
validateTestSetup()
invoke(mapboxMap) { ui: UiController, mapboxMap: MapboxMap ->
mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(LatLng(0.0, 180.0), 8.0))
+ ui.loopMainThreadForAtLeast(5000)
val latLngs = listOf(
mapboxMap.getLatLngFromScreenCoords(0f, 0f),
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f),
@@ -290,17 +279,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 4f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height * 3f / 4f)
- .also { it.longitude += 360 }
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, mapView.height / 4, 0, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, 0f)))
}
}
@@ -322,17 +308,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 4f, 0f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width * 3f / 4f, mapView.height / 2f)
- .also { it.longitude += 360 }
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, mapView.width / 4, 0)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height / 2f)))
}
}
@@ -354,17 +337,14 @@ class VisibleRegionTest : BaseTest() {
mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height.toFloat()),
mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f),
- mapboxMap.getLatLngFromScreenCoords(0f, mapView.height / 4f),
- mapboxMap.getLatLngFromScreenCoords(mapView.width.toFloat(), mapView.height * 3f / 4f)
- .also { it.longitude += 360 }
+ mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height / 2f)
)
mapboxMap.setPadding(0, 0, 0, mapView.height / 4)
val visibleRegion = mapboxMap.projection.getVisibleRegion(false)
val filtered = latLngs.filter { visibleRegion.latLngBounds.contains(it) }
- assertEquals(5, filtered.size)
+ assertTrue(filtered.size == 6)
assertFalse(filtered.contains(mapboxMap.getLatLngFromScreenCoords(mapView.width / 2f, mapView.height.toFloat())))
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
index 625e37798f..69cf1264bf 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraAnimateTest.java
@@ -1,297 +1,11 @@
package com.mapbox.mapboxsdk.testapp.camera;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.IdlingRegistry;
-import android.support.test.espresso.idling.CountingIdlingResource;
-
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.testapp.activity.BaseTest;
-import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-
-import org.junit.Test;
-
-import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke;
-import static org.junit.Assert.assertEquals;
-
-public class CameraAnimateTest extends BaseTest {
-
- private final CountingIdlingResource animationIdlingResource =
- new CountingIdlingResource("animation_idling_resource");
-
- @Override
- protected Class getActivityClass() {
- return DeviceIndependentTestActivity.class;
- }
+public class CameraAnimateTest extends CameraTest {
@Override
- public void beforeTest() {
- super.beforeTest();
- IdlingRegistry.getInstance().register(animationIdlingResource);
- }
-
- @Test
- public void testAnimateToCameraPositionTarget() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- LatLng moveTarget = new LatLng(1, 1);
- CameraPosition initialPosition = new CameraPosition.Builder().target(
- new LatLng()).zoom(zoom).bearing(0).tilt(0).build();
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Default camera position should match default", cameraPosition, initialPosition);
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.newLatLng(moveTarget), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToCameraPositionTargetZoom() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float moveZoom = 15.5f;
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.newLatLngZoom(moveTarget, moveZoom), new MapboxMap
- .CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToCameraPosition() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
- final float moveZoom = 15.5f;
- final float moveTilt = 45.5f;
- final float moveBearing = 12.5f;
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(
- new CameraPosition.Builder()
- .target(moveTarget)
- .zoom(moveZoom)
- .tilt(moveTilt)
- .bearing(moveBearing)
- .build()),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToBounds() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng centerBounds = new LatLng(1, 1);
- LatLng cornerOne = new LatLng();
- LatLng cornerTwo = new LatLng(2, 2);
- final LatLngBounds.Builder builder = new LatLngBounds.Builder();
- builder.include(cornerOne);
- builder.include(cornerTwo);
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 0), new MapboxMap
- .CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
+ void executeCameraMovement(CameraUpdate cameraUpdate, MapboxMap.CancelableCallback callback) {
+ mapboxMap.animateCamera(cameraUpdate, callback);
}
-
- @Test
- public void testAnimateToZoomIn() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.zoomIn(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToZoomOut() {
- validateTestSetup();
- float zoom = 10.0f;
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- animationIdlingResource.increment();
- mapboxMap.animateCamera(
- CameraUpdateFactory.newLatLngZoom(new LatLng(), zoom),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- invoke(mapboxMap, ((uiController, mapboxMap1) -> {
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.zoomOut(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- }));
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToZoomBy() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- final float zoomBy = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.zoomBy(zoomBy), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testAnimateToZoomTo() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float zoomTo = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.animateCamera(CameraUpdateFactory.zoomTo(zoomTo), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Override
- public void afterTest() {
- super.afterTest();
- IdlingRegistry.getInstance().unregister(animationIdlingResource);
- }
-
- private void verifyCameraPosition(MapboxMap mapboxMap, LatLng moveTarget, double moveZoom, double moveBearing,
- double moveTilt) {
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Moved camera position latitude should match", cameraPosition.target.getLatitude(),
- moveTarget.getLatitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved camera position longitude should match", cameraPosition.target.getLongitude(),
- moveTarget.getLongitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.zoom, moveZoom, TestConstants.ZOOM_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.tilt, moveTilt, TestConstants.TILT_DELTA);
- assertEquals("Moved bearing should match", cameraPosition.bearing, moveBearing, TestConstants.BEARING_DELTA);
- }
-}
-
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
index ae81dc1302..be3b18ef8b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraEaseTest.java
@@ -1,294 +1,12 @@
package com.mapbox.mapboxsdk.testapp.camera;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.IdlingRegistry;
-import android.support.test.espresso.idling.CountingIdlingResource;
-
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.testapp.activity.BaseTest;
-import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-
-import org.junit.Test;
-
-import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke;
-import static org.junit.Assert.assertEquals;
-
-public class CameraEaseTest extends BaseTest {
- private final CountingIdlingResource animationIdlingResource =
- new CountingIdlingResource("animation_idling_resource");
-
- @Override
- protected Class getActivityClass() {
- return DeviceIndependentTestActivity.class;
- }
+public class CameraEaseTest extends CameraTest {
@Override
- public void beforeTest() {
- super.beforeTest();
- IdlingRegistry.getInstance().register(animationIdlingResource);
- }
-
- @Test
- public void testEaseToCameraPositionTarget() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- LatLng moveTarget = new LatLng(1, 1);
- CameraPosition initialPosition = new CameraPosition.Builder().target(
- new LatLng()).zoom(zoom).bearing(0).tilt(0).build();
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Default camera position should match default", cameraPosition, initialPosition);
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.newLatLng(moveTarget), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToCameraPositionTargetZoom() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float moveZoom = 15.5f;
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(moveTarget, moveZoom), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToCameraPosition() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
- final float moveZoom = 15.5f;
- final float moveTilt = 45.5f;
- final float moveBearing = 12.5f;
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.newCameraPosition(
- new CameraPosition.Builder()
- .target(moveTarget)
- .zoom(moveZoom)
- .tilt(moveTilt)
- .bearing(moveBearing)
- .build()),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
- }
- );
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToBounds() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng centerBounds = new LatLng(1, 1);
- LatLng cornerOne = new LatLng();
- LatLng cornerTwo = new LatLng(2, 2);
- final LatLngBounds.Builder builder = new LatLngBounds.Builder();
- builder.include(cornerOne);
- builder.include(cornerTwo);
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 0),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToZoomIn() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.zoomIn(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToZoomOut() {
- float zoom = 10.0f;
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(), zoom), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.zoomOut(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToZoomBy() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- final float zoomBy = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.zoomBy(zoomBy), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testEaseToZoomTo() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float zoomTo = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.easeCamera(CameraUpdateFactory.zoomTo(zoomTo), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Override
- public void afterTest() {
- super.afterTest();
- IdlingRegistry.getInstance().unregister(animationIdlingResource);
- }
-
- private void verifyCameraPosition(MapboxMap mapboxMap, LatLng moveTarget, double moveZoom, double moveBearing,
- double moveTilt) {
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Moved camera position latitude should match", cameraPosition.target.getLatitude(),
- moveTarget.getLatitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved camera position longitude should match", cameraPosition.target.getLongitude(),
- moveTarget.getLongitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.zoom, moveZoom, TestConstants.ZOOM_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.tilt, moveTilt, TestConstants.TILT_DELTA);
- assertEquals("Moved bearing should match", cameraPosition.bearing, moveBearing, TestConstants.BEARING_DELTA);
+ void executeCameraMovement(CameraUpdate cameraUpdate, MapboxMap.CancelableCallback callback) {
+ mapboxMap.easeCamera(cameraUpdate, callback);
}
} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
index f8aa43d52d..2cd7b6ffe3 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraMoveTest.java
@@ -1,294 +1,12 @@
package com.mapbox.mapboxsdk.testapp.camera;
-import android.support.test.espresso.Espresso;
-import android.support.test.espresso.IdlingRegistry;
-import android.support.test.espresso.idling.CountingIdlingResource;
-
-import com.mapbox.mapboxsdk.camera.CameraPosition;
-import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.maps.MapboxMap;
-import com.mapbox.mapboxsdk.testapp.activity.BaseTest;
-import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity;
-import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
-
-import org.junit.Test;
-
-import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke;
-import static org.junit.Assert.assertEquals;
-
-public class CameraMoveTest extends BaseTest {
-
- private final CountingIdlingResource animationIdlingResource =
- new CountingIdlingResource("animation_idling_resource");
-
- @Override
- protected Class getActivityClass() {
- return DeviceIndependentTestActivity.class;
- }
-
- @Override
- public void beforeTest() {
- super.beforeTest();
- IdlingRegistry.getInstance().register(animationIdlingResource);
- }
-
- @Test
- public void testMoveToCameraPositionTarget() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- LatLng moveTarget = new LatLng(1, 1);
- CameraPosition initialPosition = new CameraPosition.Builder().target(
- new LatLng()).zoom(zoom).bearing(0).tilt(0).build();
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Default camera position should match default", cameraPosition, initialPosition);
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(moveTarget), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToCameraPositionTargetZoom() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float moveZoom = 15.5f;
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(moveTarget, moveZoom), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToCameraPosition() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
- final float moveZoom = 15.5f;
- final float moveTilt = 45.5f;
- final float moveBearing = 12.5f;
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
- new CameraPosition.Builder()
- .target(moveTarget)
- .zoom(moveZoom)
- .tilt(moveTilt)
- .bearing(moveBearing)
- .build()),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToBounds() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final LatLng centerBounds = new LatLng(1, 1);
- LatLng cornerOne = new LatLng();
- LatLng cornerTwo = new LatLng(2, 2);
- final LatLngBounds.Builder builder = new LatLngBounds.Builder();
- builder.include(cornerOne);
- builder.include(cornerTwo);
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngBounds(builder.build(), 0),
- new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToZoomIn() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.zoomIn(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToZoomOut() {
- float zoom = 10.0f;
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(), zoom), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.zoomOut(), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToZoomBy() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- float zoom = 1.0f;
- final float zoomBy = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.zoomBy(zoomBy), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
-
- @Test
- public void testMoveToZoomTo() {
- validateTestSetup();
- invoke(mapboxMap, (uiController, mapboxMap) -> {
- final float zoomTo = 2.45f;
-
- animationIdlingResource.increment();
- mapboxMap.moveCamera(CameraUpdateFactory.zoomTo(zoomTo), new MapboxMap.CancelableCallback() {
- @Override
- public void onCancel() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
-
- @Override
- public void onFinish() {
- verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0);
- animationIdlingResource.decrement();
- }
- });
- });
-
- Espresso.onIdle();
- }
+public class CameraMoveTest extends CameraTest {
@Override
- public void afterTest() {
- super.afterTest();
- IdlingRegistry.getInstance().unregister(animationIdlingResource);
- }
-
- private void verifyCameraPosition(MapboxMap mapboxMap, LatLng moveTarget, double moveZoom, double moveBearing,
- double moveTilt) {
- CameraPosition cameraPosition = mapboxMap.getCameraPosition();
- assertEquals("Moved camera position latitude should match", cameraPosition.target.getLatitude(),
- moveTarget.getLatitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved camera position longitude should match", cameraPosition.target.getLongitude(),
- moveTarget.getLongitude(), TestConstants.LAT_LNG_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.zoom, moveZoom, TestConstants.ZOOM_DELTA);
- assertEquals("Moved zoom should match", cameraPosition.tilt, moveTilt, TestConstants.TILT_DELTA);
- assertEquals("Moved bearing should match", cameraPosition.bearing, moveBearing, TestConstants.BEARING_DELTA);
+ void executeCameraMovement(CameraUpdate cameraUpdate, MapboxMap.CancelableCallback callback) {
+ mapboxMap.moveCamera(cameraUpdate, callback);
}
-}
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraTest.java
new file mode 100644
index 0000000000..ebce9aaec5
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraTest.java
@@ -0,0 +1,307 @@
+package com.mapbox.mapboxsdk.testapp.camera;
+
+import com.mapbox.mapboxsdk.camera.CameraPosition;
+import com.mapbox.mapboxsdk.camera.CameraUpdate;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.testapp.activity.BaseTest;
+import com.mapbox.mapboxsdk.testapp.activity.espresso.DeviceIndependentTestActivity;
+import com.mapbox.mapboxsdk.testapp.utils.TestConstants;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import static com.mapbox.mapboxsdk.testapp.action.MapboxMapAction.invoke;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+
+public abstract class CameraTest extends BaseTest {
+
+ private CountDownLatch latch;
+
+ @Override
+ protected Class getActivityClass() {
+ return DeviceIndependentTestActivity.class;
+ }
+
+ @Override
+ public void beforeTest() {
+ super.beforeTest();
+ latch = new CountDownLatch(1);
+ }
+
+ @Test
+ public void testToCameraPositionTarget() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ float zoom = 1.0f;
+ LatLng moveTarget = new LatLng(1, 1);
+ CameraPosition initialPosition = new CameraPosition.Builder().target(
+ new LatLng()).zoom(zoom).bearing(0).tilt(0).padding(new double[4]).build();
+ CameraPosition cameraPosition = mapboxMap.getCameraPosition();
+ assertEquals("Default camera position should match default", cameraPosition, initialPosition);
+
+ executeCameraMovement(CameraUpdateFactory.newLatLng(moveTarget), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, moveTarget, zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToCameraPositionTargetZoom() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ final float moveZoom = 15.5f;
+ final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
+
+ executeCameraMovement(CameraUpdateFactory.newLatLngZoom(moveTarget, moveZoom),
+ new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, moveTarget, moveZoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToCameraPosition() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ final LatLng moveTarget = new LatLng(1.0000000001, 1.0000000003);
+ final float moveZoom = 15.5f;
+ final float moveTilt = 45.5f;
+ final float moveBearing = 12.5f;
+ final double[] movePadding = new double[] {0, 500, 350, 1};
+
+ executeCameraMovement(CameraUpdateFactory.newCameraPosition(
+ new CameraPosition.Builder()
+ .target(moveTarget)
+ .zoom(moveZoom)
+ .tilt(moveTilt)
+ .bearing(moveBearing)
+ .padding(movePadding)
+ .build()),
+ new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt, movePadding);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, moveTarget, moveZoom, moveBearing, moveTilt, movePadding);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToBounds() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ final LatLng centerBounds = new LatLng(1, 1);
+ LatLng cornerOne = new LatLng();
+ LatLng cornerTwo = new LatLng(2, 2);
+ final LatLngBounds.Builder builder = new LatLngBounds.Builder();
+ builder.include(cornerOne);
+ builder.include(cornerTwo);
+
+ executeCameraMovement(CameraUpdateFactory.newLatLngBounds(builder.build(), 0),
+ new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, centerBounds, mapboxMap.getCameraPosition().zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToZoomIn() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ float zoom = 1.0f;
+
+ executeCameraMovement(CameraUpdateFactory.zoomIn(), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + 1, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToZoomOut() throws InterruptedException {
+ float zoom = 10.0f;
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ executeCameraMovement(CameraUpdateFactory.newLatLngZoom(new LatLng(), zoom), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+
+ latch = new CountDownLatch(1);
+
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ executeCameraMovement(CameraUpdateFactory.zoomOut(), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom - 1, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToZoomBy() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ float zoom = 1.0f;
+ final float zoomBy = 2.45f;
+
+ executeCameraMovement(CameraUpdateFactory.zoomBy(zoomBy), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoom + zoomBy, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ @Test
+ public void testToZoomTo() throws InterruptedException {
+ validateTestSetup();
+ invoke(mapboxMap, (uiController, mapboxMap) -> {
+ final float zoomTo = 2.45f;
+
+ executeCameraMovement(CameraUpdateFactory.zoomTo(zoomTo), new MapboxMap.CancelableCallback() {
+ @Override
+ public void onCancel() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0, new double[4]);
+ latch.countDown();
+ }
+
+ @Override
+ public void onFinish() {
+ verifyCameraPosition(mapboxMap, mapboxMap.getCameraPosition().target, zoomTo, 0, 0, new double[4]);
+ latch.countDown();
+ }
+ });
+ });
+
+ if (!latch.await(10, TimeUnit.SECONDS)) {
+ Assert.fail("timeout");
+ }
+ }
+
+ abstract void executeCameraMovement(CameraUpdate cameraUpdate, MapboxMap.CancelableCallback callback);
+
+ private void verifyCameraPosition(MapboxMap mapboxMap, LatLng moveTarget, double moveZoom, double moveBearing,
+ double moveTilt, double[] padding) {
+ CameraPosition cameraPosition = mapboxMap.getCameraPosition();
+ assertEquals("Moved camera position latitude should match", cameraPosition.target.getLatitude(),
+ moveTarget.getLatitude(), TestConstants.LAT_LNG_DELTA);
+ assertEquals("Moved camera position longitude should match", cameraPosition.target.getLongitude(),
+ moveTarget.getLongitude(), TestConstants.LAT_LNG_DELTA);
+ assertEquals("Moved zoom should match", cameraPosition.zoom, moveZoom, TestConstants.ZOOM_DELTA);
+ assertEquals("Moved zoom should match", cameraPosition.tilt, moveTilt, TestConstants.TILT_DELTA);
+ assertEquals("Moved bearing should match", cameraPosition.bearing, moveBearing, TestConstants.BEARING_DELTA);
+ assertArrayEquals("Moved padding should match", cameraPosition.padding, padding, TestConstants.PADDING_DELTA);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java
index 09e27d30f2..255d1e1e7d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/utils/TestConstants.java
@@ -5,6 +5,7 @@ public class TestConstants {
public static final double BEARING_DELTA = 0.1;
public static final double TILT_DELTA = 0.3;
public static final double ZOOM_DELTA = 0.3;
+ public static final double PADDING_DELTA = 0.0001;
public static final String TEXT_MARKER_TITLE = "Marker";
public static final String TEXT_MARKER_SNIPPET = "Snippet";
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 e278d033be..7ce54831f2 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
@@ -36,6 +36,7 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
private static final LatLng START_LAT_LNG = new LatLng(37.787947, -122.407432);
private final LongSparseArray<Animator> animators = new LongSparseArray<>();
+ private Animator set;
{
AnimatorSet accelerateDecelerateAnimatorSet = new AnimatorSet();
@@ -92,7 +93,8 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
.bearing(135)
.build();
- createExampleAnimator(mapboxMap.getCameraPosition(), animatedPosition).start();
+ set = createExampleAnimator(mapboxMap.getCameraPosition(), animatedPosition);
+ set.start();
});
}
@@ -237,6 +239,9 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
for (int i = 0; i < animators.size(); i++) {
animators.get(animators.keyAt(i)).cancel();
}
+ if (set != null) {
+ set.cancel();
+ }
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
index 83b0c415ec..6979097658 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/camera/CameraPositionActivity.java
@@ -63,12 +63,12 @@ public class CameraPositionActivity extends FragmentActivity implements OnMapRea
fab = findViewById(R.id.fab);
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, R.color.primary));
fab.setOnClickListener(this);
- });
- toggleLogCameraChanges();
+ toggleLogCameraChanges();
- // listen to long click events to toggle logging camera changes
- mapboxMap.addOnMapLongClickListener(this);
+ // listen to long click events to toggle logging camera changes
+ mapboxMap.addOnMapLongClickListener(this);
+ });
}
@Override
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java
index 732a7929b8..cb2701d436 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/GeoJsonClusteringActivity.java
@@ -30,6 +30,8 @@ import java.util.List;
import java.util.Objects;
import static com.mapbox.mapboxsdk.style.expressions.Expression.all;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.accumulated;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.concat;
import static com.mapbox.mapboxsdk.style.expressions.Expression.division;
import static com.mapbox.mapboxsdk.style.expressions.Expression.exponential;
import static com.mapbox.mapboxsdk.style.expressions.Expression.get;
@@ -39,6 +41,8 @@ import static com.mapbox.mapboxsdk.style.expressions.Expression.has;
import static com.mapbox.mapboxsdk.style.expressions.Expression.interpolate;
import static com.mapbox.mapboxsdk.style.expressions.Expression.literal;
import static com.mapbox.mapboxsdk.style.expressions.Expression.lt;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.max;
+import static com.mapbox.mapboxsdk.style.expressions.Expression.neq;
import static com.mapbox.mapboxsdk.style.expressions.Expression.rgb;
import static com.mapbox.mapboxsdk.style.expressions.Expression.stop;
import static com.mapbox.mapboxsdk.style.expressions.Expression.toNumber;
@@ -138,6 +142,9 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
.withCluster(true)
.withClusterMaxZoom(14)
.withClusterRadius(50)
+ .withClusterProperty("max", max(accumulated(), get("max")), get("mag"))
+ .withClusterProperty("sum", literal("+"), get("mag"))
+ .withClusterProperty("felt", literal("any"), neq(get("felt"), literal("null")))
);
}
@@ -182,9 +189,9 @@ public class GeoJsonClusteringActivity extends AppCompatActivity {
}
private SymbolLayer createClusterTextLayer() {
- return new SymbolLayer("count", "earthquakes")
+ return new SymbolLayer("property", "earthquakes")
.withProperties(
- textField(Expression.toString(get("point_count"))),
+ textField(concat(get("point_count"), literal(", "), get("max"))),
textSize(12f),
textColor(Color.WHITE),
textIgnorePlacement(true),
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml
index 28bdaf7b2a..9b57e18a7a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_camera_position.xml
@@ -18,6 +18,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="?android:attr/actionBarSize"
+ app:mapbox_localIdeographFontFamilies="@array/array_local_ideograph_family_test"
app:mapbox_uiAttributionTintColor="@color/redAccent"/>
<android.support.design.widget.FloatingActionButton
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml
index 26c61e1639..58e49c3cef 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_gesture_detector.xml
@@ -10,6 +10,7 @@
android:id="@id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ app:mapbox_localIdeographEnabled="false"
app:mapbox_cameraTargetLat="51.50325"
app:mapbox_cameraTargetLng="-0.11968"
app:mapbox_cameraZoom="15" />
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml
index 4b7ded8e3a..ad9f88a46e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/arrays.xml
@@ -7,4 +7,9 @@
<item>1000</item>
<item>10000</item>
</string-array>
+ <string-array name="array_local_ideograph_family_test">
+ <item>foo</item>
+ <item>monospace</item>
+ <item>bar</item>
+ </string-array>
</resources> \ No newline at end of file
diff --git a/platform/android/core-files.json b/platform/android/core-files.json
index 62ecc0c671..b19e5d9a93 100644
--- a/platform/android/core-files.json
+++ b/platform/android/core-files.json
@@ -38,6 +38,7 @@
"platform/android/src/java/util.cpp",
"platform/android/src/java_types.cpp",
"platform/android/src/jni.cpp",
+ "platform/android/src/jni_native.cpp",
"platform/android/src/logger.cpp",
"platform/android/src/logging_android.cpp",
"platform/android/src/map/camera_position.cpp",
@@ -142,6 +143,7 @@
"java/util.hpp": "platform/android/src/java/util.hpp",
"java_types.hpp": "platform/android/src/java_types.hpp",
"jni.hpp": "platform/android/src/jni.hpp",
+ "jni_native.hpp": "platform/android/src/jni_native.hpp",
"logger.hpp": "platform/android/src/logger.hpp",
"map/camera_position.hpp": "platform/android/src/map/camera_position.hpp",
"map/image.hpp": "platform/android/src/map/image.hpp",
diff --git a/platform/android/gradle/dependencies.gradle b/platform/android/gradle/dependencies.gradle
index 526861e8b1..da7f007065 100644
--- a/platform/android/gradle/dependencies.gradle
+++ b/platform/android/gradle/dependencies.gradle
@@ -10,7 +10,7 @@ ext {
mapboxServices : '4.8.0',
mapboxTelemetry : '4.5.1',
mapboxCore : '1.3.0',
- mapboxGestures : '0.5.0',
+ mapboxGestures : '0.5.1',
mapboxAccounts : '0.2.0',
supportLib : '28.0.0',
constraintLayout: '1.1.2',
diff --git a/platform/android/src/android_renderer_frontend.cpp b/platform/android/src/android_renderer_frontend.cpp
index 6862fabcb4..d1a2624f0d 100644
--- a/platform/android/src/android_renderer_frontend.cpp
+++ b/platform/android/src/android_renderer_frontend.cpp
@@ -42,8 +42,8 @@ public:
delegate.invoke(&RendererObserver::onWillStartRenderingFrame);
}
- void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded) override {
- delegate.invoke(&RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded);
+ void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded, bool placementChanged) override {
+ delegate.invoke(&RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded, placementChanged);
}
void onDidFinishRenderingMap() override {
diff --git a/platform/android/src/java_types.cpp b/platform/android/src/java_types.cpp
index dd165470cf..7a1ba93a58 100644
--- a/platform/android/src/java_types.cpp
+++ b/platform/android/src/java_types.cpp
@@ -18,6 +18,10 @@ namespace java {
jni::jclass* Map::jclass;
jni::jmethodID* Map::getMethodId;
+ jni::jmethodID* Map::keySetMethodId;
+
+ jni::jclass* Set::jclass;
+ jni::jmethodID* Set::toArrayMethodId;
void registerNatives(JNIEnv& env) {
ObjectArray::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "[Ljava/lang/Object;")).release();
@@ -34,6 +38,10 @@ namespace java {
Map::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Map")).release();
Map::getMethodId = &jni::GetMethodID(env, *Map::jclass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ Map::keySetMethodId = &jni::GetMethodID(env, *Map::jclass, "keySet", "()Ljava/util/Set;");
+
+ Set::jclass = jni::NewGlobalRef(env, &jni::FindClass(env, "java/util/Set")).release();
+ Set::toArrayMethodId = &jni::GetMethodID(env, *Set::jclass, "toArray", "()[Ljava/lang/Object;");
}
}
diff --git a/platform/android/src/java_types.hpp b/platform/android/src/java_types.hpp
index edec5cb550..c7c93ce71b 100644
--- a/platform/android/src/java_types.hpp
+++ b/platform/android/src/java_types.hpp
@@ -29,6 +29,12 @@ namespace java {
struct Map {
static jni::jclass* jclass;
static jni::jmethodID* getMethodId;
+ static jni::jmethodID* keySetMethodId;
+ };
+
+ struct Set {
+ static jni::jclass* jclass;
+ static jni::jmethodID* toArrayMethodId;
};
void registerNatives(JNIEnv&);
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index 088b3b796c..189ec29dce 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -2,66 +2,9 @@
#include <mbgl/util/logging.hpp>
-#include "annotation/marker.hpp"
-#include "annotation/polygon.hpp"
-#include "annotation/polyline.hpp"
-#include "bitmap.hpp"
-#include "bitmap_factory.hpp"
-#include "connectivity_listener.hpp"
-#include "conversion/conversion.hpp"
-#include "conversion/collection.hpp"
-#include "file_source.hpp"
-#include "geojson/feature.hpp"
-#include "geojson/feature_collection.hpp"
-#include "geojson/geometry.hpp"
-#include "geojson/geometry_collection.hpp"
-#include "geojson/line_string.hpp"
-#include "geojson/multi_line_string.hpp"
-#include "geojson/multi_point.hpp"
-#include "geojson/multi_polygon.hpp"
-#include "geojson/point.hpp"
-#include "geojson/polygon.hpp"
-#include "geometry/lat_lng.hpp"
-#include "geometry/lat_lng_bounds.hpp"
-#include "geometry/lat_lng_quad.hpp"
-#include "geometry/projected_meters.hpp"
-#include "graphics/pointf.hpp"
-#include "graphics/rectf.hpp"
-#include "gson/json_array.hpp"
-#include "gson/json_element.hpp"
-#include "gson/json_object.hpp"
-#include "gson/json_primitive.hpp"
-#include "java_types.hpp"
-#include "map_renderer.hpp"
-#include "map_renderer_runnable.hpp"
-#include "native_map_view.hpp"
-#ifndef MBGL_MODULE_OFFLINE_DISABLE
-#include "offline/offline_manager.hpp"
-#include "offline/offline_region.hpp"
-#include "offline/offline_region_definition.hpp"
-#include "offline/offline_region_error.hpp"
-#include "offline/offline_region_status.hpp"
-#endif
-#include "style/transition_options.hpp"
-#include "style/layers/layer_manager.hpp"
-#include "style/sources/source.hpp"
-#include "style/light.hpp"
-#include "style/formatted.hpp"
-#include "style/formatted_section.hpp"
-#ifndef MBGL_MODULE_SNAPSHOT_DISABLE
-#include "snapshotter/map_snapshotter.hpp"
-#include "snapshotter/map_snapshot.hpp"
-#endif
-#include "text/collator_jni.hpp"
-#include "text/local_glyph_rasterizer_jni.hpp"
-#include "text/format_number_jni.hpp"
-#include "logger.hpp"
-
namespace mbgl {
namespace android {
-void RegisterNativeHTTPRequest(JNIEnv&);
-
JavaVM* theJVM;
//TODO: remove
@@ -107,105 +50,5 @@ void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach) {
*env = nullptr;
}
-void registerNatives(JavaVM *vm) {
- theJVM = vm;
-
- jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
-
- // For the DefaultFileSource
- static mbgl::util::RunLoop mainRunLoop;
- FileSource::registerNative(env);
-
- // Basic types
- java::registerNatives(env);
- java::util::registerNative(env);
- PointF::registerNative(env);
- RectF::registerNative(env);
-
- // GeoJSON
- geojson::Feature::registerNative(env);
- geojson::FeatureCollection::registerNative(env);
- geojson::Geometry::registerNative(env);
- geojson::GeometryCollection::registerNative(env);
- geojson::LineString::registerNative(env);
- geojson::MultiLineString::registerNative(env);
- geojson::MultiPoint::registerNative(env);
- geojson::MultiPolygon::registerNative(env);
- geojson::Point::registerNative(env);
- geojson::Polygon::registerNative(env);
-
- // Geometry
- LatLng::registerNative(env);
- LatLngBounds::registerNative(env);
- LatLngQuad::registerNative(env);
- ProjectedMeters::registerNative(env);
-
- // GSon
- gson::JsonArray::registerNative(env);
- gson::JsonElement::registerNative(env);
- gson::JsonObject::registerNative(env);
- gson::JsonPrimitive::registerNative(env);
-
- //Annotation
- Marker::registerNative(env);
- Polygon::registerNative(env);
- Polyline::registerNative(env);
-
- // Map
- MapRenderer::registerNative(env);
- MapRendererRunnable::registerNative(env);
- NativeMapView::registerNative(env);
-
- // Http
- RegisterNativeHTTPRequest(env);
-
- // Bitmap
- Bitmap::registerNative(env);
- BitmapFactory::registerNative(env);
-
- // Style
- TransitionOptions::registerNative(env);
- LayerManagerAndroid::get()->registerNative(env);
- Source::registerNative(env);
- Light::registerNative(env);
- Position::registerNative(env);
- Formatted::registerNative(env);
- FormattedSection::registerNative(env);
-
- // Map
- CameraPosition::registerNative(env);
- Image::registerNative(env);
-
- // Connectivity
- ConnectivityListener::registerNative(env);
-
- // Offline
-#ifndef MBGL_MODULE_OFFLINE_DISABLE
- OfflineManager::registerNative(env);
- OfflineRegion::registerNative(env);
- OfflineRegionDefinition::registerNative(env);
- OfflineTilePyramidRegionDefinition::registerNative(env);
- OfflineGeometryRegionDefinition::registerNative(env);
- OfflineRegionError::registerNative(env);
- OfflineRegionStatus::registerNative(env);
-#endif
-
- // Snapshotter
-#ifndef MBGL_MODULE_SNAPSHOT_DISABLE
- MapSnapshotter::registerNative(env);
- MapSnapshot::registerNative(env);
-#endif
-
- // text
- LocalGlyphRasterizer::registerNative(env);
- Locale::registerNative(env);
- Collator::registerNative(env);
- StringUtils::registerNative(env);
- NumberFormat::registerNative(env);
-
- // Logger
- Logger::registerNative(env);
-}
-
} // namespace android
} // namespace mbgl
diff --git a/platform/android/src/jni.hpp b/platform/android/src/jni.hpp
index e5df92e701..cb519f911d 100644
--- a/platform/android/src/jni.hpp
+++ b/platform/android/src/jni.hpp
@@ -1,6 +1,7 @@
#pragma once
#include <string>
+#include <jni/jni.hpp>
typedef struct _jmethodID* jmethodID;
typedef struct _JavaVM JavaVM;
@@ -17,7 +18,5 @@ extern std::string dataPath;
bool attach_jni_thread(JavaVM* vm, JNIEnv** env, std::string threadName);
void detach_jni_thread(JavaVM* vm, JNIEnv** env, bool detach);
-extern void registerNatives(JavaVM* vm);
-
} // namespace android
} // namespace mbgl
diff --git a/platform/android/src/jni_native.cpp b/platform/android/src/jni_native.cpp
new file mode 100755
index 0000000000..df96ba9759
--- /dev/null
+++ b/platform/android/src/jni_native.cpp
@@ -0,0 +1,164 @@
+#include "jni_native.hpp"
+
+#include "annotation/marker.hpp"
+#include "annotation/polygon.hpp"
+#include "annotation/polyline.hpp"
+#include "bitmap.hpp"
+#include "bitmap_factory.hpp"
+#include "connectivity_listener.hpp"
+#include "conversion/conversion.hpp"
+#include "conversion/collection.hpp"
+#include "file_source.hpp"
+#include "geojson/feature.hpp"
+#include "geojson/feature_collection.hpp"
+#include "geojson/geometry.hpp"
+#include "geojson/geometry_collection.hpp"
+#include "geojson/line_string.hpp"
+#include "geojson/multi_line_string.hpp"
+#include "geojson/multi_point.hpp"
+#include "geojson/multi_polygon.hpp"
+#include "geojson/point.hpp"
+#include "geojson/polygon.hpp"
+#include "geometry/lat_lng.hpp"
+#include "geometry/lat_lng_bounds.hpp"
+#include "geometry/lat_lng_quad.hpp"
+#include "geometry/projected_meters.hpp"
+#include "graphics/pointf.hpp"
+#include "graphics/rectf.hpp"
+#include "gson/json_array.hpp"
+#include "gson/json_element.hpp"
+#include "gson/json_object.hpp"
+#include "gson/json_primitive.hpp"
+#include "java_types.hpp"
+#include "map_renderer.hpp"
+#include "map_renderer_runnable.hpp"
+#include "native_map_view.hpp"
+#ifndef MBGL_MODULE_OFFLINE_DISABLE
+#include "offline/offline_manager.hpp"
+#include "offline/offline_region.hpp"
+#include "offline/offline_region_definition.hpp"
+#include "offline/offline_region_error.hpp"
+#include "offline/offline_region_status.hpp"
+#endif
+#include "style/transition_options.hpp"
+#include "style/layers/layer_manager.hpp"
+#include "style/sources/source.hpp"
+#include "style/light.hpp"
+#include "style/formatted.hpp"
+#include "style/formatted_section.hpp"
+#ifndef MBGL_MODULE_SNAPSHOT_DISABLE
+#include "snapshotter/map_snapshotter.hpp"
+#include "snapshotter/map_snapshot.hpp"
+#endif
+#include "text/collator_jni.hpp"
+#include "text/local_glyph_rasterizer_jni.hpp"
+#include "text/format_number_jni.hpp"
+#include "logger.hpp"
+
+namespace mbgl {
+namespace android {
+
+void RegisterNativeHTTPRequest(JNIEnv&);
+
+void registerNatives(JavaVM *vm) {
+ theJVM = vm;
+
+ jni::JNIEnv& env = jni::GetEnv(*vm, jni::jni_version_1_6);
+
+ // For the DefaultFileSource
+ static mbgl::util::RunLoop mainRunLoop;
+ FileSource::registerNative(env);
+
+ // Basic types
+ java::registerNatives(env);
+ java::util::registerNative(env);
+ PointF::registerNative(env);
+ RectF::registerNative(env);
+
+ // GeoJSON
+ geojson::Feature::registerNative(env);
+ geojson::FeatureCollection::registerNative(env);
+ geojson::Geometry::registerNative(env);
+ geojson::GeometryCollection::registerNative(env);
+ geojson::LineString::registerNative(env);
+ geojson::MultiLineString::registerNative(env);
+ geojson::MultiPoint::registerNative(env);
+ geojson::MultiPolygon::registerNative(env);
+ geojson::Point::registerNative(env);
+ geojson::Polygon::registerNative(env);
+
+ // Geometry
+ LatLng::registerNative(env);
+ LatLngBounds::registerNative(env);
+ LatLngQuad::registerNative(env);
+ ProjectedMeters::registerNative(env);
+
+ // GSon
+ gson::JsonArray::registerNative(env);
+ gson::JsonElement::registerNative(env);
+ gson::JsonObject::registerNative(env);
+ gson::JsonPrimitive::registerNative(env);
+
+ //Annotation
+ Marker::registerNative(env);
+ Polygon::registerNative(env);
+ Polyline::registerNative(env);
+
+ // Map
+ MapRenderer::registerNative(env);
+ MapRendererRunnable::registerNative(env);
+ NativeMapView::registerNative(env);
+
+ // Http
+ RegisterNativeHTTPRequest(env);
+
+ // Bitmap
+ Bitmap::registerNative(env);
+ BitmapFactory::registerNative(env);
+
+ // Style
+ TransitionOptions::registerNative(env);
+ LayerManagerAndroid::get()->registerNative(env);
+ Source::registerNative(env);
+ Light::registerNative(env);
+ Position::registerNative(env);
+ Formatted::registerNative(env);
+ FormattedSection::registerNative(env);
+
+ // Map
+ CameraPosition::registerNative(env);
+ Image::registerNative(env);
+
+ // Connectivity
+ ConnectivityListener::registerNative(env);
+
+ // Offline
+#ifndef MBGL_MODULE_OFFLINE_DISABLE
+ OfflineManager::registerNative(env);
+ OfflineRegion::registerNative(env);
+ OfflineRegionDefinition::registerNative(env);
+ OfflineTilePyramidRegionDefinition::registerNative(env);
+ OfflineGeometryRegionDefinition::registerNative(env);
+ OfflineRegionError::registerNative(env);
+ OfflineRegionStatus::registerNative(env);
+#endif
+
+ // Snapshotter
+#ifndef MBGL_MODULE_SNAPSHOT_DISABLE
+ MapSnapshotter::registerNative(env);
+ MapSnapshot::registerNative(env);
+#endif
+
+ // text
+ LocalGlyphRasterizer::registerNative(env);
+ Locale::registerNative(env);
+ Collator::registerNative(env);
+ StringUtils::registerNative(env);
+ NumberFormat::registerNative(env);
+
+ // Logger
+ Logger::registerNative(env);
+}
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/jni_native.hpp b/platform/android/src/jni_native.hpp
new file mode 100644
index 0000000000..a4c89d3036
--- /dev/null
+++ b/platform/android/src/jni_native.hpp
@@ -0,0 +1,11 @@
+#pragma once
+
+#include "jni.hpp"
+
+namespace mbgl {
+namespace android {
+
+void registerNatives(JavaVM* vm);
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/main.cpp b/platform/android/src/main.cpp
index 03a8288719..9b5c6c1974 100644
--- a/platform/android/src/main.cpp
+++ b/platform/android/src/main.cpp
@@ -1,4 +1,5 @@
#include "jni.hpp"
+#include "jni_native.hpp"
#include <jni/jni.hpp>
extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) {
@@ -6,4 +7,3 @@ extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *) {
mbgl::android::registerNatives(vm);
return JNI_VERSION_1_6;
}
-
diff --git a/platform/android/src/map/camera_position.cpp b/platform/android/src/map/camera_position.cpp
index fcbec5639a..03aca79bda 100644
--- a/platform/android/src/map/camera_position.cpp
+++ b/platform/android/src/map/camera_position.cpp
@@ -4,9 +4,9 @@
namespace mbgl {
namespace android {
-jni::Local<jni::Object<CameraPosition>> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOptions options) {
+jni::Local<jni::Object<CameraPosition>> CameraPosition::New(jni::JNIEnv &env, mbgl::CameraOptions options, float pixelRatio) {
static auto& javaClass = jni::Class<CameraPosition>::Singleton(env);
- static auto constructor = javaClass.GetConstructor<jni::Object<LatLng>, double, double, double>(env);
+ static auto constructor = javaClass.GetConstructor<jni::Object<LatLng>, double, double, double, jni::Array<jni::jdouble>>(env);
// wrap LatLng values coming from core
auto center = options.center.value();
@@ -25,21 +25,33 @@ jni::Local<jni::Object<CameraPosition>> CameraPosition::New(jni::JNIEnv &env, mb
// convert tilt, core ranges from [0 rad, 1,0472 rad], android ranges from 0 to 60
double tilt_degrees = options.pitch.value_or(0);
- return javaClass.New(env, constructor, LatLng::New(env, center), options.zoom.value_or(0), tilt_degrees, bearing_degrees);
+ std::vector<jdouble> paddingVect;
+ auto insets = options.padding.value_or(EdgeInsets {0, 0, 0, 0});
+ auto padding = jni::Array<jni::jdouble>::New(env, 4);
+ paddingVect.push_back(insets.left() * pixelRatio);
+ paddingVect.push_back(insets.top() * pixelRatio);
+ paddingVect.push_back(insets.right() * pixelRatio);
+ paddingVect.push_back(insets.bottom() * pixelRatio);
+ padding.SetRegion<std::vector<jni::jdouble>>(env, 0, paddingVect);
+
+ return javaClass.New(env, constructor, LatLng::New(env, center), options.zoom.value_or(0), tilt_degrees, bearing_degrees, padding);
}
-mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, const jni::Object<CameraPosition>& position) {
+mbgl::CameraOptions CameraPosition::getCameraOptions(jni::JNIEnv& env, const jni::Object<CameraPosition>& position, float pixelRatio) {
static auto& javaClass = jni::Class<CameraPosition>::Singleton(env);
static auto bearing = javaClass.GetField<jni::jdouble>(env, "bearing");
static auto target = javaClass.GetField<jni::Object<LatLng>>(env, "target");
static auto tilt = javaClass.GetField<jni::jdouble>(env, "tilt");
static auto zoom = javaClass.GetField<jni::jdouble>(env, "zoom");
+ static auto paddingField = javaClass.GetField<jni::Array<jni::jdouble>>(env, "padding");
+ static auto padding = position.Get(env, paddingField);
auto center = LatLng::getLatLng(env, position.Get(env, target));
return mbgl::CameraOptions {
center,
- {},
+ EdgeInsets {padding.Get(env, 1) * pixelRatio, padding.Get(env, 0) * pixelRatio,
+ padding.Get(env, 3) * pixelRatio, padding.Get(env, 2) * pixelRatio},
{},
position.Get(env, zoom),
position.Get(env, bearing),
diff --git a/platform/android/src/map/camera_position.hpp b/platform/android/src/map/camera_position.hpp
index 7579f9fed1..b677f04ea0 100644
--- a/platform/android/src/map/camera_position.hpp
+++ b/platform/android/src/map/camera_position.hpp
@@ -12,9 +12,9 @@ class CameraPosition : private mbgl::util::noncopyable {
public:
static constexpr auto Name() { return "com/mapbox/mapboxsdk/camera/CameraPosition"; };
- static jni::Local<jni::Object<CameraPosition>> New(jni::JNIEnv&, mbgl::CameraOptions);
+ static jni::Local<jni::Object<CameraPosition>> New(jni::JNIEnv&, mbgl::CameraOptions, float pixelRatio);
- static mbgl::CameraOptions getCameraOptions(jni::JNIEnv&, const jni::Object<CameraPosition>&);
+ static mbgl::CameraOptions getCameraOptions(jni::JNIEnv&, const jni::Object<CameraPosition>&, float pixelRatio);
static void registerNative(jni::JNIEnv&);
};
diff --git a/platform/android/src/map_renderer.cpp b/platform/android/src/map_renderer.cpp
index 92444c404d..6be708b994 100644
--- a/platform/android/src/map_renderer.cpp
+++ b/platform/android/src/map_renderer.cpp
@@ -16,11 +16,9 @@ namespace android {
MapRenderer::MapRenderer(jni::JNIEnv& _env,
const jni::Object<MapRenderer>& obj,
jni::jfloat pixelRatio_,
- const jni::String& programCacheDir_,
const jni::String& localIdeographFontFamily_)
: javaPeer(_env, obj)
, pixelRatio(pixelRatio_)
- , programCacheDir(jni::Make<std::string>(_env, programCacheDir_))
, localIdeographFontFamily(localIdeographFontFamily_ ? jni::Make<std::string>(_env, localIdeographFontFamily_) : optional<std::string>{})
, mailbox(std::make_shared<Mailbox>(*this)) {
}
@@ -173,7 +171,7 @@ void MapRenderer::onSurfaceCreated(JNIEnv&) {
// Create the new backend and renderer
backend = std::make_unique<AndroidRendererBackend>();
- renderer = std::make_unique<Renderer>(*backend, pixelRatio, programCacheDir, localIdeographFontFamily);
+ renderer = std::make_unique<Renderer>(*backend, pixelRatio, localIdeographFontFamily);
rendererRef = std::make_unique<ActorRef<Renderer>>(*renderer, mailbox);
// Set the observer on the new Renderer implementation
@@ -214,7 +212,7 @@ void MapRenderer::registerNative(jni::JNIEnv& env) {
// Register the peer
jni::RegisterNativePeer<MapRenderer>(env, javaClass, "nativePtr",
- jni::MakePeer<MapRenderer, const jni::Object<MapRenderer>&, jni::jfloat, const jni::String&, const jni::String&>,
+ jni::MakePeer<MapRenderer, const jni::Object<MapRenderer>&, jni::jfloat, const jni::String&>,
"nativeInitialize", "finalize",
METHOD(&MapRenderer::render, "nativeRender"),
METHOD(&MapRenderer::onRendererReset, "nativeReset"),
diff --git a/platform/android/src/map_renderer.hpp b/platform/android/src/map_renderer.hpp
index efbe55af7f..5a8ddeeb91 100644
--- a/platform/android/src/map_renderer.hpp
+++ b/platform/android/src/map_renderer.hpp
@@ -44,7 +44,6 @@ public:
MapRenderer(jni::JNIEnv& _env,
const jni::Object<MapRenderer>&,
jni::jfloat pixelRatio,
- const jni::String& programCacheDir,
const jni::String& localIdeographFontFamily);
~MapRenderer() override;
@@ -104,7 +103,6 @@ private:
jni::WeakReference<jni::Object<MapRenderer>, jni::EnvAttachingDeleter> javaPeer;
float pixelRatio;
- std::string programCacheDir;
optional<std::string> localIdeographFontFamily;
std::shared_ptr<ThreadPool> threadPool;
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 47f2c6d9aa..8ef757de15 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -185,7 +185,7 @@ void NativeMapView::onWillStartRenderingFrame() {
}
}
-void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderMode mode) {
+void NativeMapView::onDidFinishRenderingFrame(MapObserver::RenderMode mode, bool) {
assert(vm != nullptr);
android::UniqueEnv _env = android::AttachEnv();
@@ -336,13 +336,17 @@ void NativeMapView::moveBy(jni::JNIEnv&, jni::jdouble dx, jni::jdouble dy, jni::
map->moveBy({dx, dy}, animationOptions);
}
-void NativeMapView::jumpTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom) {
+void NativeMapView::jumpTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jdouble pitch, jni::jdouble zoom, const jni::Array<jni::jdouble>& padding) {
mbgl::CameraOptions options;
if (bearing != -1) {
options.bearing = bearing;
}
options.center = mbgl::LatLng(latitude, longitude);
- options.padding = insets;
+ if (padding) {
+ assert(padding.Length(env) == 4);
+ options.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1),
+ padding.Get(env, 2), padding.Get(env, 3)};
+ }
if (pitch != -1) {
options.pitch = pitch;
}
@@ -353,13 +357,17 @@ void NativeMapView::jumpTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble lati
map->jumpTo(options);
}
-void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, jni::jboolean easing) {
+void NativeMapView::easeTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, const jni::Array<jni::jdouble>& padding, jni::jboolean easing) {
mbgl::CameraOptions cameraOptions;
if (bearing != -1) {
cameraOptions.bearing = bearing;
}
cameraOptions.center = mbgl::LatLng(latitude, longitude);
- cameraOptions.padding = insets;
+ if (padding) {
+ assert(padding.Length(env) == 4);
+ cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1),
+ padding.Get(env, 2), padding.Get(env, 3)};
+ }
if (pitch != -1) {
cameraOptions.pitch = pitch;
}
@@ -377,13 +385,17 @@ void NativeMapView::easeTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble lati
map->easeTo(cameraOptions, animationOptions);
}
-void NativeMapView::flyTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom) {
+void NativeMapView::flyTo(jni::JNIEnv& env, jni::jdouble bearing, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration, jni::jdouble pitch, jni::jdouble zoom, const jni::Array<jni::jdouble>& padding) {
mbgl::CameraOptions cameraOptions;
if (bearing != -1) {
cameraOptions.bearing = bearing;
}
cameraOptions.center = mbgl::LatLng(latitude, longitude);
- cameraOptions.padding = insets;
+ if (padding) {
+ assert(padding.Length(env) == 4);
+ cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1),
+ padding.Get(env, 2), padding.Get(env, 3)};
+ }
if (pitch != -1) {
cameraOptions.pitch = pitch;
}
@@ -397,23 +409,29 @@ void NativeMapView::flyTo(jni::JNIEnv&, jni::jdouble bearing, jni::jdouble latit
}
jni::Local<jni::Object<LatLng>> NativeMapView::getLatLng(JNIEnv& env) {
- return LatLng::New(env, *map->getCameraOptions(insets).center);
+ return LatLng::New(env, *map->getCameraOptions(mbgl::nullopt).center);
}
-void NativeMapView::setLatLng(jni::JNIEnv&, jni::jdouble latitude, jni::jdouble longitude, jni::jlong duration) {
- map->easeTo(mbgl::CameraOptions().withCenter(mbgl::LatLng(latitude, longitude)).withPadding(insets),
- mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
+void NativeMapView::setLatLng(jni::JNIEnv& env, jni::jdouble latitude, jni::jdouble longitude, const jni::Array<jni::jdouble>& padding, jni::jlong duration) {
+ mbgl::CameraOptions cameraOptions;
+ cameraOptions.center = mbgl::LatLng(latitude, longitude);
+ if (padding) {
+ assert(padding.Length(env) == 4);
+ cameraOptions.padding = mbgl::EdgeInsets{padding.Get(env, 0), padding.Get(env, 1),
+ padding.Get(env, 2), padding.Get(env, 3)};
+ }
+ map->easeTo(cameraOptions, mbgl::AnimationOptions{mbgl::Milliseconds(duration)});
}
jni::Local<jni::Object<CameraPosition>> NativeMapView::getCameraForLatLngBounds(jni::JNIEnv& env, const jni::Object<LatLngBounds>& jBounds, double top, double left, double bottom, double right, double bearing, double tilt) {
mbgl::EdgeInsets padding = {top, left, bottom, right};
- return CameraPosition::New(env, map->cameraForLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds), padding, bearing, tilt));
+ return CameraPosition::New(env, map->cameraForLatLngBounds(mbgl::android::LatLngBounds::getLatLngBounds(env, jBounds), padding, bearing, tilt), pixelRatio);
}
jni::Local<jni::Object<CameraPosition>> NativeMapView::getCameraForGeometry(jni::JNIEnv& env, const jni::Object<geojson::Geometry>& jGeometry, double top, double left, double bottom, double right, double bearing, double tilt) {
auto geometry = geojson::Geometry::convert(env, jGeometry);
mbgl::EdgeInsets padding = {top, left, bottom, right};
- return CameraPosition::New(env, map->cameraForGeometry(geometry, padding, bearing, tilt));
+ return CameraPosition::New(env, map->cameraForGeometry(geometry, padding, bearing, tilt), pixelRatio);
}
void NativeMapView::setReachability(jni::JNIEnv&, jni::jboolean reachable) {
@@ -514,23 +532,6 @@ void NativeMapView::setVisibleCoordinateBounds(JNIEnv& env, const jni::Array<jni
map->easeTo(cameraOptions, animationOptions);
}
-void NativeMapView::setContentPadding(JNIEnv&, float top, float left, float bottom, float right) {
- insets = {top, left, bottom, right};
- // invalidate the camera position to consider the new padding
- map->jumpTo(map->getCameraOptions(insets));
-}
-
-jni::Local<jni::Array<jni::jfloat>> NativeMapView::getContentPadding(JNIEnv& env) {
- auto result = jni::Array<jni::jfloat>::New(env, 4);
- std::vector<jfloat> vect;
- vect.push_back(insets.top());
- vect.push_back(insets.left());
- vect.push_back(insets.bottom());
- vect.push_back(insets.right());
- result.SetRegion<std::vector<jni::jfloat>>(env, 0, vect);
- return result;
-}
-
void NativeMapView::scheduleSnapshot(jni::JNIEnv&) {
mapRenderer.requestSnapshot([&](PremultipliedImage image) {
auto _env = android::AttachEnv();
@@ -548,7 +549,7 @@ void NativeMapView::scheduleSnapshot(jni::JNIEnv&) {
}
jni::Local<jni::Object<CameraPosition>> NativeMapView::getCameraPosition(jni::JNIEnv& env) {
- return CameraPosition::New(env, map->getCameraOptions(insets));
+ return CameraPosition::New(env, map->getCameraOptions(mbgl::nullopt), pixelRatio);
}
void NativeMapView::updateMarker(jni::JNIEnv& env, jni::jlong markerId, jni::jdouble lat, jni::jdouble lon, const jni::String& jid) {
@@ -1098,8 +1099,6 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
METHOD(&NativeMapView::getBearing, "nativeGetBearing"),
METHOD(&NativeMapView::resetNorth, "nativeResetNorth"),
METHOD(&NativeMapView::setVisibleCoordinateBounds, "nativeSetVisibleCoordinateBounds"),
- METHOD(&NativeMapView::setContentPadding, "nativeSetContentPadding"),
- METHOD(&NativeMapView::getContentPadding, "nativeGetContentPadding"),
METHOD(&NativeMapView::scheduleSnapshot, "nativeTakeSnapshot"),
METHOD(&NativeMapView::getCameraPosition, "nativeGetCameraPosition"),
METHOD(&NativeMapView::updateMarker, "nativeUpdateMarker"),
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index 4ea4781b36..26567a003c 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -62,7 +62,7 @@ public:
void onDidFinishLoadingMap() override;
void onDidFailLoadingMap(MapLoadError, const std::string&) override;
void onWillStartRenderingFrame() override;
- void onDidFinishRenderingFrame(MapObserver::RenderMode) override;
+ void onDidFinishRenderingFrame(MapObserver::RenderMode, bool) override;
void onWillStartRenderingMap() override;
void onDidFinishRenderingMap(MapObserver::RenderMode) override;
void onDidBecomeIdle() override;
@@ -91,15 +91,15 @@ public:
void moveBy(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong);
- void jumpTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble);
+ void jumpTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, jni::jdouble, const jni::Array<jni::jdouble>&);
- void easeTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, jni::jboolean);
+ void easeTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, const jni::Array<jni::jdouble>&, jni::jboolean);
- void flyTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble);
+ void flyTo(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jdouble, jni::jlong, jni::jdouble, jni::jdouble, const jni::Array<jni::jdouble>&);
jni::Local<jni::Object<LatLng>> getLatLng(JNIEnv&);
- void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, jni::jlong);
+ void setLatLng(jni::JNIEnv&, jni::jdouble, jni::jdouble, const jni::Array<jni::jdouble>&, jni::jlong);
jni::Local<jni::Object<CameraPosition>> getCameraForLatLngBounds(jni::JNIEnv&, const jni::Object<mbgl::android::LatLngBounds>&, double top, double left, double bottom, double right, double bearing, double tilt);
@@ -139,10 +139,6 @@ public:
void setVisibleCoordinateBounds(JNIEnv&, const jni::Array<jni::Object<LatLng>>&, const jni::Object<RectF>&, jni::jdouble, jni::jlong);
- void setContentPadding(JNIEnv&, float, float, float, float);
-
- jni::Local<jni::Array<jni::jfloat>> getContentPadding(JNIEnv&);
-
void scheduleSnapshot(jni::JNIEnv&);
jni::Local<jni::Object<CameraPosition>> getCameraPosition(jni::JNIEnv&);
@@ -259,7 +255,6 @@ private:
// Ensure these are initialised last
std::unique_ptr<mbgl::Map> map;
- mbgl::EdgeInsets insets;
};
} // namespace android
diff --git a/platform/android/src/snapshotter/map_snapshotter.cpp b/platform/android/src/snapshotter/map_snapshotter.cpp
index 2eca6595e1..0b38269ada 100644
--- a/platform/android/src/snapshotter/map_snapshotter.cpp
+++ b/platform/android/src/snapshotter/map_snapshotter.cpp
@@ -23,7 +23,6 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
const jni::Object<LatLngBounds>& region,
const jni::Object<CameraPosition>& position,
jni::jboolean _showLogo,
- const jni::String& _programCacheDir,
const jni::String& _localIdeographFontFamily)
: javaPeer(_env, _obj)
, pixelRatio(_pixelRatio) {
@@ -39,7 +38,7 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
optional<mbgl::CameraOptions> cameraOptions;
if (position) {
- cameraOptions = CameraPosition::getCameraOptions(_env, position);
+ cameraOptions = CameraPosition::getCameraOptions(_env, position, pixelRatio);
}
optional<mbgl::LatLngBounds> bounds;
@@ -61,7 +60,6 @@ MapSnapshotter::MapSnapshotter(jni::JNIEnv& _env,
pixelRatio,
cameraOptions,
bounds,
- jni::Make<std::string>(_env, _programCacheDir),
_localIdeographFontFamily ?
jni::Make<std::string>(_env, _localIdeographFontFamily) :
optional<std::string>{},
@@ -126,7 +124,7 @@ void MapSnapshotter::setSize(JNIEnv&, jni::jint width, jni::jint height) {
}
void MapSnapshotter::setCameraPosition(JNIEnv& env, const jni::Object<CameraPosition>& position) {
- auto options = CameraPosition::getCameraOptions(env, position);
+ auto options = CameraPosition::getCameraOptions(env, position, pixelRatio);
snapshotter->setCameraOptions(options);
}
@@ -161,7 +159,7 @@ void MapSnapshotter::registerNative(jni::JNIEnv& env) {
// Register the peer
jni::RegisterNativePeer<MapSnapshotter>(env, javaClass, "nativePtr",
- jni::MakePeer<MapSnapshotter, const jni::Object<MapSnapshotter>&, const jni::Object<FileSource>&, jni::jfloat, jni::jint, jni::jint, const jni::String&, const jni::String&, const jni::Object<LatLngBounds>&, const jni::Object<CameraPosition>&, jni::jboolean, const jni::String&, const jni::String&>,
+ jni::MakePeer<MapSnapshotter, const jni::Object<MapSnapshotter>&, const jni::Object<FileSource>&, jni::jfloat, jni::jint, jni::jint, const jni::String&, const jni::String&, const jni::Object<LatLngBounds>&, const jni::Object<CameraPosition>&, jni::jboolean, const jni::String&>,
"nativeInitialize",
"finalize",
METHOD(&MapSnapshotter::setStyleUrl, "setStyleUrl"),
diff --git a/platform/android/src/snapshotter/map_snapshotter.hpp b/platform/android/src/snapshotter/map_snapshotter.hpp
index 791aa61d6a..608a4c855f 100644
--- a/platform/android/src/snapshotter/map_snapshotter.hpp
+++ b/platform/android/src/snapshotter/map_snapshotter.hpp
@@ -34,7 +34,6 @@ public:
const jni::Object<LatLngBounds>& region,
const jni::Object<CameraPosition>& position,
jni::jboolean showLogo,
- const jni::String& programCacheDir,
const jni::String& localIdeographFontFamily);
~MapSnapshotter();
diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp
index 8559720b2f..d38dbfa684 100644
--- a/platform/android/src/style/android_conversion.hpp
+++ b/platform/android/src/style/android_conversion.hpp
@@ -47,9 +47,18 @@ public:
}
template <class Fn>
- static optional<Error> eachMember(const mbgl::android::Value&, Fn&&) {
- // TODO
- mbgl::Log::Warning(mbgl::Event::Android, "eachMember not implemented");
+ static optional<Error> eachMember(const mbgl::android::Value& value, Fn&& fn) {
+ assert(value.isObject());
+ mbgl::android::Value keys = value.keyArray();
+ std::size_t length = arrayLength(keys);
+ for(std::size_t i = 0; i < length; ++i){
+ const auto k = keys.get(i).toString();
+ auto v = value.get(k.c_str());
+ optional<Error> result = fn(k, std::move(v));
+ if (result) {
+ return result;
+ }
+ }
return {};
}
diff --git a/platform/android/src/style/value.cpp b/platform/android/src/style/value.cpp
index f916909687..2f04840729 100644
--- a/platform/android/src/style/value.cpp
+++ b/platform/android/src/style/value.cpp
@@ -63,6 +63,12 @@ namespace android {
return Value(env, jni::Local<jni::Object<>>(env, member));
}
+ Value Value::keyArray() const{
+ jni::jobject* set = jni::CallMethod<jni::jobject*>(env, value.get(), *java::Map::keySetMethodId);
+ jni::jobject* array = jni::CallMethod<jni::jobject*>(env, set, *java::Set::toArrayMethodId);
+ return Value(env, jni::Local<jni::Object<>>(env, array));
+ }
+
int Value::getLength() const {
auto array = (jni::jarray<jni::jobject>*) value.get();
return jni::GetArrayLength(env, *array);
diff --git a/platform/android/src/style/value.hpp b/platform/android/src/style/value.hpp
index 0c702bb465..b507c5ed11 100644
--- a/platform/android/src/style/value.hpp
+++ b/platform/android/src/style/value.hpp
@@ -31,6 +31,7 @@ public:
long toLong() const;
bool toBool() const;
Value get(const char* key) const;
+ Value keyArray() const;
int getLength() const;
Value get(const int index ) const;
diff --git a/platform/android/vendor/mapbox-gestures-android b/platform/android/vendor/mapbox-gestures-android
-Subproject d099f39e00358d6700c3e1c588e08e1a80f6c45
+Subproject ae08de82ca178dca7f005dfc8056554cf77124a
diff --git a/platform/darwin/src/MGLAccountManager.m b/platform/darwin/src/MGLAccountManager.m
index 69170459bc..c37195967a 100644
--- a/platform/darwin/src/MGLAccountManager.m
+++ b/platform/darwin/src/MGLAccountManager.m
@@ -13,6 +13,8 @@ static NSString * const MGLAccountManagerExternalClassName = @"MBXAccounts";
static NSString * const MGLAccountManagerExternalMethodName = @"skuToken";
#endif
+NSString * const MGLMapboxAccountTypeKey = @"MGLMapboxAccountType";
+
@interface MGLAccountManager ()
@property (atomic) NSString *accessToken;
diff --git a/platform/darwin/src/MGLAccountManager_Private.h b/platform/darwin/src/MGLAccountManager_Private.h
index 3fd45f1ae8..4bf7963182 100644
--- a/platform/darwin/src/MGLAccountManager_Private.h
+++ b/platform/darwin/src/MGLAccountManager_Private.h
@@ -2,6 +2,9 @@
NS_ASSUME_NONNULL_BEGIN
+/// NSUserDefaults key that controls developer account type
+FOUNDATION_EXTERN NSString * const MGLMapboxAccountTypeKey;
+
@interface MGLAccountManager (Private)
/// Returns the shared instance of the `MGLAccountManager` class.
diff --git a/platform/darwin/src/MGLMapSnapshotter.mm b/platform/darwin/src/MGLMapSnapshotter.mm
index 65bed2cf42..0001ebcb86 100644
--- a/platform/darwin/src/MGLMapSnapshotter.mm
+++ b/platform/darwin/src/MGLMapSnapshotter.mm
@@ -624,7 +624,7 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
// Create the snapshotter
_mbglMapSnapshotter = std::make_unique<mbgl::MapSnapshotter>(
- style, size, pixelRatio, cameraOptions, coordinateBounds, config.cacheDir, config.localFontFamilyName, resourceOptions);
+ style, size, pixelRatio, cameraOptions, coordinateBounds, config.localFontFamilyName, resourceOptions);
}
@end
diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h
index 1ed364ddf3..d093bb938a 100644
--- a/platform/darwin/src/MGLOfflineStorage.h
+++ b/platform/darwin/src/MGLOfflineStorage.h
@@ -173,6 +173,11 @@ typedef NS_ENUM(NSUInteger, MGLResourceKind) {
packs and ambient caching. All of this class’s instance methods are asynchronous,
reflecting the fact that offline resources are stored in a database. The shared
object maintains a canonical collection of offline packs in its `packs` property.
+
+ Mapbox resources downloaded via this API are subject to separate Vector Tile and
+ Raster Tile API pricing and are not included in the Maps SDK’s “unlimited” requests.
+ See <a href="https://www.mapbox.com/pricing/">our pricing page</a> for more
+ information.
#### Related examples
See the <a href="https://docs.mapbox.com/ios/maps/examples/offline-pack/">
@@ -341,8 +346,7 @@ MGL_EXPORT
attempt to download additional tiles until already downloaded tiles are removed
by calling the `-removePack:withCompletionHandler:` method.
- @note The <a href="https://www.mapbox.com/tos/">Mapbox Terms of Service</a>
- prohibits changing or bypassing this limit without permission from Mapbox.
+ @param maximumCount The maximum number of tiles allowed to be downloaded.
*/
- (void)setMaximumAllowedMapboxTiles:(uint64_t)maximumCount;
@@ -420,7 +424,7 @@ MGL_EXPORT
- (void)resetDatabaseWithCompletionHandler:(void (^)(NSError *_Nullable error))completion;
-/*
+/**
Inserts the provided resource into the ambient cache.
This method mimics the caching that would take place if the equivalent resource
diff --git a/platform/darwin/src/MGLRendererConfiguration.h b/platform/darwin/src/MGLRendererConfiguration.h
index bfe88b7209..0c539f86f1 100644
--- a/platform/darwin/src/MGLRendererConfiguration.h
+++ b/platform/darwin/src/MGLRendererConfiguration.h
@@ -20,9 +20,6 @@ MGL_EXPORT
Based on the native scale where available, otherwise the standard screen scale. */
@property (nonatomic, readonly) const float scaleFactor;
-/** The cache dir to use. */
-@property (nonatomic, readonly) mbgl::optional<std::string> cacheDir;
-
/** The name of the font family to use for client-side text rendering of CJK ideographs.
Set MGLIdeographicFontFamilyName in your containing application's Info.plist to
diff --git a/platform/darwin/src/MGLRendererConfiguration.mm b/platform/darwin/src/MGLRendererConfiguration.mm
index 54bdcaa691..136dc929a6 100644
--- a/platform/darwin/src/MGLRendererConfiguration.mm
+++ b/platform/darwin/src/MGLRendererConfiguration.mm
@@ -66,10 +66,6 @@ static NSString * const MGLIdeographicFontFamilyNameKey = @"MGLIdeographicFontFa
#endif
}
-- (mbgl::optional<std::string>)cacheDir {
- return mbgl::optional<std::string>();
-}
-
- (mbgl::optional<std::string>)localFontFamilyName {
return [self _localFontFamilyNameWithPropertyDictionary:[[NSBundle mainBundle] infoDictionary]];
}
diff --git a/platform/darwin/src/http_file_source.mm b/platform/darwin/src/http_file_source.mm
index 5737d8b999..b0f69f4a7f 100644
--- a/platform/darwin/src/http_file_source.mm
+++ b/platform/darwin/src/http_file_source.mm
@@ -88,15 +88,14 @@ class HTTPFileSource::Impl {
public:
Impl() {
@autoreleasepool {
-
- NSURLSessionConfiguration *sessionConfig =
- [MGLNetworkConfiguration sharedManager].sessionConfiguration;
-
+ NSURLSessionConfiguration *sessionConfig = [MGLNetworkConfiguration sharedManager].sessionConfiguration;
session = [NSURLSession sessionWithConfiguration:sessionConfig];
userAgent = getUserAgent();
- accountType = [[NSUserDefaults standardUserDefaults] integerForKey:@"MGLMapboxAccountType"];
+#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+ accountType = [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountTypeKey];
+#endif
}
}
@@ -205,13 +204,13 @@ NSURL *resourceURLWithAccountType(const Resource& resource, NSInteger accountTyp
if (accountType == 0 &&
([url.host isEqualToString:@"mapbox.com"] || [url.host hasSuffix:@".mapbox.com"])) {
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
- NSURLQueryItem *accountsQueryItem = [NSURLQueryItem queryItemWithName:@"sku" value:MGLAccountManager.skuToken];
-
- NSMutableArray *queryItems = [NSMutableArray arrayWithObject:accountsQueryItem];
-
- // offline here
+ NSMutableArray *queryItems = [NSMutableArray array];
+
if (resource.usage == Resource::Usage::Offline) {
[queryItems addObject:[NSURLQueryItem queryItemWithName:@"offline" value:@"true"]];
+ } else {
+ // Only add SKU token to requests not tagged as "offline" usage.
+ [queryItems addObject:[NSURLQueryItem queryItemWithName:@"sku" value:MGLAccountManager.skuToken]];
}
if (components.queryItems) {
diff --git a/platform/darwin/test/MGLResourceTests.mm b/platform/darwin/test/MGLResourceTests.mm
index 0420997c39..7fcccc535c 100644
--- a/platform/darwin/test/MGLResourceTests.mm
+++ b/platform/darwin/test/MGLResourceTests.mm
@@ -22,18 +22,28 @@ namespace mbgl {
NSURL *url = [NSURL URLWithString:@(testURL.c_str())];
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
NSArray<NSURLQueryItem *> *items = components.queryItems;
- XCTAssert(items.count == 2 );
+ XCTAssert(items.count == 2);
}
Resource resource(Resource::Kind::Unknown, testURL);
- // By default, resource are NOT offline
+ // By default, resources are NOT offline
{
+ bool skuTokenQueryItemFound;
NSURL *url = resourceURLWithAccountType(resource, 0);
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
for (NSURLQueryItem *item in components.queryItems) {
XCTAssertFalse([item.name isEqualToString:@"offline"]);
+ if ([item.name isEqualToString:@"sku"]) {
+ skuTokenQueryItemFound = YES;
+ }
}
+
+#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
+ XCTAssertTrue(skuTokenQueryItemFound, "Default resource URL should have SKU token query item");
+#else
+ XCTAssertFalse(skuTokenQueryItemFound, "Non-iOS platforms should not have a SKU token query item");
+#endif
}
// Now check offline
@@ -43,20 +53,20 @@ namespace mbgl {
NSURL *url = resourceURLWithAccountType(resource, 0);
NSURLComponents *components = [NSURLComponents componentsWithURL:url resolvingAgainstBaseURL:NO];
- // For offline, we expect a single offline param and a sku param
+ // For offline, we expect a single offline query item
NSInteger foundCount = 0;
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
for (NSURLQueryItem *item in components.queryItems) {
if (([item.name isEqualToString:@"offline"] && [item.value isEqualToString:@"true"]) ||
([item.name isEqualToString:@"a"] && [item.value isEqualToString:@"one"]) ||
- ([item.name isEqualToString:@"b"] && [item.value isEqualToString:@"two"]) ||
- ([item.name isEqualToString:@"sku"])) {
+ ([item.name isEqualToString:@"b"] && [item.value isEqualToString:@"two"])) {
foundCount++;
}
+ XCTAssertFalse([item.name isEqualToString:@"sku"]);
}
- XCTAssert(foundCount == 4);
+ XCTAssert(foundCount == 3);
#else
// NOTE: Currently the macOS SDK does not supply the sku or offline query parameters
for (NSURLQueryItem *item in components.queryItems) {
@@ -64,6 +74,7 @@ namespace mbgl {
([item.name isEqualToString:@"b"] && [item.value isEqualToString:@"two"])) {
foundCount++;
}
+ XCTAssertFalse([item.name isEqualToString:@"sku"]);
}
XCTAssert(foundCount == 2);
diff --git a/platform/darwin/test/MGLTileSetTests.mm b/platform/darwin/test/MGLTileSetTests.mm
index 998d4baee6..65e096ae7f 100644
--- a/platform/darwin/test/MGLTileSetTests.mm
+++ b/platform/darwin/test/MGLTileSetTests.mm
@@ -84,9 +84,18 @@
// the attribution is reflected by the mbgl tileset
#if TARGET_OS_IPHONE
- NSString *html = (@"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00pt\">"
- @"<a href=\"https://www.mapbox.com/\">Mapbox</a> </font>"
- @"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00pt; background-color: #ff0000\">GL</font>\n");
+ NSString *html;
+ if (@available(iOS 13.0, *)) {
+ // TODO: investigate visual impact
+ // iOS 13 evidently changes font size from points to pixels
+ html = (@"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00px\">"
+ @"<a href=\"https://www.mapbox.com/\">Mapbox</a> </font>"
+ @"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00px; background-color: #ff0000\">GL</font>\n");
+ } else {
+ html = (@"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00pt\">"
+ @"<a href=\"https://www.mapbox.com/\">Mapbox</a> </font>"
+ @"<font style=\"font-family: 'Helvetica'; font-weight: normal; font-style: normal; font-size: 12.00pt; background-color: #ff0000\">GL</font>\n");
+ }
#else
NSString *html = (@"<font face=\"Helvetica\" size=\"3\" style=\"font: 12.0px Helvetica\">"
@"<a href=\"https://www.mapbox.com/\">Mapbox</a> </font>"
@@ -111,7 +120,7 @@
// the scheme is reflected by the mbgl tileset
XCTAssertEqual(tileSet.scheme, mbgl::Tileset::Scheme::TMS);
- // when the dem enciding is changed using an NSNumber
+ // when the dem encoding is changed using an NSNumber
tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{
MGLTileSourceOptionDEMEncoding: @(MGLDEMEncodingTerrarium),
});
@@ -119,7 +128,7 @@
// the encoding is reflected by the mbgl tileset
XCTAssertEqual(tileSet.encoding, mbgl::Tileset::DEMEncoding::Terrarium);
- // when the dem enciding is changed using an NSValue
+ // when the dem encoding is changed using an NSValue
MGLDEMEncoding terrarium = MGLDEMEncodingTerrarium;
tileSet = MGLTileSetFromTileURLTemplates(tileURLTemplates, @{
MGLTileSourceOptionDEMEncoding: [NSValue value:&terrarium withObjCType:@encode(MGLDEMEncoding)],
diff --git a/platform/default/include/mbgl/gfx/headless_frontend.hpp b/platform/default/include/mbgl/gfx/headless_frontend.hpp
index 7f937b34b8..8f7a7bf202 100644
--- a/platform/default/include/mbgl/gfx/headless_frontend.hpp
+++ b/platform/default/include/mbgl/gfx/headless_frontend.hpp
@@ -17,12 +17,10 @@ class TransformState;
class HeadlessFrontend : public RendererFrontend {
public:
HeadlessFrontend(float pixelRatio_,
- const optional<std::string> programCacheDir = {},
gfx::ContextMode mode = gfx::ContextMode::Unique,
const optional<std::string> localFontFamily = {});
HeadlessFrontend(Size,
float pixelRatio_,
- const optional<std::string> programCacheDir = {},
gfx::ContextMode mode = gfx::ContextMode::Unique,
const optional<std::string> localFontFamily = {});
~HeadlessFrontend() override;
diff --git a/platform/default/include/mbgl/map/map_snapshotter.hpp b/platform/default/include/mbgl/map/map_snapshotter.hpp
index db1ba1f267..c1544c36ab 100644
--- a/platform/default/include/mbgl/map/map_snapshotter.hpp
+++ b/platform/default/include/mbgl/map/map_snapshotter.hpp
@@ -31,7 +31,6 @@ public:
const float pixelRatio,
const optional<CameraOptions> cameraOptions,
const optional<LatLngBounds> region,
- const optional<std::string> cacheDir,
const optional<std::string> localFontFamily,
const ResourceOptions&);
diff --git a/platform/default/include/mbgl/storage/offline_database.hpp b/platform/default/include/mbgl/storage/offline_database.hpp
index afce87b542..e19dcfade9 100644
--- a/platform/default/include/mbgl/storage/offline_database.hpp
+++ b/platform/default/include/mbgl/storage/offline_database.hpp
@@ -78,8 +78,8 @@ public:
std::exception_ptr invalidateRegion(int64_t regionID);
// Return value is (response, stored size)
- optional<std::pair<Response, uint64_t>> getRegionResource(int64_t regionID, const Resource&);
- optional<int64_t> hasRegionResource(int64_t regionID, const Resource&);
+ optional<std::pair<Response, uint64_t>> getRegionResource(const Resource&);
+ optional<int64_t> hasRegionResource(const Resource&);
uint64_t putRegionResource(int64_t regionID, const Resource&, const Response&);
void putRegionResources(int64_t regionID, const std::list<std::tuple<Resource, Response>>&, OfflineRegionStatus&);
@@ -92,6 +92,7 @@ public:
bool offlineMapboxTileCountLimitExceeded();
uint64_t getOfflineMapboxTileCount();
bool exceedsOfflineMapboxTileCountLimit(const Resource&);
+ void markUsedResources(int64_t regionID, const std::list<Resource>&);
private:
void initialize();
diff --git a/platform/default/include/mbgl/storage/offline_download.hpp b/platform/default/include/mbgl/storage/offline_download.hpp
index 84b319fb5a..53b42ae9d1 100644
--- a/platform/default/include/mbgl/storage/offline_download.hpp
+++ b/platform/default/include/mbgl/storage/offline_download.hpp
@@ -46,7 +46,7 @@ private:
* While the request is in progress, it is recorded in `requests`. If the download
* is deactivated, all in progress requests are cancelled.
*/
- void ensureResource(const Resource&, std::function<void (Response)> = {});
+ void ensureResource(Resource&&, std::function<void (Response)> = {});
void onMapboxTileCountLimitExceeded();
@@ -60,10 +60,12 @@ private:
std::list<std::unique_ptr<AsyncRequest>> requests;
std::unordered_set<std::string> requiredSourceURLs;
std::deque<Resource> resourcesRemaining;
+ std::list<Resource> resourcesToBeMarkedAsUsed;
std::list<std::tuple<Resource, Response>> buffer;
void queueResource(Resource&&);
void queueTiles(style::SourceType, uint16_t tileSize, const Tileset&);
+ void markPendingUsedResources();
};
} // namespace mbgl
diff --git a/platform/default/src/mbgl/gfx/headless_frontend.cpp b/platform/default/src/mbgl/gfx/headless_frontend.cpp
index f5e6b7f482..287567adbd 100644
--- a/platform/default/src/mbgl/gfx/headless_frontend.cpp
+++ b/platform/default/src/mbgl/gfx/headless_frontend.cpp
@@ -10,16 +10,14 @@
namespace mbgl {
HeadlessFrontend::HeadlessFrontend(float pixelRatio_,
- const optional<std::string> programCacheDir,
const gfx::ContextMode contextMode,
const optional<std::string> localFontFamily)
: HeadlessFrontend(
- { 256, 256 }, pixelRatio_, programCacheDir, contextMode, localFontFamily) {
+ { 256, 256 }, pixelRatio_, contextMode, localFontFamily) {
}
HeadlessFrontend::HeadlessFrontend(Size size_,
float pixelRatio_,
- const optional<std::string> programCacheDir,
const gfx::ContextMode contextMode,
const optional<std::string> localFontFamily)
: size(size_),
@@ -38,7 +36,7 @@ HeadlessFrontend::HeadlessFrontend(Size size_,
renderer->render(*updateParameters_);
}
}),
- renderer(std::make_unique<Renderer>(*getBackend(), pixelRatio, programCacheDir, localFontFamily)) {
+ renderer(std::make_unique<Renderer>(*getBackend(), pixelRatio, localFontFamily)) {
}
HeadlessFrontend::~HeadlessFrontend() = default;
diff --git a/platform/default/src/mbgl/map/map_snapshotter.cpp b/platform/default/src/mbgl/map/map_snapshotter.cpp
index f0b107e77e..5f4060e3f0 100644
--- a/platform/default/src/mbgl/map/map_snapshotter.cpp
+++ b/platform/default/src/mbgl/map/map_snapshotter.cpp
@@ -19,7 +19,6 @@ public:
const float pixelRatio,
const optional<CameraOptions> cameraOptions,
const optional<LatLngBounds> region,
- const optional<std::string> programCacheDir,
const optional<std::string> localFontFamily,
const ResourceOptions& resourceOptions);
@@ -50,11 +49,10 @@ MapSnapshotter::Impl::Impl(const std::pair<bool, std::string> style,
const float pixelRatio,
const optional<CameraOptions> cameraOptions,
const optional<LatLngBounds> region,
- const optional<std::string> programCacheDir,
const optional<std::string> localFontFamily,
const ResourceOptions& resourceOptions)
: frontend(
- size, pixelRatio, programCacheDir, gfx::ContextMode::Unique, localFontFamily),
+ size, pixelRatio, gfx::ContextMode::Unique, localFontFamily),
map(frontend,
MapObserver::nullObserver(),
MapOptions().withMapMode(MapMode::Static).withSize(size).withPixelRatio(pixelRatio),
@@ -168,12 +166,11 @@ MapSnapshotter::MapSnapshotter(const std::pair<bool, std::string> style,
const float pixelRatio,
const optional<CameraOptions> cameraOptions,
const optional<LatLngBounds> region,
- const optional<std::string> programCacheDir,
const optional<std::string> localFontFamily,
const ResourceOptions& resourceOptions)
: impl(std::make_unique<util::Thread<MapSnapshotter::Impl>>(
"Map Snapshotter", style, size, pixelRatio, cameraOptions,
- region, programCacheDir, localFontFamily, resourceOptions.clone())) {}
+ region, localFontFamily, resourceOptions.clone())) {}
MapSnapshotter::~MapSnapshotter() = default;
diff --git a/platform/default/src/mbgl/storage/offline_database.cpp b/platform/default/src/mbgl/storage/offline_database.cpp
index d85b560d5a..83eea7bcc4 100644
--- a/platform/default/src/mbgl/storage/offline_database.cpp
+++ b/platform/default/src/mbgl/storage/offline_database.cpp
@@ -877,27 +877,15 @@ std::exception_ptr OfflineDatabase::deleteRegion(OfflineRegion&& region) try {
return std::current_exception();
}
-optional<std::pair<Response, uint64_t>> OfflineDatabase::getRegionResource(int64_t regionID, const Resource& resource) try {
- auto response = getInternal(resource);
-
- if (response) {
- markUsed(regionID, resource);
- }
-
- return response;
+optional<std::pair<Response, uint64_t>> OfflineDatabase::getRegionResource(const Resource& resource) try {
+ return getInternal(resource);
} catch (const mapbox::sqlite::Exception& ex) {
handleError(ex, "read region resource");
return nullopt;
}
-optional<int64_t> OfflineDatabase::hasRegionResource(int64_t regionID, const Resource& resource) try {
- auto response = hasInternal(resource);
-
- if (response) {
- markUsed(regionID, resource);
- }
-
- return response;
+optional<int64_t> OfflineDatabase::hasRegionResource(const Resource& resource) try {
+ return hasInternal(resource);
} catch (const mapbox::sqlite::Exception& ex) {
handleError(ex, "query region resource");
return nullopt;
@@ -1278,6 +1266,19 @@ bool OfflineDatabase::exceedsOfflineMapboxTileCountLimit(const Resource& resourc
&& offlineMapboxTileCountLimitExceeded();
}
+void OfflineDatabase::markUsedResources(int64_t regionID, const std::list<Resource>& resources) try {
+ if (!db) {
+ initialize();
+ }
+ mapbox::sqlite::Transaction transaction(*db);
+ for (const auto& resource : resources) {
+ markUsed(regionID, resource);
+ }
+ transaction.commit();
+} catch (const mapbox::sqlite::Exception& ex) {
+ handleError(ex, "mark resources as used");
+}
+
std::exception_ptr OfflineDatabase::resetDatabase() try {
removeExisting();
initialize();
diff --git a/platform/default/src/mbgl/storage/offline_download.cpp b/platform/default/src/mbgl/storage/offline_download.cpp
index bdcc99cc15..939164bd35 100644
--- a/platform/default/src/mbgl/storage/offline_download.cpp
+++ b/platform/default/src/mbgl/storage/offline_download.cpp
@@ -21,6 +21,13 @@
#include <set>
+namespace {
+
+const size_t kResourcesBatchSize = 64;
+const size_t kMarkBatchSize = 200;
+
+} // namespace
+
namespace mbgl {
using namespace style;
@@ -144,8 +151,9 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
auto handleTiledSource = [&] (const variant<std::string, Tileset>& urlOrTileset, const uint16_t tileSize) {
if (urlOrTileset.is<Tileset>()) {
- result->requiredResourceCount +=
- tileCount(definition, type, tileSize, urlOrTileset.get<Tileset>().zoomRange);
+ uint64_t tileSourceCount = tileCount(definition, type, tileSize, urlOrTileset.get<Tileset>().zoomRange);
+ result->requiredTileCount += tileSourceCount;
+ result->requiredResourceCount += tileSourceCount;
} else {
result->requiredResourceCount += 1;
const auto& url = urlOrTileset.get<std::string>();
@@ -154,8 +162,9 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
style::conversion::Error error;
optional<Tileset> tileset = style::conversion::convertJSON<Tileset>(*sourceResponse->data, error);
if (tileset) {
- result->requiredResourceCount +=
- tileCount(definition, type, tileSize, (*tileset).zoomRange);
+ uint64_t tileSourceCount = tileCount(definition, type, tileSize, (*tileset).zoomRange);
+ result->requiredTileCount += tileSourceCount;
+ result->requiredResourceCount += tileSourceCount;
}
} else {
result->requiredResourceCountIsPrecise = false;
@@ -228,7 +237,7 @@ void OfflineDownload::activateDownload() {
styleResource.setPriority(Resource::Priority::Low);
styleResource.setUsage(Resource::Usage::Offline);
- ensureResource(styleResource, [&](Response styleResponse) {
+ ensureResource(std::move(styleResource), [&](Response styleResponse) {
status.requiredResourceCountIsPrecise = true;
style::Parser parser;
@@ -250,7 +259,7 @@ void OfflineDownload::activateDownload() {
sourceResource.setPriority(Resource::Priority::Low);
sourceResource.setUsage(Resource::Usage::Offline);
- ensureResource(sourceResource, [=](Response sourceResponse) {
+ ensureResource(std::move(sourceResource), [=](Response sourceResponse) {
style::conversion::Error error;
optional<Tileset> tileset = style::conversion::convertJSON<Tileset>(*sourceResponse.data, error);
if (tileset) {
@@ -353,12 +362,15 @@ void OfflineDownload::activateDownload() {
*/
void OfflineDownload::continueDownload() {
if (resourcesRemaining.empty() && status.complete()) {
+ markPendingUsedResources();
setState(OfflineRegionDownloadState::Inactive);
return;
}
+ if (resourcesToBeMarkedAsUsed.size() >= kMarkBatchSize) markPendingUsedResources();
+
while (!resourcesRemaining.empty() && requests.size() < onlineFileSource.getMaximumConcurrentRequests()) {
- ensureResource(resourcesRemaining.front());
+ ensureResource(std::move(resourcesRemaining.front()));
resourcesRemaining.pop_front();
}
}
@@ -373,12 +385,16 @@ void OfflineDownload::queueResource(Resource&& resource) {
resource.setPriority(Resource::Priority::Low);
resource.setUsage(Resource::Usage::Offline);
status.requiredResourceCount++;
+ if (resource.kind == mbgl::Resource::Kind::Tile) {
+ status.requiredTileCount++;
+ }
resourcesRemaining.push_front(std::move(resource));
}
void OfflineDownload::queueTiles(SourceType type, uint16_t tileSize, const Tileset& tileset) {
tileCover(definition, type, tileSize, tileset.zoomRange, [&](const auto& tile) {
status.requiredResourceCount++;
+ status.requiredTileCount++;
auto tileResource = Resource::tile(
tileset.tiles[0], definition.match([](auto& def) { return def.pixelRatio; }),
@@ -391,7 +407,12 @@ void OfflineDownload::queueTiles(SourceType type, uint16_t tileSize, const Tiles
});
}
-void OfflineDownload::ensureResource(const Resource& resource,
+void OfflineDownload::markPendingUsedResources() {
+ offlineDatabase.markUsedResources(id, resourcesToBeMarkedAsUsed);
+ resourcesToBeMarkedAsUsed.clear();
+}
+
+void OfflineDownload::ensureResource(Resource&& resource,
std::function<void(Response)> callback) {
assert(resource.priority == Resource::Priority::Low);
assert(resource.usage == Resource::Usage::Offline);
@@ -399,24 +420,29 @@ void OfflineDownload::ensureResource(const Resource& resource,
auto workRequestsIt = requests.insert(requests.begin(), nullptr);
*workRequestsIt = util::RunLoop::Get()->invokeCancellable([=]() {
requests.erase(workRequestsIt);
-
+ const auto resourceKind = resource.kind;
auto getResourceSizeInDatabase = [&] () -> optional<int64_t> {
+ optional<int64_t> result;
if (!callback) {
- return offlineDatabase.hasRegionResource(id, resource);
- }
- optional<std::pair<Response, uint64_t>> response = offlineDatabase.getRegionResource(id, resource);
- if (!response) {
- return {};
+ result = offlineDatabase.hasRegionResource(resource);
+ } else {
+ optional<std::pair<Response, uint64_t>> response = offlineDatabase.getRegionResource(resource);
+ if (response) {
+ callback(response->first);
+ result = response->second;
+ }
}
- callback(response->first);
- return response->second;
+
+ if (result) resourcesToBeMarkedAsUsed.emplace_back(std::move(resource));
+ return result;
};
optional<int64_t> offlineResponse = getResourceSizeInDatabase();
if (offlineResponse) {
+ assert(!resourcesToBeMarkedAsUsed.empty());
status.completedResourceCount++;
status.completedResourceSize += *offlineResponse;
- if (resource.kind == Resource::Kind::Tile) {
+ if (resourceKind == Resource::Kind::Tile) {
status.completedTileCount += 1;
status.completedTileSize += *offlineResponse;
}
@@ -448,7 +474,7 @@ void OfflineDownload::ensureResource(const Resource& resource,
buffer.emplace_back(resource, onlineResponse);
// Flush buffer periodically
- if (buffer.size() == 64 || resourcesRemaining.size() == 0) {
+ if (buffer.size() == kResourcesBatchSize || resourcesRemaining.empty()) {
try {
offlineDatabase.putRegionResources(id, buffer, status);
} catch (const MapboxTileLimitExceededException&) {
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index 37612a89b8..fae5599439 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -4,10 +4,16 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
## master
-### Styles and rendering
-* Fixed rendering and collision detection issues with using `text-variable-anchor` and `icon-text-fit` properties on the same layer. ([#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367))
+* Fixed an issue that caused the tilt gesture to trigger too easily and conflict with pinch or pan gestures. ([#15349](https://github.com/mapbox/mapbox-gl-native/pull/15349))
+* Fixed a bug with annotation view positions after camera transitions. ([#15122](https://github.com/mapbox/mapbox-gl-native/pull/15122/))
+
+ ### Performance improvements
+
+ * Mark used offline region resources in batches. ([#15521](https://github.com/mapbox/mapbox-gl-native/pull/15521))
+
+## 5.3.0 - August 28, 2019
-## 5.3.0
+This release changes how offline tile requests are billed — they are now billed on a pay-as-you-go basis and all developers are able raise the offline tile limit for their users. Offline requests were previously exempt from monthly active user (MAU) billing and increasing the offline per-user tile limit to more than 6,000 tiles required the purchase of an enterprise license. By upgrading to this release, you are opting into the changes outlined in [this blog post](https://blog.mapbox.com/offline-maps-for-all-bb0fc51827be) and [#15380](https://github.com/mapbox/mapbox-gl-native/pull/15380).
### Styles and rendering
@@ -16,13 +22,18 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
* Fixed an issue where animated camera transitions zoomed in or out too dramatically. ([#15281](https://github.com/mapbox/mapbox-gl-native/pull/15281))
* Enabled variable label placement when `MGLSymbolStyleLayer.textAllowsOverlap` is set to true. ([#15354](https://github.com/mapbox/mapbox-gl-native/pull/15354))
* Added the `MGLSymbolStyleLayer.textWritingModes` layout property. This property can be set to `MGLTextWritingModeHorizontal` or `MGLTextWritingModeVertical`. ([#14932](https://github.com/mapbox/mapbox-gl-native/pull/14932))
+* Fixed rendering and collision detection issues with using `MGLSymbolStyleLayer.textVariableAnchor` and `MGLSymbolStyleLayer.iconTextFit` properties on the same layer. ([#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367))
+* Fixed symbol overlap when zooming out quickly. ([15416](https://github.com/mapbox/mapbox-gl-native/pull/15416))
+* Fixed a rendering issue where non-SDF icons would be treated as SDF icons if they are in the same layer. ([#15456](https://github.com/mapbox/mapbox-gl-native/pull/15456))
### Other changes
-* Fixed use of objects after moving, potentially causing crashes. [#15408](https://github.com/mapbox/mapbox-gl-native/pull/1540)
+* Fixed a bug where glyphs generated through the LocalGlyphRasterizer interface were changing fonts during some zoom changes. ([#15407](https://github.com/mapbox/mapbox-gl-native/pull/15407))
+* Fixed use of objects after moving, potentially causing crashes. ([#15408](https://github.com/mapbox/mapbox-gl-native/pull/15408))
* Fixed a possible crash that could be caused by invoking the wrong layer implementation casting function. ([#15398](https://github.com/mapbox/mapbox-gl-native/pull/15398))
* Fixed a rare crash when tile download requests returned “404 Not Found” errors. ([#15313](https://github.com/mapbox/mapbox-gl-native/pull/15313))
* `MGLLoggingLevel` has been updated to better match core log levels. You can now use `MGLLoggingConfiguration.loggingLevel` to filter logs from core. ([#15120](https://github.com/mapbox/mapbox-gl-native/pull/15120))
+* Fixed an issue where the scale bar could show `0 mm` instead of `0`. ([#15381](https://github.com/mapbox/mapbox-gl-native/pull/15381))
## 4.11.2 - July 30, 2019
diff --git a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m b/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.mm
index f129277e87..1b3603419e 100644
--- a/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.m
+++ b/platform/ios/Integration Tests/Annotation Tests/MGLAnnotationViewIntegrationTests.mm
@@ -4,6 +4,13 @@
#import "MGLTestLocationManager.h"
#import "MGLCompactCalloutView.h"
+#import "MGLGeometry_Private.h"
+#import "MGLMapView_Private.h"
+
+#include <mbgl/util/geo.hpp>
+#include <mbgl/map/camera.hpp>
+#include <mbgl/map/map.hpp>
+
@interface MGLTestCalloutView : MGLCompactCalloutView
@property (nonatomic) BOOL implementsMarginHints;
@end
@@ -21,6 +28,10 @@
@interface MGLMapView (Tests)
- (MGLAnnotationTag)annotationTagAtPoint:(CGPoint)point persistingResults:(BOOL)persist;
+- (id <MGLAnnotation>)annotationWithTag:(MGLAnnotationTag)tag;
+- (MGLMapCamera *)cameraByRotatingToDirection:(CLLocationDirection)degrees aroundAnchorPoint:(CGPoint)anchorPoint;
+- (MGLMapCamera *)cameraByZoomingToZoomLevel:(double)zoom aroundAnchorPoint:(CGPoint)anchorPoint;
+- (MGLMapCamera *)cameraForCameraOptions:(const mbgl::CameraOptions &)cameraOptions;
@property (nonatomic) UIView<MGLCalloutView> *calloutViewForSelectedAnnotation;
@end
@@ -502,6 +513,267 @@ static const CGPoint kAnnotationRelativeScale = { 0.05f, 0.125f };
XCTAssertEqual(originalFrame.origin.y + offset.y, offsetFrame.origin.y);
}
+#pragma mark - Rotating/zooming
+
+- (void)testSelectingAnnotationWhenMapIsRotated {
+
+ CLLocationCoordinate2D coordinates[] = {
+ { 40.0, 40.0 },
+ { NAN, NAN }
+ };
+
+ NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates];
+ MGLPointAnnotation *annotation = annotations.firstObject;
+
+ // Rotate
+ CLLocationDirection lastAngle = 0.0;
+
+ srand48(0);
+ for (NSInteger iter = 0; iter < 10; iter++ ) {
+
+ CLLocationDirection angle = (CLLocationDirection)((drand48()*1080.0) - 540.0);
+
+ CGPoint anchor = CGPointMake(drand48()*CGRectGetWidth(self.mapView.bounds), drand48()*CGRectGetHeight(self.mapView.bounds));
+
+ NSString *activityTitle = [NSString stringWithFormat:@"Rotate to: %0.1f from: %0.1f", angle, lastAngle];
+ [XCTContext runActivityNamed:activityTitle
+ block:^(id<XCTActivity> _Nonnull activity) {
+
+ MGLMapCamera *toCamera = [self.mapView cameraByRotatingToDirection:angle aroundAnchorPoint:anchor];
+ [self internalTestSelecting:annotation withCamera:toCamera];
+ }];
+
+ lastAngle = angle;
+ }
+}
+
+- (void)testSelectingAnnotationWhenMapIsScaled {
+
+ CLLocationCoordinate2D coordinates[] = {
+ { 0.005, 0.005 },
+ { NAN, NAN }
+ };
+
+ NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates];
+ MGLPointAnnotation *annotation = annotations.firstObject;
+
+ CGPoint anchor = CGPointMake(CGRectGetMidX(self.mapView.bounds), CGRectGetMidY(self.mapView.bounds));
+
+ srand48(0);
+ for (NSInteger iter = 0; iter < 10; iter++ ) {
+
+ double zoom = (double)(drand48()*14.0);
+
+ NSString *activityTitle = [NSString stringWithFormat:@"Zoom to %0.1f", zoom];
+ [XCTContext runActivityNamed:activityTitle
+ block:^(id<XCTActivity> _Nonnull activity) {
+ MGLMapCamera *toCamera = [self.mapView cameraByZoomingToZoomLevel:zoom aroundAnchorPoint:anchor];
+ [self internalTestSelecting:annotation withCamera:toCamera];
+ }];
+ }
+}
+
+- (void)testSelectingAnnotationWhenMapIsScaledAndRotated {
+
+ CLLocationCoordinate2D coordinates[] = {
+ { 0.005, 0.005 },
+ { NAN, NAN }
+ };
+
+ NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates];
+ MGLPointAnnotation *annotation = annotations.firstObject;
+
+ srand48(0);
+ for (NSInteger iter = 0; iter < 10; iter++ ) {
+
+ double zoom = (double)(7.0 + drand48()*7.0);
+ CLLocationDirection angle = (CLLocationDirection)((drand48()*1080.0) - 540.0);
+
+ CGPoint anchor = CGPointMake(drand48()*CGRectGetWidth(self.mapView.bounds), drand48()*CGRectGetHeight(self.mapView.bounds));
+
+ NSString *activityTitle = [NSString stringWithFormat:@"Zoom to %0.1f", zoom];
+ [XCTContext runActivityNamed:activityTitle
+ block:^(id<XCTActivity> _Nonnull activity)
+ {
+ mbgl::CameraOptions currentCameraOptions;
+
+ currentCameraOptions.bearing = angle;
+ currentCameraOptions.anchor = mbgl::ScreenCoordinate { anchor.x, anchor.y };
+ currentCameraOptions.zoom = zoom;
+ MGLMapCamera *toCamera = [self.mapView cameraForCameraOptions:currentCameraOptions];
+
+ [self internalTestSelecting:annotation withCamera:toCamera];
+ }];
+ }
+}
+
+
+- (void)testShowingAnnotationsThenSelectingAnimated {
+ [self internalTestShowingAnnotationsThenSelectingAnimated:YES];
+}
+
+- (void)testShowingAnnotationsThenSelecting {
+ [self internalTestShowingAnnotationsThenSelectingAnimated:NO];
+}
+
+- (void)internalTestShowingAnnotationsThenSelectingAnimated:(BOOL)animated {
+ srand48(0);
+
+ CGFloat maxXPadding = std::max(CGRectGetWidth(self.mapView.bounds)/5.0, 100.0);
+ CGFloat maxYPadding = std::max(CGRectGetHeight(self.mapView.bounds)/5.0, 100.0);
+
+ for (int i = 0; i < 10; i++) {
+ UIEdgeInsets edgePadding;
+ edgePadding.top = floor(drand48()*maxYPadding);
+ edgePadding.bottom = floor(drand48()*maxYPadding);
+ edgePadding.left = floor(drand48()*maxXPadding);
+ edgePadding.right = floor(drand48()*maxXPadding);
+
+ UIEdgeInsets contentInsets;
+ contentInsets.top = floor(drand48()*maxYPadding);
+ contentInsets.bottom = floor(drand48()*maxYPadding);
+ contentInsets.left = floor(drand48()*maxXPadding);
+ contentInsets.right = floor(drand48()*maxXPadding);
+
+ [self internalTestShowingAnnotationsThenSelectingAnimated:animated edgePadding:edgePadding contentInsets:contentInsets];
+ }
+}
+
+- (void)internalTestShowingAnnotationsThenSelectingAnimated:(BOOL)animated edgePadding:(UIEdgeInsets)edgeInsets contentInsets:(UIEdgeInsets)contentInsets {
+ CLLocationCoordinate2D coordinates[21];
+
+ for (int i = 0; i < (int)(sizeof(coordinates)/sizeof(coordinates[0])); i++)
+ {
+ coordinates[i].latitude = drand48();
+ coordinates[i].longitude = drand48();
+ }
+ coordinates[20] = CLLocationCoordinate2DMake(NAN, NAN);
+
+ NSArray *annotations = [self internalAddAnnotationsAtCoordinates:coordinates];
+
+ XCTestExpectation *showCompleted = [self expectationWithDescription:@"showCompleted"];
+
+ self.mapView.contentInset = contentInsets;
+ [self.mapView showAnnotations:annotations
+ edgePadding:edgeInsets
+ animated:animated
+ completionHandler:^{
+ [showCompleted fulfill];
+ }];
+
+ [self waitForExpectations:@[showCompleted] timeout:3.5];
+
+ // These tests will fail if this isn't here. But this isn't quite what we're
+ // seeing in https://github.com/mapbox/mapbox-gl-native/issues/15106
+ [self waitForCollisionDetectionToRun];
+
+ for (MGLPointAnnotation *point in annotations) {
+ [self internalSelectDeselectAnnotation:point];
+ }
+
+ [self.mapView removeAnnotations:annotations];
+ self.mapView.contentInset = UIEdgeInsetsZero;
+ [self waitForCollisionDetectionToRun];
+}
+
+- (NSArray*)internalAddAnnotationsAtCoordinates:(CLLocationCoordinate2D*)coordinates
+{
+ __block NSMutableArray *annotations = [NSMutableArray array];
+
+ [XCTContext runActivityNamed:@"Map setup"
+ block:^(id<XCTActivity> _Nonnull activity)
+ {
+
+ NSString * const MGLTestAnnotationReuseIdentifer = @"MGLTestAnnotationReuseIdentifer";
+
+ CGSize annotationSize = CGSizeMake(40.0, 40.0);
+
+ self.viewForAnnotation = ^MGLAnnotationView*(MGLMapView *view, id<MGLAnnotation> annotation2) {
+
+ if (![annotation2 isKindOfClass:[MGLPointAnnotation class]]) {
+ return nil;
+ }
+
+ // No dequeue
+ MGLAnnotationView *annotationView = [[MGLAnnotationView alloc] initWithAnnotation:annotation2 reuseIdentifier:MGLTestAnnotationReuseIdentifer];
+ annotationView.bounds = (CGRect){ .origin = CGPointZero, .size = annotationSize };
+ annotationView.backgroundColor = UIColor.redColor;
+ annotationView.enabled = YES;
+
+ return annotationView;
+ };
+
+ CLLocationCoordinate2D *coordinatePtr = coordinates;
+ while (!isnan(coordinatePtr->latitude)) {
+ CLLocationCoordinate2D coordinate = *coordinatePtr++;
+
+ MGLPointAnnotation *annotation = [[MGLPointAnnotation alloc] init];
+ annotation.title = NSStringFromSelector(_cmd);
+ annotation.coordinate = coordinate;
+ [annotations addObject:annotation];
+ }
+
+ [self.mapView addAnnotations:annotations];
+
+ }];
+
+ NSArray *copiedAnnotations = [annotations copy];
+ annotations = nil;
+
+ return copiedAnnotations;
+}
+
+- (void)internalTestSelecting:(MGLPointAnnotation*)point withCamera:(MGLMapCamera*)camera {
+
+ // Rotate
+ XCTestExpectation *rotationCompleted = [self expectationWithDescription:@"rotationCompleted"];
+ [self.mapView setCamera:camera withDuration:0.1 animationTimingFunction:nil completionHandler:^{
+ [rotationCompleted fulfill];
+ }];
+
+ [self waitForExpectations:@[rotationCompleted] timeout:1.5];
+
+ // Collision detection may not have completed, if not we may not get our annotation.
+ [self waitForCollisionDetectionToRun];
+
+ // Look up annotation at point
+ [self internalSelectDeselectAnnotation:point];
+}
+
+- (void)internalSelectDeselectAnnotation:(MGLPointAnnotation*)point {
+ [XCTContext runActivityNamed:[NSString stringWithFormat:@"Select annotation: %@", point]
+ block:^(id<XCTActivity> _Nonnull activity)
+ {
+ CGPoint annotationPoint = [self.mapView convertCoordinate:point.coordinate toPointToView:self.mapView];
+
+ MGLAnnotationTag tagAtPoint = [self.mapView annotationTagAtPoint:annotationPoint persistingResults:YES];
+ if (tagAtPoint != UINT32_MAX)
+ {
+ id <MGLAnnotation> annotation = [self.mapView annotationWithTag:tagAtPoint];
+ XCTAssertNotNil(annotation);
+
+ // Select
+ XCTestExpectation *selectionCompleted = [self expectationWithDescription:@"Selection completed"];
+ [self.mapView selectAnnotation:annotation moveIntoView:NO animateSelection:NO completionHandler:^{
+ [selectionCompleted fulfill];
+ }];
+
+ [self waitForExpectations:@[selectionCompleted] timeout:0.05];
+
+ XCTAssert(self.mapView.selectedAnnotations.count == 1, @"There should only be 1 selected annotation");
+ XCTAssertEqualObjects(self.mapView.selectedAnnotations.firstObject, annotation, @"The annotation should be selected");
+
+ // Deselect
+ [self.mapView deselectAnnotation:annotation animated:NO];
+ }
+ else
+ {
+ XCTFail(@"Should be an annotation at this point: %@", NSStringFromCGPoint(annotationPoint));
+ }
+ }];
+
+}
+
#pragma mark - Utilities
- (void)runRunLoop {
@@ -529,6 +801,7 @@ static const CGPoint kAnnotationRelativeScale = { 0.05f, 0.125f };
- (void)waitForCollisionDetectionToRun {
XCTAssertNil(self.renderFinishedExpectation, @"Incorrect test setup");
+ [self.mapView setNeedsRerender];
self.renderFinishedExpectation = [self expectationWithDescription:@"Map view should be rendered"];
XCTestExpectation *timerExpired = [self expectationWithDescription:@"Timer expires"];
diff --git a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
index dedafdb83a..07d8698f38 100644
--- a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
+++ b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.h
@@ -26,6 +26,7 @@
@interface MGLMapViewIntegrationTest : XCTestCase <MGLMapViewDelegate>
@property (nonatomic) MGLMapView *mapView;
+@property (nonatomic) UIWindow *window;
@property (nonatomic) MGLStyle *style;
@property (nonatomic) XCTestExpectation *styleLoadingExpectation;
@property (nonatomic) XCTestExpectation *renderFinishedExpectation;
diff --git a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
index 2c89bb1c77..3fa191dfcd 100644
--- a/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
+++ b/platform/ios/Integration Tests/MGLMapViewIntegrationTest.m
@@ -2,6 +2,7 @@
@interface MGLMapView (MGLMapViewIntegrationTest)
- (void)updateFromDisplayLink:(CADisplayLink *)displayLink;
+- (void)setNeedsRerender;
@end
@implementation MGLMapViewIntegrationTest
@@ -43,9 +44,9 @@
UIView *superView = [[UIView alloc] initWithFrame:UIScreen.mainScreen.bounds];
[superView addSubview:self.mapView];
- UIWindow *window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
- [window addSubview:superView];
- [window makeKeyAndVisible];
+ self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
+ [self.window addSubview:superView];
+ [self.window makeKeyAndVisible];
if (!self.mapView.style) {
[self waitForMapViewToFinishLoadingStyleWithTimeout:10];
@@ -57,6 +58,7 @@
self.renderFinishedExpectation = nil;
self.mapView = nil;
self.style = nil;
+ self.window = nil;
[MGLAccountManager setAccessToken:nil];
[super tearDown];
@@ -133,9 +135,10 @@
- (void)waitForMapViewToBeRenderedWithTimeout:(NSTimeInterval)timeout {
XCTAssertNil(self.renderFinishedExpectation);
- [self.mapView setNeedsDisplay];
+ [self.mapView setNeedsRerender];
self.renderFinishedExpectation = [self expectationWithDescription:@"Map view should be rendered"];
[self waitForExpectations:@[self.renderFinishedExpectation] timeout:timeout];
+ self.renderFinishedExpectation = nil;
}
- (void)waitForExpectations:(NSArray<XCTestExpectation *> *)expectations timeout:(NSTimeInterval)seconds {
diff --git a/platform/ios/Integration Tests/MGLMapViewPendingBlockTests.m b/platform/ios/Integration Tests/MGLMapViewPendingBlockTests.m
new file mode 100644
index 0000000000..ad71dafd48
--- /dev/null
+++ b/platform/ios/Integration Tests/MGLMapViewPendingBlockTests.m
@@ -0,0 +1,367 @@
+#import "MGLMapViewIntegrationTest.h"
+#import "MGLTestUtility.h"
+
+@interface MGLMapView (MGLMapViewPendingBlockTests)
+@property (nonatomic) NSMutableArray *pendingCompletionBlocks;
+- (void)pauseRendering:(__unused NSNotification *)notification;
+@end
+
+@interface MGLMapViewPendingBlockTests : MGLMapViewIntegrationTest
+@property (nonatomic, copy) void (^observation)(NSDictionary*);
+@property (nonatomic) BOOL completionHandlerCalled;
+@end
+
+@implementation MGLMapViewPendingBlockTests
+
+- (void)testSetCenterCoordinate {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
+ zoomLevel:10.0
+ direction:0
+ animated:NO
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testSetCenterCoordinateAnimated {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
+ zoomLevel:10.0
+ direction:0
+ animated:YES
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testSetVisibleCoordinateBounds {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ [strongSelf.mapView setVisibleCoordinateBounds:unitBounds
+ edgePadding:UIEdgeInsetsZero
+ animated:NO
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testSetVisibleCoordinateBoundsAnimated {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ [strongSelf.mapView setVisibleCoordinateBounds:unitBounds
+ edgePadding:UIEdgeInsetsZero
+ animated:YES
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testSetCamera {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
+
+ [strongSelf.mapView setCamera:camera withDuration:0.0 animationTimingFunction:nil completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testSetCameraAnimated {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
+
+ [strongSelf.mapView setCamera:camera withDuration:0.3 animationTimingFunction:nil completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+// Marked as pending due to https://github.com/mapbox/mapbox-gl-native/issues/15471
+- (void)testFlyToCameraPENDING {
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
+
+ [strongSelf.mapView flyToCamera:camera withDuration:0.0 completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+- (void)testFlyToCameraAnimated {
+
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ MGLCoordinateBounds unitBounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(0, 0), CLLocationCoordinate2DMake(1, 1));
+ MGLMapCamera *camera = [strongSelf.mapView cameraThatFitsCoordinateBounds:unitBounds];
+
+ [strongSelf.mapView flyToCamera:camera withDuration:0.3 completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:nil];
+}
+
+
+#pragma mark - test interrupting regular rendering
+
+- (void)testSetCenterCoordinateSetHidden {
+
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
+ zoomLevel:10.0
+ direction:0
+ animated:NO
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ dispatch_block_t addedToPending = ^{
+ __typeof__(self) strongSelf = weakSelf;
+
+ MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled);
+
+ // Now hide the mapview
+ strongSelf.mapView.hidden = YES;
+
+ MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled);
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:addedToPending];
+}
+
+- (void)testSetCenterCoordinatePauseRendering {
+
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
+ zoomLevel:10.0
+ direction:0
+ animated:NO
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ dispatch_block_t addedToPending = ^{
+ __typeof__(self) strongSelf = weakSelf;
+
+ MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled);
+
+ // Pause rendering, stopping display link
+ [strongSelf.mapView pauseRendering:nil];
+
+ MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled);
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:addedToPending];
+}
+
+- (void)testSetCenterCoordinateRemoveFromSuperview {
+
+ __typeof__(self) weakSelf = self;
+
+ void (^transition)(dispatch_block_t) = ^(dispatch_block_t completion) {
+ __typeof__(self) strongSelf = weakSelf;
+
+ if (strongSelf) {
+ [strongSelf.mapView setCenterCoordinate:CLLocationCoordinate2DMake(10.0, 10.0)
+ zoomLevel:10.0
+ direction:0
+ animated:NO
+ completionHandler:completion];
+ }
+ else {
+ completion();
+ }
+ };
+
+ dispatch_block_t addedToPending = ^{
+ __typeof__(self) strongSelf = weakSelf;
+
+ MGLTestAssert(strongSelf, !strongSelf.completionHandlerCalled);
+
+ // Remove from window, triggering validateDisplayLink
+ [strongSelf.mapView removeFromSuperview];
+
+ MGLTestAssert(strongSelf, strongSelf.completionHandlerCalled);
+ };
+
+ [self internalTestCompletionBlockAddedToPendingForTestName:NSStringFromSelector(_cmd)
+ transition:transition
+ addToPendingCallback:addedToPending];
+}
+
+#pragma mark - Shared utility methods
+
+- (void)internalTestCompletionBlockAddedToPendingForTestName:(NSString *)testName
+ transition:(void (^)(dispatch_block_t))transition
+ addToPendingCallback:(dispatch_block_t)addToPendingCallback {
+
+ XCTestExpectation *expectation = [self expectationWithDescription:testName];
+
+ __weak __typeof__(self) myself = self;
+
+ dispatch_block_t block = ^{
+ myself.completionHandlerCalled = YES;
+ [expectation fulfill];
+ };
+
+ XCTAssertNotNil(transition);
+ transition(block);
+
+ XCTAssert(!self.completionHandlerCalled);
+ XCTAssert(self.mapView.pendingCompletionBlocks.count == 0);
+
+ __block BOOL blockAddedToPendingBlocks = NO;
+
+ // Observes changes to pendingCompletionBlocks (including additions)
+ self.observation = ^(NSDictionary *change){
+
+ NSLog(@"change = %@ count = %lu", change, myself.mapView.pendingCompletionBlocks.count);
+
+ NSArray *value = change[NSKeyValueChangeNewKey];
+
+ MGLTestAssert(myself, [value isKindOfClass:[NSArray class]]);
+
+ if (value.count > 0) {
+ MGLTestAssert(myself, [value containsObject:block]);
+ MGLTestAssert(myself, !blockAddedToPendingBlocks);
+ if ([myself.mapView.pendingCompletionBlocks containsObject:block]) {
+ blockAddedToPendingBlocks = YES;
+
+ if (addToPendingCallback) {
+ addToPendingCallback();
+ }
+ }
+ }
+ };
+
+ [self.mapView addObserver:self forKeyPath:@"pendingCompletionBlocks" options:NSKeyValueObservingOptionNew context:_cmd];
+
+ [self waitForExpectations:@[expectation] timeout:0.5];
+
+ XCTAssert(blockAddedToPendingBlocks);
+ XCTAssert(self.completionHandlerCalled);
+ XCTAssert(self.mapView.pendingCompletionBlocks.count == 0);
+
+ [self.mapView removeObserver:self forKeyPath:@"pendingCompletionBlocks" context:_cmd];
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
+ if (self.observation) {
+ self.observation(change);
+ }
+}
+@end
diff --git a/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec b/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec
index 77ff18c104..4a781ba688 100644
--- a/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-snapshot-dynamic.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '5.3.0-alpha.3'
+ version = '5.3.0'
m.name = 'Mapbox-iOS-SDK-snapshot-dynamic'
m.version = "#{version}-snapshot"
diff --git a/platform/ios/Mapbox-iOS-SDK-stripped.podspec b/platform/ios/Mapbox-iOS-SDK-stripped.podspec
index 5c8b30220a..3d37e26c69 100644
--- a/platform/ios/Mapbox-iOS-SDK-stripped.podspec
+++ b/platform/ios/Mapbox-iOS-SDK-stripped.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '5.3.0-alpha.3'
+ version = '5.3.0'
m.name = 'Mapbox-iOS-SDK-stripped'
m.version = "#{version}-stripped"
diff --git a/platform/ios/Mapbox-iOS-SDK.podspec b/platform/ios/Mapbox-iOS-SDK.podspec
index c356a3c12d..2901dd6720 100644
--- a/platform/ios/Mapbox-iOS-SDK.podspec
+++ b/platform/ios/Mapbox-iOS-SDK.podspec
@@ -1,6 +1,6 @@
Pod::Spec.new do |m|
- version = '5.3.0-alpha.3'
+ version = '5.3.0'
m.name = 'Mapbox-iOS-SDK'
m.version = version
diff --git a/platform/ios/app/MBXState.h b/platform/ios/app/MBXState.h
index 7cf064acd8..346c31d586 100644
--- a/platform/ios/app/MBXState.h
+++ b/platform/ios/app/MBXState.h
@@ -12,7 +12,6 @@ FOUNDATION_EXTERN NSString *const MBXShowsZoomLevelOrnament;
FOUNDATION_EXTERN NSString *const MBXShowsTimeFrameGraph;
FOUNDATION_EXTERN NSString *const MBXMapFramerateMeasurementEnabled;
FOUNDATION_EXTERN NSString *const MBXDebugMaskValue;
-FOUNDATION_EXTERN NSString *const MBXDebugLoggingEnabled;
FOUNDATION_EXTERN NSString *const MBXReuseQueueStatsEnabled;
@interface MBXState : NSObject <NSSecureCoding>
@@ -26,7 +25,6 @@ FOUNDATION_EXTERN NSString *const MBXReuseQueueStatsEnabled;
@property (nonatomic) BOOL showsTimeFrameGraph;
@property (nonatomic) BOOL framerateMeasurementEnabled;
@property (nonatomic) MGLMapDebugMaskOptions debugMask;
-@property (nonatomic) BOOL debugLoggingEnabled;
@property (nonatomic) BOOL reuseQueueStatsEnabled;
@property (nonatomic, readonly) NSString *debugDescription;
diff --git a/platform/ios/app/MBXState.m b/platform/ios/app/MBXState.m
index 0365306637..455961e88a 100644
--- a/platform/ios/app/MBXState.m
+++ b/platform/ios/app/MBXState.m
@@ -6,7 +6,6 @@ NSString *const MBXShowsUserLocation = @"MBXShowsUserLocation";
NSString *const MBXDebugMaskValue = @"MBXDebugMaskValue";
NSString *const MBXShowsZoomLevelOrnament = @"MBXShowsZoomLevelOrnament";
NSString *const MBXShowsTimeFrameGraph = @"MBXShowsFrameTimeGraph";
-NSString *const MBXDebugLoggingEnabled = @"MGLMapboxMetricsDebugLoggingEnabled";
NSString *const MBXShowsMapScale = @"MBXMapShowsScale";
NSString *const MBXMapShowsHeadingIndicator = @"MBXMapShowsHeadingIndicator";
NSString *const MBXMapFramerateMeasurementEnabled = @"MBXMapFramerateMeasurementEnabled";
@@ -26,7 +25,6 @@ NSString *const MBXReuseQueueStatsEnabled = @"MBXReuseQueueStatsEnabled";
[coder encodeObject:[NSNumber numberWithUnsignedInteger:_debugMask] forKey:MBXDebugMaskValue];
[coder encodeBool:_showsZoomLevelOrnament forKey:MBXShowsZoomLevelOrnament];
[coder encodeBool:_showsTimeFrameGraph forKey:MBXShowsTimeFrameGraph];
- [coder encodeBool:_debugLoggingEnabled forKey:MBXDebugLoggingEnabled];
[coder encodeBool:_showsMapScale forKey:MBXShowsMapScale];
[coder encodeBool:_showsUserHeadingIndicator forKey:MBXMapShowsHeadingIndicator];
[coder encodeBool:_framerateMeasurementEnabled forKey:MBXMapFramerateMeasurementEnabled];
@@ -41,7 +39,6 @@ NSString *const MBXReuseQueueStatsEnabled = @"MBXReuseQueueStatsEnabled";
NSNumber *decodedDebugMaskOptions = [decoder decodeObjectForKey:MBXDebugMaskValue];
BOOL decodedZoomLevelOrnament = [decoder decodeBoolForKey:MBXShowsZoomLevelOrnament];
BOOL decodedShowsTimeFrameGraph = [decoder decodeBoolForKey:MBXShowsTimeFrameGraph];
- BOOL decodedDebugLoggingEnabled = [decoder decodeBoolForKey:MBXDebugLoggingEnabled];
BOOL decodedShowsMapScale = [decoder decodeBoolForKey:MBXShowsMapScale];
BOOL decodedShowsUserHeadingIndicator = [decoder decodeBoolForKey:MBXMapShowsHeadingIndicator];
BOOL decodedFramerateMeasurementEnabled = [decoder decodeBoolForKey:MBXMapFramerateMeasurementEnabled];
@@ -53,7 +50,6 @@ NSString *const MBXReuseQueueStatsEnabled = @"MBXReuseQueueStatsEnabled";
_debugMask = decodedDebugMaskOptions.intValue;
_showsZoomLevelOrnament = decodedZoomLevelOrnament;
_showsTimeFrameGraph = decodedShowsTimeFrameGraph;
- _debugLoggingEnabled = decodedDebugLoggingEnabled;
_showsMapScale = decodedShowsMapScale;
_showsUserHeadingIndicator = decodedShowsUserHeadingIndicator;
_framerateMeasurementEnabled = decodedFramerateMeasurementEnabled;
@@ -67,15 +63,14 @@ NSString *const MBXReuseQueueStatsEnabled = @"MBXReuseQueueStatsEnabled";
return YES;
}
-- (NSString*) debugDescription {
- return [NSString stringWithFormat:@"Camera: %@\nTracking mode: %lu\nShows user location: %@\nDebug mask value: %lu\nShows zoom level ornament: %@\nShows time frame graph: %@\nDebug logging enabled: %@\nShows map scale: %@\nShows user heading indicator: %@\nFramerate measurement enabled: %@\nReuse queue stats enabled: %@",
+- (NSString *)debugDescription {
+ return [NSString stringWithFormat:@"Camera: %@\nTracking mode: %lu\nShows user location: %@\nDebug mask value: %lu\nShows zoom level ornament: %@\nShows time frame graph: %@\nShows map scale: %@\nShows user heading indicator: %@\nFramerate measurement enabled: %@\nReuse queue stats enabled: %@",
self.camera,
(unsigned long)self.userTrackingMode,
self.showsUserLocation ? @"YES" : @"NO",
(unsigned long)self.debugMask,
self.showsZoomLevelOrnament ? @"YES" : @"NO",
self.showsTimeFrameGraph ? @"YES" : @"NO",
- self.debugLoggingEnabled ? @"YES" : @"NO",
self.showsMapScale ? @"YES" : @"NO",
self.showsUserHeadingIndicator ? @"YES" : @"NO",
self.framerateMeasurementEnabled ? @"YES" : @"NO",
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index 2fb95e1b17..346a182a88 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -211,7 +211,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
@property (nonatomic) BOOL shouldLimitCameraChanges;
@property (nonatomic) BOOL randomWalk;
@property (nonatomic) BOOL zoomLevelOrnamentEnabled;
-@property (nonatomic) BOOL debugLoggingEnabled;
@property (nonatomic) NSMutableArray<UIWindow *> *helperWindows;
@property (nonatomic) NSMutableArray<UIView *> *contentInsetsOverlays;
@@ -246,7 +245,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
self.mapView.showsScale = YES;
self.zoomLevelOrnamentEnabled = NO;
self.frameTimeGraphEnabled = NO;
- self.debugLoggingEnabled = YES;
} else {
// Revert to the previously saved state
[self restoreMapState:nil];
@@ -441,14 +439,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
@"Ornaments Placement",
]];
- if (self.currentState.debugLoggingEnabled)
- {
- [settingsTitles addObjectsFromArray:@[
- @"Print Telemetry Logfile",
- @"Delete Telemetry Logfile",
- ]];
- };
-
break;
default:
NSAssert(NO, @"All settings sections should be implemented");
@@ -558,15 +548,12 @@ CLLocationCoordinate2D randomWorldCoordinate() {
case MBXSettingsAnnotationSelectRandomOffscreenPointAnnotation:
[self selectAnOffscreenPointAnnotation];
break;
-
case MBXSettingsAnnotationCenterSelectedAnnotation:
[self centerSelectedAnnotation];
break;
-
case MBXSettingsAnnotationAddVisibleAreaPolyline:
[self addVisibleAreaPolyline];
break;
-
default:
NSAssert(NO, @"All annotations setting rows should be implemented");
break;
@@ -667,13 +654,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
case MBXSettingsMiscellaneousRandomTour:
[self randomWorldTour];
break;
-
- case MBXSettingsMiscellaneousPrintLogFile:
- [self printTelemetryLogFile];
- break;
- case MBXSettingsMiscellaneousDeleteLogFile:
- [self deleteTelemetryLogFile];
- break;
case MBXSettingsMiscellaneousScrollView:
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
@@ -1734,37 +1714,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
return backupImage;
}
-- (void)printTelemetryLogFile
-{
- NSString *fileContents = [NSString stringWithContentsOfFile:[self telemetryDebugLogFilePath] encoding:NSUTF8StringEncoding error:nil];
- NSLog(@"%@", fileContents);
-}
-
-- (void)deleteTelemetryLogFile
-{
- NSString *filePath = [self telemetryDebugLogFilePath];
- if ([[NSFileManager defaultManager] isDeletableFileAtPath:filePath])
- {
- NSError *error;
- BOOL success = [[NSFileManager defaultManager] removeItemAtPath:filePath error:&error];
- if (success) {
- NSLog(@"Deleted telemetry log.");
- } else {
- NSLog(@"Error deleting telemetry log: %@", error.localizedDescription);
- }
- }
-}
-
-- (NSString *)telemetryDebugLogFilePath
-{
- NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
- [dateFormatter setDateFormat:@"yyyy'-'MM'-'dd"];
- [dateFormatter setTimeZone:[NSTimeZone systemTimeZone]];
- NSString *filePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"telemetry_log-%@.json", [dateFormatter stringFromDate:[NSDate date]]]];
-
- return filePath;
-}
-
#pragma mark - Random World Tour
- (void)addAnnotations:(NSInteger)numAnnotations aroundCoordinate:(CLLocationCoordinate2D)coordinate radius:(CLLocationDistance)radius {
@@ -2396,7 +2345,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
self.currentState.showsZoomLevelOrnament = self.zoomLevelOrnamentEnabled;
self.currentState.showsTimeFrameGraph = self.frameTimeGraphEnabled;
self.currentState.debugMask = self.mapView.debugMask;
- self.currentState.debugLoggingEnabled = self.debugLoggingEnabled;
self.currentState.reuseQueueStatsEnabled = self.reuseQueueStatsEnabled;
[[MBXStateManager sharedManager] saveState:self.currentState];
@@ -2413,7 +2361,6 @@ CLLocationCoordinate2D randomWorldCoordinate() {
self.zoomLevelOrnamentEnabled = currentState.showsZoomLevelOrnament;
self.frameTimeGraphEnabled = currentState.showsTimeFrameGraph;
self.mapView.debugMask = currentState.debugMask;
- self.debugLoggingEnabled = currentState.debugLoggingEnabled;
self.reuseQueueStatsEnabled = currentState.reuseQueueStatsEnabled;
self.currentState = currentState;
diff --git a/platform/ios/app/Main.storyboard b/platform/ios/app/Main.storyboard
index 28316745a1..ac83bd968f 100644
--- a/platform/ios/app/Main.storyboard
+++ b/platform/ios/app/Main.storyboard
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
-<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14810.11" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14865.1" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="PSe-Ot-7Ff">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
- <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14766.13"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14819.2"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -13,11 +13,11 @@
<objects>
<viewController id="WaX-pd-UZQ" userLabel="Map View Controller" customClass="MBXViewController" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Z9X-fc-PUC">
- <rect key="frame" x="0.0" y="0.0" width="203" height="33"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kNe-zV-9ha" customClass="MGLMapView">
- <rect key="frame" x="0.0" y="0.0" width="203" height="33"/>
+ <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews>
<button hidden="YES" opaque="NO" userInteractionEnabled="NO" alpha="0.69999999999999996" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="tailTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="58y-pX-YyB">
<rect key="frame" x="8" y="82" width="40" height="20"/>
@@ -38,7 +38,7 @@
</userDefinedRuntimeAttributes>
</button>
<view hidden="YES" opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BHE-Wn-x69" customClass="MBXFrameTimeGraphView">
- <rect key="frame" x="0.0" y="-167" width="203" height="200"/>
+ <rect key="frame" x="0.0" y="467" width="375" height="200"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<accessibility key="accessibilityConfiguration">
<accessibilityTraits key="traits" notEnabled="YES"/>
@@ -84,7 +84,7 @@
</connections>
</barButtonItem>
<button key="titleView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="KsN-ny-Hou">
- <rect key="frame" x="65" y="5.5" width="203" height="33"/>
+ <rect key="frame" x="89" y="5.5" width="148" height="33"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" weight="medium" pointSize="17"/>
<state key="normal" title="Streets"/>
@@ -198,7 +198,7 @@
<action selector="addCurrentRegion:" destination="7q0-lI-zqb" id="G2O-3V-aEA"/>
</connections>
</barButtonItem>
- <barButtonItem style="plain" systemItem="refresh" id="2fx-iS-Veb">
+ <barButtonItem systemItem="refresh" id="2fx-iS-Veb">
<connections>
<action selector="invalidatePacks:" destination="7q0-lI-zqb" id="5lx-FY-aTt"/>
</connections>
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index de2bec5d99..018a5f9368 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -388,7 +388,7 @@
9680274022653B84006BA4A1 /* MBXSKUToken.h in Headers */ = {isa = PBXBuildFile; fileRef = 9680273E22653B84006BA4A1 /* MBXSKUToken.h */; };
9680276422655696006BA4A1 /* libmbxaccounts.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9680274122653C3E006BA4A1 /* libmbxaccounts.a */; };
96802766226556C5006BA4A1 /* libmbxaccounts.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9680274122653C3E006BA4A1 /* libmbxaccounts.a */; };
- 9686D1BD22D9357700194EA0 /* MGLMapViewZoomTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.m */; };
+ 9686D1BD22D9357700194EA0 /* MGLMapViewZoomTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.mm */; };
968F36B51E4D128D003A5522 /* MGLDistanceFormatter.h in Headers */ = {isa = PBXBuildFile; fileRef = 3557F7AE1E1D27D300CCA5E6 /* MGLDistanceFormatter.h */; settings = {ATTRIBUTES = (Public, ); }; };
96E027231E57C76E004B8E66 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 96E027251E57C76E004B8E66 /* Localizable.strings */; };
96E516DC2000547000A02306 /* MGLPolyline_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 9654C1251FFC1AB900DB6A19 /* MGLPolyline_Private.h */; };
@@ -481,6 +481,8 @@
9C6E284522A982670056B7BE /* MMEUINavigation.h in Headers */ = {isa = PBXBuildFile; fileRef = 406E99B31FFEFED600D9FFCC /* MMEUINavigation.h */; };
9C6E284622A982670056B7BE /* MMEUniqueIdentifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 40834BBF1FE05D6E00C1BD0D /* MMEUniqueIdentifier.h */; };
9C6E284722A982670056B7BE /* MMEDispatchManager.h in Headers */ = {isa = PBXBuildFile; fileRef = ACA65F552140696B00537748 /* MMEDispatchManager.h */; };
+ A4DE3DCB23038C98005B3473 /* MGLMockGestureRecognizers.h in Sources */ = {isa = PBXBuildFile; fileRef = A4DE3DCA23038A7F005B3473 /* MGLMockGestureRecognizers.h */; };
+ A4DE3DCC23038CCA005B3473 /* MGLMockGestureRecognizers.m in Sources */ = {isa = PBXBuildFile; fileRef = A4DE3DC823038A07005B3473 /* MGLMockGestureRecognizers.m */; };
A4F3FB1D2254865900A30170 /* missing_icon.json in Resources */ = {isa = PBXBuildFile; fileRef = A4F3FB1C2254865900A30170 /* missing_icon.json */; };
AC46EB59225E600A0039C013 /* MMECertPin.h in Headers */ = {isa = PBXBuildFile; fileRef = AC46EB57225E60090039C013 /* MMECertPin.h */; };
AC46EB5A225E600A0039C013 /* MMECertPin.h in Headers */ = {isa = PBXBuildFile; fileRef = AC46EB57225E60090039C013 /* MMECertPin.h */; };
@@ -506,11 +508,12 @@
CA1B4A512099FB2200EDD491 /* MGLMapSnapshotterTest.m in Sources */ = {isa = PBXBuildFile; fileRef = CA1B4A502099FB2200EDD491 /* MGLMapSnapshotterTest.m */; };
CA34C9C3207FD272005C1A06 /* MGLCameraTransitionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA34C9C2207FD272005C1A06 /* MGLCameraTransitionTests.mm */; };
CA4EB8C720863487006AB465 /* MGLStyleLayerIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */; };
+ CA4F3BDE230F74C3008BAFEA /* MGLMapViewPendingBlockTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA4F3BDD230F74C3008BAFEA /* MGLMapViewPendingBlockTests.m */; };
CA55CD41202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; };
CA55CD42202C16AA00CE7095 /* MGLCameraChangeReason.h in Headers */ = {isa = PBXBuildFile; fileRef = CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */; settings = {ATTRIBUTES = (Public, ); }; };
CA65C4F821E9BB080068B0D4 /* MGLCluster.h in Headers */ = {isa = PBXBuildFile; fileRef = CA65C4F721E9BB080068B0D4 /* MGLCluster.h */; settings = {ATTRIBUTES = (Public, ); }; };
CA65C4F921E9BB080068B0D4 /* MGLCluster.h in Headers */ = {isa = PBXBuildFile; fileRef = CA65C4F721E9BB080068B0D4 /* MGLCluster.h */; settings = {ATTRIBUTES = (Public, ); }; };
- CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m */; };
+ CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm */; };
CA7766832229C10E0008DE9E /* MGLCompactCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA8848451CBAFB9800AB86E3 /* MGLCompactCalloutView.m */; };
CA7766842229C11A0008DE9E /* SMCalloutView.m in Sources */ = {isa = PBXBuildFile; fileRef = DA88488A1CBB037E00AB86E3 /* SMCalloutView.m */; };
CA86FF0E22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CA86FF0D22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m */; };
@@ -1129,7 +1132,7 @@
967C864A210A9D3C004DF794 /* UIDevice+MGLAdditions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+MGLAdditions.m"; sourceTree = "<group>"; };
9680273E22653B84006BA4A1 /* MBXSKUToken.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MBXSKUToken.h; path = "../vendor/mapbox-accounts-ios/MBXSKUToken.h"; sourceTree = "<group>"; };
9680274122653C3E006BA4A1 /* libmbxaccounts.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmbxaccounts.a; path = "vendor/mapbox-accounts-ios/libmbxaccounts.a"; sourceTree = SOURCE_ROOT; };
- 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewZoomTests.m; sourceTree = "<group>"; };
+ 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapViewZoomTests.mm; sourceTree = "<group>"; };
968F36B41E4D0FC6003A5522 /* ja */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
96E027241E57C76E004B8E66 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/Localizable.strings; sourceTree = "<group>"; };
96E027271E57C77A004B8E66 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -1173,6 +1176,8 @@
9C6E286522A9849E0056B7BE /* release-notes-jazzy.md.ejs */ = {isa = PBXFileReference; lastKnownFileType = text; path = "release-notes-jazzy.md.ejs"; sourceTree = "<group>"; };
9C6E286622A9849E0056B7BE /* deploy-snapshot.sh */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "deploy-snapshot.sh"; sourceTree = "<group>"; };
9C6E286722A9849E0056B7BE /* release-notes.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "release-notes.js"; sourceTree = "<group>"; };
+ A4DE3DC823038A07005B3473 /* MGLMockGestureRecognizers.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLMockGestureRecognizers.m; sourceTree = "<group>"; };
+ A4DE3DCA23038A7F005B3473 /* MGLMockGestureRecognizers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMockGestureRecognizers.h; sourceTree = "<group>"; };
A4F3FB1C2254865900A30170 /* missing_icon.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = missing_icon.json; sourceTree = "<group>"; };
AC46EB57225E60090039C013 /* MMECertPin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MMECertPin.h; sourceTree = "<group>"; };
AC46EB58225E60090039C013 /* MMECertPin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MMECertPin.m; sourceTree = "<group>"; };
@@ -1194,10 +1199,11 @@
CA1B4A502099FB2200EDD491 /* MGLMapSnapshotterTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapSnapshotterTest.m; sourceTree = "<group>"; };
CA34C9C2207FD272005C1A06 /* MGLCameraTransitionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLCameraTransitionTests.mm; sourceTree = "<group>"; };
CA4EB8C620863487006AB465 /* MGLStyleLayerIntegrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLStyleLayerIntegrationTests.m; sourceTree = "<group>"; };
+ CA4F3BDD230F74C3008BAFEA /* MGLMapViewPendingBlockTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLMapViewPendingBlockTests.m; sourceTree = "<group>"; };
CA55CD3E202C16AA00CE7095 /* MGLCameraChangeReason.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCameraChangeReason.h; sourceTree = "<group>"; };
CA5E5042209BDC5F001A8A81 /* MGLTestUtility.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = MGLTestUtility.h; path = ../../darwin/test/MGLTestUtility.h; sourceTree = "<group>"; };
CA65C4F721E9BB080068B0D4 /* MGLCluster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCluster.h; sourceTree = "<group>"; };
- CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = MGLAnnotationViewIntegrationTests.m; path = "Annotation Tests/MGLAnnotationViewIntegrationTests.m"; sourceTree = "<group>"; };
+ CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLAnnotationViewIntegrationTests.mm; path = "Annotation Tests/MGLAnnotationViewIntegrationTests.mm"; sourceTree = "<group>"; };
CA86FF0D22D8D5A0009EB14A /* MGLNetworkConfigurationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLNetworkConfigurationTests.m; sourceTree = "<group>"; };
CA88DC2F21C85D900059ED5A /* MGLStyleURLIntegrationTest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLStyleURLIntegrationTest.m; sourceTree = "<group>"; };
CA8FBC0821A47BB100D1203C /* MGLRendererConfigurationTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLRendererConfigurationTests.mm; path = ../../darwin/test/MGLRendererConfigurationTests.mm; sourceTree = "<group>"; };
@@ -1550,6 +1556,7 @@
CA88DC2F21C85D900059ED5A /* MGLStyleURLIntegrationTest.m */,
077061DB215DA11F000FEF62 /* MGLTestLocationManager.h */,
077061D9215DA00E000FEF62 /* MGLTestLocationManager.m */,
+ CA4F3BDD230F74C3008BAFEA /* MGLMapViewPendingBlockTests.m */,
);
path = "Integration Tests";
sourceTree = "<group>";
@@ -1744,6 +1751,8 @@
children = (
CA5E5042209BDC5F001A8A81 /* MGLTestUtility.h */,
4031ACFE1E9FD29F00A3EA26 /* MGLSDKTestHelpers.swift */,
+ A4DE3DCA23038A7F005B3473 /* MGLMockGestureRecognizers.h */,
+ A4DE3DC823038A07005B3473 /* MGLMockGestureRecognizers.m */,
);
name = "Test Helpers";
sourceTree = "<group>";
@@ -1920,7 +1929,7 @@
CA6914B320E67F07002DB0EE /* Annotations */ = {
isa = PBXGroup;
children = (
- CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m */,
+ CA6914B420E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm */,
);
name = Annotations;
sourceTree = "<group>";
@@ -2057,7 +2066,7 @@
96381C0122C6F3950053497D /* MGLMapViewPitchTests.m */,
9658C154204761FC00D8A674 /* MGLMapViewScaleBarTests.m */,
076171C22139C70900668A35 /* MGLMapViewTests.m */,
- 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.m */,
+ 9686D1BC22D9357700194EA0 /* MGLMapViewZoomTests.mm */,
1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */,
96036A0520059BBA00510F3D /* MGLNSOrthographyAdditionsTests.m */,
DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */,
@@ -3190,13 +3199,14 @@
CA7766842229C11A0008DE9E /* SMCalloutView.m in Sources */,
CA34C9C3207FD272005C1A06 /* MGLCameraTransitionTests.mm in Sources */,
16376B0A1FFD9DAF0000563E /* MBGLIntegrationTests.mm in Sources */,
+ CA4F3BDE230F74C3008BAFEA /* MGLMapViewPendingBlockTests.m in Sources */,
CA88DC3021C85D900059ED5A /* MGLStyleURLIntegrationTest.m in Sources */,
CA0C27942076CA19001CE5B7 /* MGLMapViewIntegrationTest.m in Sources */,
CA7766832229C10E0008DE9E /* MGLCompactCalloutView.m in Sources */,
CAE7AD5520F46EF5003B6782 /* MGLMapSnapshotterSwiftTests.swift in Sources */,
CA0C27922076C804001CE5B7 /* MGLShapeSourceTests.m in Sources */,
077061DA215DA00E000FEF62 /* MGLTestLocationManager.m in Sources */,
- CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.m in Sources */,
+ CA6914B520E67F50002DB0EE /* MGLAnnotationViewIntegrationTests.mm in Sources */,
CA1B4A512099FB2200EDD491 /* MGLMapSnapshotterTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -3236,6 +3246,8 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ A4DE3DCC23038CCA005B3473 /* MGLMockGestureRecognizers.m in Sources */,
+ A4DE3DCB23038C98005B3473 /* MGLMockGestureRecognizers.h in Sources */,
6407D6701E0085FD00F6A9C3 /* MGLDocumentationExampleTests.swift in Sources */,
DA2E88631CC0382C00F24E7B /* MGLOfflineRegionTests.m in Sources */,
409F43FD1E9E781C0048729D /* MGLMapViewDelegateIntegrationTests.swift in Sources */,
@@ -3273,7 +3285,7 @@
3575798B1D502B0C000B822E /* MGLBackgroundStyleLayerTests.mm in Sources */,
9658C155204761FC00D8A674 /* MGLMapViewScaleBarTests.m in Sources */,
409D0A0D1ED614CE00C95D0C /* MGLAnnotationViewIntegrationTests.swift in Sources */,
- 9686D1BD22D9357700194EA0 /* MGLMapViewZoomTests.m in Sources */,
+ 9686D1BD22D9357700194EA0 /* MGLMapViewZoomTests.mm in Sources */,
DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */,
55E2AD131E5B125400E8C587 /* MGLOfflineStorageTests.mm in Sources */,
07D8C6FF1F67562C00381808 /* MGLComputedShapeSourceTests.m in Sources */,
diff --git a/platform/ios/scripts/deploy-packages.sh b/platform/ios/scripts/deploy-packages.sh
index a0efbd622e..b33a25df86 100755
--- a/platform/ios/scripts/deploy-packages.sh
+++ b/platform/ios/scripts/deploy-packages.sh
@@ -7,12 +7,10 @@ set -u
# dynamic environment variables:
# VERSION_TAG={determined automatically}: Version tag in format ios-vX.X.X-pre.X
# GITHUB_RELEASE=true: Upload to github
-# BINARY_DIRECTORY=build/ios/deploy: Directory in which to save test packages
# environment variables and dependencies:
# - You must run "mbx auth ..." before running
# - Set GITHUB_TOKEN to a GitHub API access token in your environment to use GITHUB_RELEASE
-# - "wget" is required for downloading the zip files from s3
# - The "github-release" command is required to use GITHUB_RELEASE
function step { >&2 echo -e "\033[1m\033[36m* $@\033[0m"; }
@@ -36,8 +34,6 @@ buildPackageStyle() {
./platform/ios/scripts/publish.sh "${PUBLISH_VERSION}" ${style}
file_name=mapbox-ios-sdk-${PUBLISH_VERSION}-${style}.zip
fi
- step "Downloading ${file_name} from s3 to ${BINARY_DIRECTORY}"
- wget -O ${BINARY_DIRECTORY}/${file_name} http://mapbox.s3.amazonaws.com/mapbox-gl-native/ios/builds/${file_name}
if [[ "${GITHUB_RELEASE}" == true ]]; then
step "Uploading ${file_name} to GitHub"
github-release upload \
@@ -54,7 +50,7 @@ export BUILDTYPE=Release
VERSION_TAG=${VERSION_TAG:-''}
PUBLISH_VERSION=
-BINARY_DIRECTORY=${BINARY_DIRECTORY:-build/ios/deploy}
+BINARY_DIRECTORY='build/ios'
GITHUB_RELEASE=${GITHUB_RELEASE:-true}
PUBLISH_PRE_FLAG=''
diff --git a/platform/ios/scripts/install-packaging-dependencies.sh b/platform/ios/scripts/install-packaging-dependencies.sh
index 3d87a93f20..3d7f2fa4ea 100755
--- a/platform/ios/scripts/install-packaging-dependencies.sh
+++ b/platform/ios/scripts/install-packaging-dependencies.sh
@@ -22,15 +22,6 @@ else
fi
##
-## wget
-##
-if [ -z `which wget` ]; then
- brew install wget
-else
- echo "Found brew"
-fi
-
-##
## cocoapods
##
if [[ -z `which pod` || $(pod --version) != "${COCOAPODS_VERSION}" ]]; then
diff --git a/platform/ios/scripts/publish.sh b/platform/ios/scripts/publish.sh
index b4e6f30257..1a4652a509 100755
--- a/platform/ios/scripts/publish.sh
+++ b/platform/ios/scripts/publish.sh
@@ -24,18 +24,19 @@ GITHUB_REPO=${GITHUB_REPO:-'mapbox-gl-native'}
# zip
#
cd build/ios/pkg
-SNAPSHOT_FILENAME="mapbox-ios-sdk-${PUBLISH_VERSION}${PUBLISH_STYLE}.zip"
-step "Compressing ${SNAPSHOT_FILENAME}…"
-rm -f ../${SNAPSHOT_FILENAME}
-zip -yr ../${SNAPSHOT_FILENAME} *
+ZIP_FILENAME="mapbox-ios-sdk-${PUBLISH_VERSION}${PUBLISH_STYLE}.zip"
+step "Compressing ${ZIP_FILENAME}…"
+rm -f ../${ZIP_FILENAME}
+zip -yr ../${ZIP_FILENAME} *
+cd ..
#
# report file sizes
#
step "Echoing file sizes…"
-du -sh ../${SNAPSHOT_FILENAME}
-du -sch *
-du -sch dynamic/*
+du -sh ${ZIP_FILENAME}
+du -sch pkg/*
+du -sch pkg/dynamic/*
#
# upload
@@ -45,17 +46,34 @@ if [ -n "${CI:-}" ]; then
PROGRESS="--no-progress"
fi
-step "Uploading ${SNAPSHOT_FILENAME} to s3…"
-aws s3 cp ../${SNAPSHOT_FILENAME} s3://mapbox/$GITHUB_REPO/ios/builds/ --acl public-read ${PROGRESS}
-echo "URL: https://mapbox.s3.amazonaws.com/$GITHUB_REPO/ios/builds/${SNAPSHOT_FILENAME}"
+step "Uploading ${ZIP_FILENAME} to s3…"
+aws s3 cp ${ZIP_FILENAME} s3://mapbox/${GITHUB_REPO}/ios/builds/ --acl public-read ${PROGRESS}
+S3_URL=https://mapbox.s3.amazonaws.com/${GITHUB_REPO}/ios/builds/${ZIP_FILENAME}
+echo "URL: ${S3_URL}"
#
# upload & update snapshot
#
if [[ ${PUBLISH_VERSION} =~ "snapshot" ]]; then
step "Updating ${PUBLISH_VERSION} to ${PUBLISH_STYLE}…"
- GENERIC_SNAPSHOT_FILENAME="mapbox-ios-sdk-${PUBLISH_VERSION}.zip"
+ GENERIC_ZIP_FILENAME="mapbox-ios-sdk-${PUBLISH_VERSION}.zip"
aws s3 cp \
- s3://mapbox/$GITHUB_REPO/ios/builds/${SNAPSHOT_FILENAME} \
- s3://mapbox/$GITHUB_REPO/ios/builds/${GENERIC_SNAPSHOT_FILENAME} --acl public-read ${PROGRESS}
+ s3://mapbox/$GITHUB_REPO/ios/builds/${ZIP_FILENAME} \
+ s3://mapbox/$GITHUB_REPO/ios/builds/${GENERIC_ZIP_FILENAME} --acl public-read ${PROGRESS}
+fi
+
+#
+# verify upload integrity
+#
+
+step "Validating local and remote checksums…"
+curl --output remote-${ZIP_FILENAME} ${S3_URL}
+LOCAL_CHECKSUM=$( shasum -a 256 -b ${ZIP_FILENAME} | cut -d ' ' -f 1 )
+REMOTE_CHECKSUM=$( shasum -a 256 -b remote-${ZIP_FILENAME} | cut -d ' ' -f 1 )
+
+if [ "${LOCAL_CHECKSUM}" == "${REMOTE_CHECKSUM}" ]; then
+ echo "Checksums match: ${LOCAL_CHECKSUM}"
+else
+ echo "Checksums did not match: ${LOCAL_CHECKSUM} != ${REMOTE_CHECKSUM}"
+ exit 1
fi
diff --git a/platform/ios/src/MGLMapView+Impl.h b/platform/ios/src/MGLMapView+Impl.h
index 0a62b7da82..66dc408274 100644
--- a/platform/ios/src/MGLMapView+Impl.h
+++ b/platform/ios/src/MGLMapView+Impl.h
@@ -62,7 +62,7 @@ public:
void onDidFinishLoadingMap() override;
void onDidFailLoadingMap(mbgl::MapLoadError mapError, const std::string& what) override;
void onWillStartRenderingFrame() override;
- void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode) override;
+ void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode, bool) override;
void onWillStartRenderingMap() override;
void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode) override;
void onDidFinishLoadingStyle() override;
diff --git a/platform/ios/src/MGLMapView+Impl.mm b/platform/ios/src/MGLMapView+Impl.mm
index 1bccfa662f..76c9c0f9ba 100644
--- a/platform/ios/src/MGLMapView+Impl.mm
+++ b/platform/ios/src/MGLMapView+Impl.mm
@@ -68,7 +68,7 @@ void MGLMapViewImpl::onWillStartRenderingFrame() {
[mapView mapViewWillStartRenderingFrame];
}
-void MGLMapViewImpl::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode) {
+void MGLMapViewImpl::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode, bool) {
bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
[mapView mapViewDidFinishRenderingFrameFullyRendered:fullyRendered];
}
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index e6f66e39ae..6d9b30e467 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -748,7 +748,8 @@ MGL_EXPORT
Changes the center coordinate of the map and optionally animates the change.
Changing the center coordinate centers the map on the new coordinate without
- changing the current zoom level.
+ changing the current zoom level. For animated changes, wait until the map view has
+ finished loading before calling this method.
@param coordinate The new center coordinate for the map.
@param animated Specify `YES` if you want the map view to scroll to the new
@@ -762,7 +763,8 @@ MGL_EXPORT
/**
Changes the center coordinate and zoom level of the map and optionally animates
- the change.
+ the change. For animated changes, wait until the map view has
+ finished loading before calling this method.
@param centerCoordinate The new center coordinate for the map.
@param zoomLevel The new zoom level for the map.
@@ -777,7 +779,8 @@ MGL_EXPORT
/**
Changes the center coordinate, zoom level, and direction of the map and
- optionally animates the change.
+ optionally animates the change. For animated changes, wait until the map view has
+ finished loading before calling this method.
@param centerCoordinate The new center coordinate for the map.
@param zoomLevel The new zoom level for the map.
@@ -794,7 +797,8 @@ MGL_EXPORT
/**
Changes the center coordinate, zoom level, and direction of the map, calling a
- completion handler at the end of an optional animation.
+ completion handler at the end of an optional animation. For animated changes,
+ wait until the map view has finished loading before calling this method.
@param centerCoordinate The new center coordinate for the map.
@param zoomLevel The new zoom level for the map.
@@ -1065,7 +1069,8 @@ MGL_EXPORT
/**
Moves the viewpoint to a different location with respect to the map with an
- optional transition animation.
+ optional transition animation. For animated changes, wait until the map view has
+ finished loading before calling this method.
@param camera The new viewpoint.
@param animated Specify `YES` if you want the map view to animate the change to
@@ -1081,7 +1086,8 @@ MGL_EXPORT
/**
Moves the viewpoint to a different location with respect to the map with an
- optional transition duration and timing function.
+ optional transition duration and timing function. For animated changes, wait
+ until the map view has finished loading before calling this method.
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
@@ -1100,7 +1106,8 @@ MGL_EXPORT
/**
Moves the viewpoint to a different location with respect to the map with an
- optional transition duration and timing function.
+ optional transition duration and timing function. For animated changes, wait
+ until the map view has finished loading before calling this method.
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
@@ -1116,7 +1123,8 @@ MGL_EXPORT
/**
Moves the viewpoint to a different location with respect to the map with an
optional transition duration and timing function, and optionally some additional
- padding on each side.
+ padding on each side. For animated changes, wait until the map view has
+ finished loading before calling this method.
@param camera The new viewpoint.
@param duration The amount of time, measured in seconds, that the transition
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index d77f94d8ba..2eafea1dd9 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -128,6 +128,9 @@ const CLLocationDirection MGLToleranceForSnappingToNorth = 7;
/// Distance threshold to stop the camera while animating.
const CLLocationDistance MGLDistanceThresholdForCameraPause = 500;
+/// Rotation threshold while a pinch gesture is occurring.
+static NSString * const MGLRotationThresholdWhileZoomingKey = @"MGLRotationThresholdWhileZooming";
+
/// Reuse identifier and file name of the default point annotation image.
static NSString * const MGLDefaultStyleMarkerSymbolName = @"default_marker";
@@ -154,6 +157,9 @@ static const NSUInteger MGLPresentsWithTransactionAnnotationCount = 0;
/// An indication that the requested annotation was not found or is nonexistent.
enum { MGLAnnotationTagNotFound = UINT32_MAX };
+/// The threshold used to consider when a tilt gesture should start.
+const CLLocationDegrees MGLHorizontalTiltToleranceDegrees = 45.0;
+
/// Mapping from an annotation tag to metadata about that annotation, including
/// the annotation itself.
typedef std::unordered_map<MGLAnnotationTag, MGLAnnotationContext> MGLAnnotationTagContextMap;
@@ -240,6 +246,10 @@ public:
@property (nonatomic) CGFloat quickZoomStart;
@property (nonatomic, getter=isDormant) BOOL dormant;
@property (nonatomic, readonly, getter=isRotationAllowed) BOOL rotationAllowed;
+@property (nonatomic) CGFloat rotationThresholdWhileZooming;
+@property (nonatomic) CGFloat rotationBeforeThresholdMet;
+@property (nonatomic) BOOL isZooming;
+@property (nonatomic) BOOL isRotating;
@property (nonatomic) BOOL shouldTriggerHapticFeedbackForCompass;
@property (nonatomic) MGLMapViewProxyAccessibilityElement *mapViewProxyAccessibilityElement;
@property (nonatomic) MGLAnnotationContainerView *annotationContainerView;
@@ -247,6 +257,7 @@ public:
@property (nonatomic) NSMutableDictionary<NSString *, NSMutableArray<MGLAnnotationView *> *> *annotationViewReuseQueueByIdentifier;
@property (nonatomic, readonly) BOOL enablePresentsWithTransaction;
@property (nonatomic) UIImage *lastSnapshotImage;
+@property (nonatomic) NSMutableArray *pendingCompletionBlocks;
/// Experimental rendering performance measurement.
@property (nonatomic) BOOL experimental_enableFrameRateMeasurement;
@@ -260,6 +271,9 @@ public:
@property (nonatomic) MGLMapDebugMaskOptions residualDebugMask;
@property (nonatomic, copy) NSURL *residualStyleURL;
+/// Tilt gesture recognizer helper
+@property (nonatomic, assign) CGPoint dragGestureMiddlePoint;
+
- (mbgl::Map &)mbglMap;
@end
@@ -457,7 +471,7 @@ public:
// setup mbgl map
MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration];
- auto renderer = std::make_unique<mbgl::Renderer>(_mbglView->getRendererBackend(), config.scaleFactor, config.cacheDir, config.localFontFamilyName);
+ auto renderer = std::make_unique<mbgl::Renderer>(_mbglView->getRendererBackend(), config.scaleFactor, config.localFontFamilyName);
BOOL enableCrossSourceCollisions = !config.perSourceCollisions;
_rendererFrontend = std::make_unique<MGLRenderFrontend>(std::move(renderer), self, _mbglView->getRendererBackend());
@@ -612,6 +626,11 @@ public:
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didEnterBackground:) name:UIApplicationDidEnterBackgroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
+
+ // Pending completion blocks are called *after* annotation views have been updated
+ // in updateFromDisplayLink.
+ _pendingCompletionBlocks = [NSMutableArray array];
+
// As of 3.7.5, we intentionally do not listen for `UIApplicationWillResignActiveNotification` or call `pauseRendering:` in response to it, as doing
// so causes a loop when asking for location permission. See: https://github.com/mapbox/mapbox-gl-native/issues/11225
@@ -1033,6 +1052,34 @@ public:
return CGPointMake(CGRectGetMidX(contentFrame), CGRectGetMidY(contentFrame));
}
+#pragma mark - Pending completion blocks
+
+- (void)processPendingBlocks
+{
+ NSArray *blocks = self.pendingCompletionBlocks;
+ self.pendingCompletionBlocks = [NSMutableArray array];
+
+ for (dispatch_block_t block in blocks)
+ {
+ block();
+ }
+}
+
+- (BOOL)scheduleTransitionCompletion:(dispatch_block_t)block
+{
+ // Only add a block if the display link (that calls processPendingBlocks) is
+ // running, otherwise fall back to calling immediately.
+ if (_displayLink && !_displayLink.isPaused)
+ {
+ [self willChangeValueForKey:@"pendingCompletionBlocks"];
+ [self.pendingCompletionBlocks addObject:block];
+ [self didChangeValueForKey:@"pendingCompletionBlocks"];
+ return YES;
+ }
+
+ return NO;
+}
+
#pragma mark - Life Cycle -
- (void)updateFromDisplayLink:(CADisplayLink *)displayLink
@@ -1057,7 +1104,7 @@ public:
return;
}
- if (_needsDisplayRefresh)
+ if (_needsDisplayRefresh || (self.pendingCompletionBlocks.count > 0))
{
_needsDisplayRefresh = NO;
@@ -1066,6 +1113,13 @@ public:
[self updateAnnotationViews];
[self updateCalloutView];
+ // Call any pending completion blocks. This is primarily to ensure
+ // that annotations are in the expected position after core rendering
+ // and map update.
+ //
+ // TODO: Consider using this same mechanism for delegate callbacks.
+ [self processPendingBlocks];
+
_mbglView->display();
}
@@ -1132,6 +1186,7 @@ public:
{
[_displayLink invalidate];
_displayLink = nil;
+ [self processPendingBlocks];
}
}
@@ -1415,6 +1470,7 @@ public:
[MGLMapboxEvents flush];
_displayLink.paused = YES;
+ [self processPendingBlocks];
if ( ! self.glSnapshotView)
{
@@ -1467,6 +1523,11 @@ public:
{
super.hidden = hidden;
_displayLink.paused = hidden;
+
+ if (hidden)
+ {
+ [self processPendingBlocks];
+ }
}
- (void)tintColorDidChange
@@ -1622,6 +1683,9 @@ public:
{
self.scale = powf(2, [self zoomLevel]);
+ if (abs(pinch.velocity) > abs(self.rotate.velocity)) {
+ self.isZooming = YES;
+ }
[self notifyGestureDidBegin];
}
else if (pinch.state == UIGestureRecognizerStateChanged)
@@ -1697,6 +1761,7 @@ public:
}
}
+ self.isZooming = NO;
[self notifyGestureDidEndWithDrift:drift];
[self unrotateIfNeededForGesture];
}
@@ -1709,6 +1774,106 @@ public:
{
if ( ! self.isRotateEnabled) return;
+ if ([[NSUserDefaults standardUserDefaults] objectForKey:MGLRotationThresholdWhileZoomingKey]) {
+ [self handleRotateGestureRecognizerWithThreshold:rotate];
+ } else {
+ [self cancelTransitions];
+
+ CGPoint centerPoint = [self anchorPointForGesture:rotate];
+ MGLMapCamera *oldCamera = self.camera;
+
+ self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGestureRotate;
+
+ if (rotate.state == UIGestureRecognizerStateBegan)
+ {
+ self.angle = MGLRadiansFromDegrees(*self.mbglMap.getCameraOptions().bearing) * -1;
+
+ self.isRotating = YES;
+ if (self.userTrackingMode != MGLUserTrackingModeNone)
+ {
+ self.userTrackingMode = MGLUserTrackingModeFollow;
+ }
+
+ self.shouldTriggerHapticFeedbackForCompass = NO;
+ [self notifyGestureDidBegin];
+ }
+ if (rotate.state == UIGestureRecognizerStateChanged)
+ {
+ CGFloat newDegrees = MGLDegreesFromRadians(self.angle + rotate.rotation) * -1;
+
+ // constrain to +/-30 degrees when merely rotating like Apple does
+ //
+ if ( ! self.isRotationAllowed && std::abs(self.pinch.scale) < 10)
+ {
+ newDegrees = fminf(newDegrees, 30);
+ newDegrees = fmaxf(newDegrees, -30);
+ }
+
+ MGLMapCamera *toCamera = [self cameraByRotatingToDirection:newDegrees aroundAnchorPoint:centerPoint];
+
+ if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
+ {
+ self.mbglMap.jumpTo(mbgl::CameraOptions()
+ .withBearing(newDegrees)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y}));
+ }
+
+ [self cameraIsChanging];
+
+ // Trigger a light haptic feedback event when the user rotates to due north.
+ if (@available(iOS 10.0, *))
+ {
+ if (self.isHapticFeedbackEnabled && fabs(newDegrees) <= 1 && self.shouldTriggerHapticFeedbackForCompass)
+ {
+ UIImpactFeedbackGenerator *hapticFeedback = [[UIImpactFeedbackGenerator alloc] initWithStyle:UIImpactFeedbackStyleLight];
+ [hapticFeedback impactOccurred];
+
+ self.shouldTriggerHapticFeedbackForCompass = NO;
+ }
+ else if (fabs(newDegrees) > 1)
+ {
+ self.shouldTriggerHapticFeedbackForCompass = YES;
+ }
+ }
+ }
+ else if ((rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled))
+ {
+ CGFloat velocity = rotate.velocity;
+ CGFloat decelerationRate = self.decelerationRate;
+ if (decelerationRate != MGLMapViewDecelerationRateImmediate && fabs(velocity) > 3)
+ {
+ CGFloat radians = self.angle + rotate.rotation;
+ CGFloat newRadians = radians + velocity * decelerationRate * 0.1;
+ CGFloat newDegrees = MGLDegreesFromRadians(newRadians) * -1;
+
+ MGLMapCamera *toCamera = [self cameraByRotatingToDirection:newDegrees aroundAnchorPoint:centerPoint];
+
+ if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
+ {
+ self.mbglMap.easeTo(mbgl::CameraOptions()
+ .withBearing(newDegrees)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }),
+ MGLDurationFromTimeInterval(decelerationRate));
+
+ [self notifyGestureDidEndWithDrift:YES];
+ __weak MGLMapView *weakSelf = self;
+
+ [self animateWithDelay:decelerationRate animations:^
+ {
+ [weakSelf unrotateIfNeededForGesture];
+ }];
+ }
+ }
+ else
+ {
+ [self notifyGestureDidEndWithDrift:NO];
+ [self unrotateIfNeededForGesture];
+ }
+ }
+ }
+}
+
+- (void)handleRotateGestureRecognizerWithThreshold:(UIRotationGestureRecognizer *)rotate {
[self cancelTransitions];
CGPoint centerPoint = [self anchorPointForGesture:rotate];
@@ -1716,20 +1881,29 @@ public:
self.cameraChangeReasonBitmask |= MGLCameraChangeReasonGestureRotate;
- if (rotate.state == UIGestureRecognizerStateBegan)
+ _rotationThresholdWhileZooming = [[[NSUserDefaults standardUserDefaults] objectForKey:MGLRotationThresholdWhileZoomingKey] floatValue];
+
+ // Check whether a zoom triggered by a pinch gesture is occurring and if the rotation threshold has been met.
+ if (MGLDegreesFromRadians(self.rotationBeforeThresholdMet) < self.rotationThresholdWhileZooming && self.isZooming && !self.isRotating) {
+ self.rotationBeforeThresholdMet += fabs(rotate.rotation);
+ rotate.rotation = 0;
+ return;
+ }
+
+ if (rotate.state == UIGestureRecognizerStateBegan || ! self.isRotating)
{
self.angle = MGLRadiansFromDegrees(*self.mbglMap.getCameraOptions().bearing) * -1;
+ self.isRotating = YES;
if (self.userTrackingMode != MGLUserTrackingModeNone)
{
self.userTrackingMode = MGLUserTrackingModeFollow;
}
self.shouldTriggerHapticFeedbackForCompass = NO;
-
[self notifyGestureDidBegin];
}
- else if (rotate.state == UIGestureRecognizerStateChanged)
+ if (rotate.state == UIGestureRecognizerStateChanged)
{
CGFloat newDegrees = MGLDegreesFromRadians(self.angle + rotate.rotation) * -1;
@@ -1740,14 +1914,14 @@ public:
newDegrees = fminf(newDegrees, 30);
newDegrees = fmaxf(newDegrees, -30);
}
-
+
MGLMapCamera *toCamera = [self cameraByRotatingToDirection:newDegrees aroundAnchorPoint:centerPoint];
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
- self.mbglMap.jumpTo(mbgl::CameraOptions()
- .withBearing(newDegrees)
- .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y}));
+ self.mbglMap.jumpTo(mbgl::CameraOptions()
+ .withBearing(newDegrees)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y}));
}
[self cameraIsChanging];
@@ -1768,8 +1942,12 @@ public:
}
}
}
- else if (rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled)
+ else if ((rotate.state == UIGestureRecognizerStateEnded || rotate.state == UIGestureRecognizerStateCancelled))
{
+ self.rotationBeforeThresholdMet = 0;
+ if (! self.isRotating) { return; }
+ self.isRotating = NO;
+
CGFloat velocity = rotate.velocity;
CGFloat decelerationRate = self.decelerationRate;
if (decelerationRate != MGLMapViewDecelerationRateImmediate && fabs(velocity) > 3)
@@ -1783,14 +1961,13 @@ public:
if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
{
self.mbglMap.easeTo(mbgl::CameraOptions()
- .withBearing(newDegrees)
- .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }),
+ .withBearing(newDegrees)
+ .withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }),
MGLDurationFromTimeInterval(decelerationRate));
[self notifyGestureDidEndWithDrift:YES];
-
__weak MGLMapView *weakSelf = self;
-
+
[self animateWithDelay:decelerationRate animations:^
{
[weakSelf unrotateIfNeededForGesture];
@@ -2016,6 +2193,14 @@ public:
if (twoFingerDrag.state == UIGestureRecognizerStateBegan)
{
+ CGPoint midPoint = [twoFingerDrag translationInView:twoFingerDrag.view];
+ // In the following if and for the first execution middlePoint
+ // will be equal to dragGestureMiddlePoint and the resulting
+ // gestureSlopeAngle will be 0º causing a small delay,
+ // initializing dragGestureMiddlePoint with the current midPoint
+ // but substracting one point from 'y' forces an initial 90º angle
+ // making the gesture avoid the delay
+ self.dragGestureMiddlePoint = CGPointMake(midPoint.x, midPoint.y-1);
initialPitch = *self.mbglMap.getCameraOptions().pitch;
[self notifyGestureDidBegin];
}
@@ -2027,30 +2212,45 @@ public:
twoFingerDrag.state = UIGestureRecognizerStateEnded;
return;
}
-
- CGFloat gestureDistance = CGPoint([twoFingerDrag translationInView:twoFingerDrag.view]).y;
- CGFloat slowdown = 2.0;
-
- CGFloat pitchNew = initialPitch - (gestureDistance / slowdown);
-
- CGPoint centerPoint = [self anchorPointForGesture:twoFingerDrag];
-
- MGLMapCamera *oldCamera = self.camera;
- MGLMapCamera *toCamera = [self cameraByTiltingToPitch:pitchNew];
-
- if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
- {
- self.mbglMap.jumpTo(mbgl::CameraOptions()
+
+ CGPoint leftTouchPoint = [twoFingerDrag locationOfTouch:0 inView:twoFingerDrag.view];
+ CGPoint rightTouchPoint = [twoFingerDrag locationOfTouch:1 inView:twoFingerDrag.view];
+ CLLocationDegrees fingerSlopeAngle = [self angleBetweenPoints:leftTouchPoint endPoint:rightTouchPoint];
+
+ CGPoint middlePoint = [twoFingerDrag translationInView:twoFingerDrag.view];
+
+ CLLocationDegrees gestureSlopeAngle = [self angleBetweenPoints:self.dragGestureMiddlePoint endPoint:middlePoint];
+ self.dragGestureMiddlePoint = middlePoint;
+ if (fabs(fingerSlopeAngle) < MGLHorizontalTiltToleranceDegrees && fabs(gestureSlopeAngle) > 60.0 ) {
+
+ CGFloat gestureDistance = middlePoint.y;
+ CGFloat slowdown = 2.0;
+
+ CGFloat pitchNew = initialPitch - (gestureDistance / slowdown);
+
+ CGPoint centerPoint = [self anchorPointForGesture:twoFingerDrag];
+
+ MGLMapCamera *oldCamera = self.camera;
+ MGLMapCamera *toCamera = [self cameraByTiltingToPitch:pitchNew];
+
+ if ([self _shouldChangeFromCamera:oldCamera toCamera:toCamera])
+ {
+ self.mbglMap.jumpTo(mbgl::CameraOptions()
.withPitch(pitchNew)
.withAnchor(mbgl::ScreenCoordinate { centerPoint.x, centerPoint.y }));
+ }
+
+ [self cameraIsChanging];
+
}
- [self cameraIsChanging];
+
}
else if (twoFingerDrag.state == UIGestureRecognizerStateEnded || twoFingerDrag.state == UIGestureRecognizerStateCancelled)
{
[self notifyGestureDidEndWithDrift:NO];
[self unrotateIfNeededForGesture];
+ self.dragGestureMiddlePoint = CGPointZero;
}
}
@@ -2173,23 +2373,17 @@ public:
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer
{
- if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]])
+ if (gestureRecognizer == _twoFingerDrag)
{
UIPanGestureRecognizer *panGesture = (UIPanGestureRecognizer *)gestureRecognizer;
if (panGesture.minimumNumberOfTouches == 2)
{
- CGPoint west = [panGesture locationOfTouch:0 inView:panGesture.view];
- CGPoint east = [panGesture locationOfTouch:1 inView:panGesture.view];
-
- if (west.x > east.x) {
- CGPoint swap = west;
- west = east;
- east = swap;
- }
+ CGPoint leftTouchPoint = [panGesture locationOfTouch:0 inView:panGesture.view];
+ CGPoint rightTouchPoint = [panGesture locationOfTouch:1 inView:panGesture.view];
- CLLocationDegrees horizontalToleranceDegrees = 60.0;
- if ([self angleBetweenPoints:west east:east] > horizontalToleranceDegrees) {
+ CLLocationDegrees degrees = [self angleBetweenPoints:leftTouchPoint endPoint:rightTouchPoint];
+ if (fabs(degrees) > MGLHorizontalTiltToleranceDegrees) {
return NO;
}
}
@@ -2211,18 +2405,24 @@ public:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
NSArray *validSimultaneousGestures = @[ self.pan, self.pinch, self.rotate ];
-
return ([validSimultaneousGestures containsObject:gestureRecognizer] && [validSimultaneousGestures containsObject:otherGestureRecognizer]);
}
-- (CLLocationDegrees)angleBetweenPoints:(CGPoint)west east:(CGPoint)east
+- (CLLocationDegrees)angleBetweenPoints:(CGPoint)originPoint endPoint:(CGPoint)endPoint
{
- CGFloat slope = (west.y - east.y) / (west.x - east.x);
+ if (originPoint.x > endPoint.x) {
+ CGPoint swap = originPoint;
+ originPoint = endPoint;
+ endPoint = swap;
+ }
+
+ CGFloat x = (endPoint.x - originPoint.x);
+ CGFloat y = (endPoint.y - originPoint.y);
- CGFloat angle = atan(fabs(slope));
- CLLocationDegrees degrees = MGLDegreesFromRadians(angle);
+ CGFloat angleInRadians = atan2(y, x);
+ CLLocationDegrees angleInDegrees = MGLDegreesFromRadians(angleInRadians);
- return degrees;
+ return angleInDegrees;
}
#pragma mark - Attribution -
@@ -2302,7 +2502,7 @@ public:
NSString *message;
NSString *participateTitle;
NSString *declineTitle;
- if ([[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsEnabled"])
+ if ([[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsEnabledKey])
{
message = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_MSG", nil, nil, @"You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.", @"Telemetry prompt message");
participateTitle = NSLocalizedStringWithDefaultValue(@"TELEMETRY_ENABLED_ON", nil, nil, @"Keep Participating", @"Telemetry prompt button");
@@ -2330,14 +2530,14 @@ public:
UIAlertAction *declineAction = [UIAlertAction actionWithTitle:declineTitle
style:UIAlertActionStyleDefault
handler:^(UIAlertAction * _Nonnull action) {
- [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"MGLMapboxMetricsEnabled"];
+ [[NSUserDefaults standardUserDefaults] setBool:NO forKey:MGLMapboxMetricsEnabledKey];
}];
[alertController addAction:declineAction];
UIAlertAction *participateAction = [UIAlertAction actionWithTitle:participateTitle
style:UIAlertActionStyleCancel
handler:^(UIAlertAction * _Nonnull action) {
- [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"MGLMapboxMetricsEnabled"];
+ [[NSUserDefaults standardUserDefaults] setBool:YES forKey:MGLMapboxMetricsEnabledKey];
}];
[alertController addAction:participateAction];
@@ -3188,26 +3388,35 @@ public:
animationOptions.duration.emplace(MGLDurationFromTimeInterval(duration));
animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}
+
+ dispatch_block_t pendingCompletion;
+
if (completion)
{
- animationOptions.transitionFinishFn = [completion]() {
+ __weak __typeof__(self) weakSelf = self;
+
+ pendingCompletion = ^{
+ if (![weakSelf scheduleTransitionCompletion:completion])
+ {
+ completion();
+ }
+ };
+
+ animationOptions.transitionFinishFn = [pendingCompletion]() {
// Must run asynchronously after the transition is completely over.
// Otherwise, a call to -setCenterCoordinate: within the completion
// handler would reenter the completion handler’s caller.
- dispatch_async(dispatch_get_main_queue(), ^{
- completion();
- });
+
+ dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}
MGLMapCamera *camera = [self cameraForCameraOptions:cameraOptions];
if ([self.camera isEqualToMapCamera:camera] && UIEdgeInsetsEqualToEdgeInsets(_contentInset, insets))
{
- if (completion)
+ if (pendingCompletion)
{
- [self animateWithDelay:duration animations:^{
- completion();
- }];
+ [self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
@@ -3374,12 +3583,22 @@ public:
animationOptions.duration.emplace(MGLDurationFromTimeInterval(duration));
animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}
+
+ dispatch_block_t pendingCompletion;
+
if (completion)
{
- animationOptions.transitionFinishFn = [completion]() {
- dispatch_async(dispatch_get_main_queue(), ^{
+ __weak __typeof__(self) weakSelf = self;
+
+ pendingCompletion = ^{
+ if (![weakSelf scheduleTransitionCompletion:completion])
+ {
completion();
- });
+ }
+ };
+
+ animationOptions.transitionFinishFn = [pendingCompletion]() {
+ dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}
@@ -3389,11 +3608,9 @@ public:
MGLMapCamera *camera = [self cameraForCameraOptions:cameraOptions];
if ([self.camera isEqualToMapCamera:camera])
{
- if (completion)
+ if (pendingCompletion)
{
- [self animateWithDelay:duration animations:^{
- completion();
- }];
+ [self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
@@ -3534,22 +3751,30 @@ public:
animationOptions.duration.emplace(MGLDurationFromTimeInterval(duration));
animationOptions.easing.emplace(MGLUnitBezierForMediaTimingFunction(function));
}
+
+ dispatch_block_t pendingCompletion;
+
if (completion)
{
- animationOptions.transitionFinishFn = [completion]() {
- dispatch_async(dispatch_get_main_queue(), ^{
+ __weak __typeof__(self) weakSelf = self;
+
+ pendingCompletion = ^{
+ if (![weakSelf scheduleTransitionCompletion:completion])
+ {
completion();
- });
+ }
+ };
+
+ animationOptions.transitionFinishFn = [pendingCompletion]() {
+ dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}
if ([self.camera isEqualToMapCamera:camera] && UIEdgeInsetsEqualToEdgeInsets(_contentInset, edgePadding))
{
- if (completion)
+ if (pendingCompletion)
{
- [self animateWithDelay:duration animations:^{
- completion();
- }];
+ [self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
@@ -3605,22 +3830,30 @@ public:
animationOptions.minZoom = MGLZoomLevelForAltitude(peakAltitude, peakPitch,
peakLatitude, self.frame.size);
}
+
+ dispatch_block_t pendingCompletion;
+
if (completion)
{
- animationOptions.transitionFinishFn = [completion]() {
- dispatch_async(dispatch_get_main_queue(), ^{
+ __weak __typeof__(self) weakSelf = self;
+
+ pendingCompletion = ^{
+ if (![weakSelf scheduleTransitionCompletion:completion])
+ {
completion();
- });
+ }
+ };
+
+ animationOptions.transitionFinishFn = [pendingCompletion]() {
+ dispatch_async(dispatch_get_main_queue(), pendingCompletion);
};
}
if ([self.camera isEqualToMapCamera:camera] && UIEdgeInsetsEqualToEdgeInsets(_contentInset, insets))
{
- if (completion)
+ if (pendingCompletion)
{
- [self animateWithDelay:duration animations:^{
- completion();
- }];
+ [self animateWithDelay:duration animations:pendingCompletion];
}
return;
}
diff --git a/platform/ios/src/MGLMapView_Private.h b/platform/ios/src/MGLMapView_Private.h
index e53dc8519c..155527000f 100644
--- a/platform/ios/src/MGLMapView_Private.h
+++ b/platform/ios/src/MGLMapView_Private.h
@@ -52,8 +52,6 @@ FOUNDATION_EXTERN MGL_EXPORT MGLExceptionName const _Nonnull MGLUnderlyingMapUna
/// Synchronously render a frame of the map.
- (void)renderSync;
-- (nonnull mbgl::Map *)mbglMap;
-
- (nonnull mbgl::Renderer *)renderer;
/** Returns whether the map view is currently loading or processing any assets required to render the map */
diff --git a/platform/ios/src/MGLMapboxEvents.h b/platform/ios/src/MGLMapboxEvents.h
index cb3132656f..a7d316cc06 100644
--- a/platform/ios/src/MGLMapboxEvents.h
+++ b/platform/ios/src/MGLMapboxEvents.h
@@ -3,6 +3,9 @@
NS_ASSUME_NONNULL_BEGIN
+/// NSUserDefaults key that controls telemetry user opt-out status
+FOUNDATION_EXTERN NSString * const MGLMapboxMetricsEnabledKey;
+
@interface MGLMapboxEvents : NSObject
+ (nullable instancetype)sharedInstance;
diff --git a/platform/ios/src/MGLMapboxEvents.m b/platform/ios/src/MGLMapboxEvents.m
index cc7390ac61..808c3a88bf 100644
--- a/platform/ios/src/MGLMapboxEvents.m
+++ b/platform/ios/src/MGLMapboxEvents.m
@@ -3,14 +3,16 @@
#import "NSBundle+MGLAdditions.h"
#import "MGLAccountManager_Private.h"
+// NSUserDefaults and Info.plist keys
+NSString * const MGLMapboxMetricsEnabledKey = @"MGLMapboxMetricsEnabled";
+static NSString * const MGLMapboxMetricsDebugLoggingEnabledKey = @"MGLMapboxMetricsDebugLoggingEnabled";
+static NSString * const MGLMapboxMetricsEnabledSettingShownInAppKey = @"MGLMapboxMetricsEnabledSettingShownInApp";
+static NSString * const MGLTelemetryAccessTokenKey = @"MGLTelemetryAccessToken";
+static NSString * const MGLTelemetryBaseURLKey = @"MGLTelemetryBaseURL";
+static NSString * const MGLEventsProfileKey = @"MMEEventsProfile";
+static NSString * const MGLVariableGeofenceKey = @"VariableGeofence";
+
static NSString * const MGLAPIClientUserAgentBase = @"mapbox-maps-ios";
-static NSString * const MGLMapboxAccountType = @"MGLMapboxAccountType";
-static NSString * const MGLMapboxMetricsEnabled = @"MGLMapboxMetricsEnabled";
-static NSString * const MGLMapboxMetricsDebugLoggingEnabled = @"MGLMapboxMetricsDebugLoggingEnabled";
-static NSString * const MGLTelemetryAccessToken = @"MGLTelemetryAccessToken";
-static NSString * const MGLTelemetryBaseURL = @"MGLTelemetryBaseURL";
-static NSString * const MGLEventsProfile = @"MMEEventsProfile";
-static NSString * const MGLVariableGeofence = @"VariableGeofence";
@interface MGLMapboxEvents ()
@@ -19,16 +21,16 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
@property (nonatomic, copy) NSString *accessToken;
@end
-@implementation MGLMapboxEvents
+@implementation MGLMapboxEvents
+ (void)initialize {
if (self == [MGLMapboxEvents class]) {
NSBundle *bundle = [NSBundle mainBundle];
- NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:MGLMapboxAccountType];
- [[NSUserDefaults standardUserDefaults] registerDefaults:@{MGLMapboxAccountType: accountTypeNumber ?: @0,
- MGLMapboxMetricsEnabled: @YES,
- MGLMapboxMetricsDebugLoggingEnabled: @NO}];
+ NSNumber *accountTypeNumber = [bundle objectForInfoDictionaryKey:MGLMapboxAccountTypeKey];
+ [[NSUserDefaults standardUserDefaults] registerDefaults:@{MGLMapboxAccountTypeKey: accountTypeNumber ?: @0,
+ MGLMapboxMetricsEnabledKey: @YES,
+ MGLMapboxMetricsDebugLoggingEnabledKey: @NO}];
}
}
@@ -46,9 +48,9 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
self = [super init];
if (self) {
_eventsManager = MMEEventsManager.sharedManager;
- _eventsManager.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsDebugLoggingEnabled];
- _eventsManager.accountType = [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountType];
- _eventsManager.metricsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsEnabled];
+ _eventsManager.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsDebugLoggingEnabledKey];
+ _eventsManager.accountType = [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountTypeKey];
+ _eventsManager.metricsEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsEnabledKey];
// It is possible for the shared instance of this class to be created because of a call to
// +[MGLAccountManager load] early on in the app lifecycle of the host application.
@@ -57,11 +59,11 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
// (once -[MMEEventsManager initializeWithAccessToken:userAgentBase:hostSDKVersion:] is called.
// Normally, the telem access token and base URL are not set this way. However, overriding these values
// with user defaults can be useful for testing with an alternative (test) backend system.
- if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryAccessToken]) {
- self.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryAccessToken];
+ if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryAccessTokenKey]) {
+ self.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryAccessTokenKey];
}
- if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryBaseURL]) {
- self.baseURL = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryBaseURL]];
+ if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryBaseURLKey]) {
+ self.baseURL = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryBaseURLKey]];
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:NSUserDefaultsDidChangeNotification object:nil];
@@ -81,22 +83,22 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
}
- (void)updateNonDisablingConfigurationValues {
- self.eventsManager.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"MGLMapboxMetricsDebugLoggingEnabled"];
+ self.eventsManager.debugLoggingEnabled = [[NSUserDefaults standardUserDefaults] boolForKey:MGLMapboxMetricsDebugLoggingEnabledKey];
- // It is possible for `MGLTelemetryAccessToken` to have been set yet `userDefaultsDidChange:`
+ // It is possible for the telemetry access token key to have been set yet `userDefaultsDidChange:`
// is called before `setupWithAccessToken:` is called.
// In that case, setting the access token here will have no effect. In practice, that's fine
// because the access token value will be resolved when `setupWithAccessToken:` is called eventually
- if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryAccessToken]) {
- self.eventsManager.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryAccessToken];
+ if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryAccessTokenKey]) {
+ self.eventsManager.accessToken = [[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryAccessTokenKey];
}
- // It is possible for `MGLTelemetryBaseURL` to have been set yet `userDefaultsDidChange:`
+ // It is possible for the telemetry base URL key to have been set yet `userDefaultsDidChange:`
// is called before setupWithAccessToken: is called.
// In that case, setting the base URL here will have no effect. In practice, that's fine
// because the base URL value will be resolved when `setupWithAccessToken:` is called eventually
- if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryBaseURL]) {
- NSURL *baseURL = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryBaseURL]];
+ if ([[[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys] containsObject:MGLTelemetryBaseURLKey]) {
+ NSURL *baseURL = [NSURL URLWithString:[[NSUserDefaults standardUserDefaults] objectForKey:MGLTelemetryBaseURLKey]];
self.eventsManager.baseURL = baseURL;
}
}
@@ -109,8 +111,8 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
if ([[notification object] respondsToSelector:@selector(objectForKey:)]) {
NSUserDefaults *userDefaults = [notification object];
- NSInteger accountType = [userDefaults integerForKey:MGLMapboxAccountType];
- BOOL metricsEnabled = [userDefaults boolForKey:MGLMapboxMetricsEnabled];
+ NSInteger accountType = [userDefaults integerForKey:MGLMapboxAccountTypeKey];
+ BOOL metricsEnabled = [userDefaults boolForKey:MGLMapboxMetricsEnabledKey];
if (accountType != self.eventsManager.accountType || metricsEnabled != self.eventsManager.metricsEnabled) {
self.eventsManager.accountType = accountType;
@@ -124,7 +126,7 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
+ (void)setupWithAccessToken:(NSString *)accessToken {
int64_t delayTime = 0;
- if ([[[NSBundle mainBundle] objectForInfoDictionaryKey:MGLEventsProfile] isEqualToString:MGLVariableGeofence]) {
+ if ([[[NSBundle mainBundle] objectForInfoDictionaryKey:MGLEventsProfileKey] isEqualToString:MGLVariableGeofenceKey]) {
delayTime = 10;
}
@@ -164,11 +166,11 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
}
+ (void)ensureMetricsOptoutExists {
- NSNumber *shownInAppNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"MGLMapboxMetricsEnabledSettingShownInApp"];
+ NSNumber *shownInAppNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:MGLMapboxMetricsEnabledSettingShownInAppKey];
BOOL metricsEnabledSettingShownInAppFlag = [shownInAppNumber boolValue];
if (!metricsEnabledSettingShownInAppFlag &&
- [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountType] == 0) {
+ [[NSUserDefaults standardUserDefaults] integerForKey:MGLMapboxAccountTypeKey] == 0) {
// Opt-out is not configured in UI, so check for Settings.bundle
id defaultEnabledValue;
NSString *appSettingsBundle = [[NSBundle mainBundle] pathForResource:@"Settings" ofType:@"bundle"];
@@ -178,7 +180,7 @@ static NSString * const MGLVariableGeofence = @"VariableGeofence";
NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[appSettingsBundle stringByAppendingPathComponent:@"Root.plist"]];
NSArray *preferences = settings[@"PreferenceSpecifiers"];
for (NSDictionary *prefSpecification in preferences) {
- if ([prefSpecification[@"Key"] isEqualToString:MGLMapboxMetricsEnabled]) {
+ if ([prefSpecification[@"Key"] isEqualToString:MGLMapboxMetricsEnabledKey]) {
defaultEnabledValue = prefSpecification[@"DefaultValue"];
}
}
diff --git a/platform/ios/src/MGLScaleBar.mm b/platform/ios/src/MGLScaleBar.mm
index 9590a99438..993852d8b9 100644
--- a/platform/ios/src/MGLScaleBar.mm
+++ b/platform/ios/src/MGLScaleBar.mm
@@ -84,7 +84,7 @@ static const MGLRow MGLImperialTable[] ={
@property (nonatomic) UIColor *secondaryColor;
@property (nonatomic) CALayer *borderLayer;
@property (nonatomic, assign) CGFloat borderWidth;
-@property (nonatomic) NSCache* labelImageCache;
+@property (nonatomic) NSMutableDictionary* labelImageCache;
@property (nonatomic) MGLScaleBarLabel* prototypeLabel;
@property (nonatomic) CGFloat lastLabelWidth;
@@ -159,7 +159,7 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
_formatter = [[MGLDistanceFormatter alloc] init];
// Image labels are now images
- _labelImageCache = [[NSCache alloc] init];
+ _labelImageCache = [[NSMutableDictionary alloc] init];
_prototypeLabel = [[MGLScaleBarLabel alloc] init];
_prototypeLabel.font = [UIFont systemFontOfSize:8 weight:UIFontWeightMedium];
_prototypeLabel.clipsToBounds = NO;
@@ -180,6 +180,17 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
// Zero is a special case (no formatting)
[self addZeroLabel];
+
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(resetLabelImageCache) name:NSCurrentLocaleDidChangeNotification object:nil];
+}
+
+- (void)dealloc {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)resetLabelImageCache {
+ self.labelImageCache = [[NSMutableDictionary alloc] init];
+ [self addZeroLabel];
}
#pragma mark - Dimensions
diff --git a/platform/ios/test/MGLMapViewDirectionTests.mm b/platform/ios/test/MGLMapViewDirectionTests.mm
index 8a724a06bc..81e169432b 100644
--- a/platform/ios/test/MGLMapViewDirectionTests.mm
+++ b/platform/ios/test/MGLMapViewDirectionTests.mm
@@ -1,5 +1,6 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>
+#import "MGLMockGestureRecognizers.h"
#import <mbgl/math/wrap.hpp>
@@ -8,12 +9,6 @@
- (void)resetNorthAnimated:(BOOL)animated;
@end
-@interface UIRotationGestureRecognizerMock : UIRotationGestureRecognizer
-@end
-
-@implementation UIRotationGestureRecognizerMock
-- (CGPoint)locationInView:(nullable UIView*)view { return view.center; }
-@end
@interface MGLMapViewDirectionTests : XCTestCase
@property (nonatomic) MGLMapView *mapView;
diff --git a/platform/ios/test/MGLMapViewPitchTests.m b/platform/ios/test/MGLMapViewPitchTests.m
index b7b18973a1..3e9311dbd4 100644
--- a/platform/ios/test/MGLMapViewPitchTests.m
+++ b/platform/ios/test/MGLMapViewPitchTests.m
@@ -2,23 +2,35 @@
#import <XCTest/XCTest.h>
@interface MockUIPanGestureRecognizer : UIPanGestureRecognizer
-@property CGFloat mbx_tiltGestureYTranslation;
@property NSUInteger mbx_numberOfFingersForGesture;
+@property CGPoint mbx_middlePoint;
+@property CGPoint mbx_westPoint;
+@property CGPoint mbx_eastPoint;
@end
@implementation MockUIPanGestureRecognizer
- (instancetype)initWithTarget:(id)target action:(SEL)action {
if (self = [super initWithTarget:target action:action]) {
- self.mbx_tiltGestureYTranslation = 0;
self.mbx_numberOfFingersForGesture = 2;
+ self.mbx_westPoint = CGPointMake(100, 0);
+ self.mbx_eastPoint = CGPointMake(200, 0);
}
return self;
}
- (NSUInteger)numberOfTouches { return self.mbx_numberOfFingersForGesture; }
-- (CGPoint)translationInView:(UIView *)view { return CGPointMake(0, self.mbx_tiltGestureYTranslation); }
+- (CGPoint)translationInView:(UIView *)view { return self.mbx_middlePoint; }
+- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(UIView *)view {
+ if (touchIndex == 0) {
+ return self.mbx_westPoint;
+ }
+ return self.mbx_eastPoint;
+}
- (void)setTiltGestureYTranslationForPitchDegrees:(CGFloat)degrees {
// The tilt gesture takes the number of screen points the fingers have moved and then divides them by a "slowdown" factor, which happens to be set to 2.0 in -[MGLMapView handleTwoFingerDragGesture:].
- self.mbx_tiltGestureYTranslation = -(degrees * 2.0);
+ CGFloat mbx_tiltGestureYTranslation = -(degrees * 2.0);
+ self.mbx_westPoint = CGPointMake(self.mbx_westPoint.x, mbx_tiltGestureYTranslation);
+ self.mbx_eastPoint = CGPointMake(self.mbx_eastPoint.x, mbx_tiltGestureYTranslation);
+ self.mbx_middlePoint = CGPointMake(self.mbx_middlePoint.x, mbx_tiltGestureYTranslation);
}
@end
@@ -112,6 +124,25 @@
}
}
+- (void)testHorizontalTiltGesture {
+ MockUIPanGestureRecognizer *gesture = [[MockUIPanGestureRecognizer alloc] initWithTarget:self.mapView action:nil];
+ gesture.state = UIGestureRecognizerStateBegan;
+ [self.mapView handleTwoFingerDragGesture:gesture];
+ XCTAssertEqual(self.mapView.camera.pitch, 0, @"Pitch should initially be set to 0°.");
+
+ // Tilt gestures should not be triggered on horizontal dragging.
+ for (NSInteger deltaX = 0; deltaX < 5; deltaX++) {
+ gesture.mbx_westPoint = CGPointMake(100 - deltaX, 100);
+ gesture.mbx_eastPoint = CGPointMake(100 - deltaX, 50);
+ gesture.mbx_middlePoint = CGPointMake((gesture.mbx_westPoint.x + gesture.mbx_westPoint.x)/2, (gesture.mbx_westPoint.y + gesture.mbx_westPoint.y)/2);
+
+ gesture.state = UIGestureRecognizerStateChanged;
+
+ [self.mapView handleTwoFingerDragGesture:gesture];
+ XCTAssertEqual(self.mapView.camera.pitch, 0, @"Horizontal dragging should not tilt the map.");
+ }
+}
+
- (void)testTiltGestureFromInitialTilt {
CGFloat initialTilt = 20;
CGFloat additionalTilt = 30;
diff --git a/platform/ios/test/MGLMapViewZoomTests.m b/platform/ios/test/MGLMapViewZoomTests.mm
index bd617857fd..360af72d02 100644
--- a/platform/ios/test/MGLMapViewZoomTests.m
+++ b/platform/ios/test/MGLMapViewZoomTests.mm
@@ -1,16 +1,14 @@
#import <Mapbox/Mapbox.h>
#import <XCTest/XCTest.h>
+#import "MGLMockGestureRecognizers.h"
+
+#import <mbgl/math/wrap.hpp>
@interface MGLMapView (MGLMapViewZoomTests)
+@property (nonatomic) BOOL isZooming;
+@property (nonatomic) CGFloat rotationThresholdWhileZooming;
- (void)handlePinchGesture:(UIPinchGestureRecognizer *)pinch;
-@end
-
-@interface UIPinchGestureRecognizerMock : UIPinchGestureRecognizer
-@property (nonatomic) CGPoint locationInViewOverride;
-@end
-
-@implementation UIPinchGestureRecognizerMock
-- (CGPoint)locationInView:(nullable UIView *)view { return self.locationInViewOverride; }
+- (void)handleRotateGesture:(UIRotationGestureRecognizer *)rotate;
@end
@interface MGLMapViewZoomTests : XCTestCase
@@ -129,6 +127,60 @@
XCTAssertEqualWithAccuracy(centerCoordinateBeforeReset.longitude, self.mapView.centerCoordinate.longitude, 0.0000001, @"Map center coordinate longitude should remain constant after resetting to north.");
}
+- (void)testPinchAndZoom {
+
+ [[NSUserDefaults standardUserDefaults] setObject:@3 forKey:@"MGLRotationThresholdWhileZooming"];
+ self.mapView.rotationThresholdWhileZooming = 3;
+ self.mapView.zoomLevel = 15;
+ UIPinchGestureRecognizerMock *pinch = [[UIPinchGestureRecognizerMock alloc] initWithTarget:self.mapView action:nil];
+ [self.mapView addGestureRecognizer:pinch];
+ pinch.state = UIGestureRecognizerStateBegan;
+ pinch.velocity = 5.0;
+ pinch.locationInViewOverride = CGPointMake(0, 0);
+ [self.mapView handlePinchGesture:pinch];
+
+ XCTAssertTrue(self.mapView.isZooming);
+
+ UIRotationGestureRecognizerMock *rotate = [[UIRotationGestureRecognizerMock alloc] initWithTarget:self.mapView action:nil];
+ rotate.state = UIGestureRecognizerStateBegan;
+ rotate.rotation = MGLRadiansFromDegrees(1);
+ [self.mapView addGestureRecognizer:rotate];
+ [self.mapView handleRotateGesture:rotate];
+
+ // Both the rotation and direction should be zero since the rotation threshold hasn't been met.
+ XCTAssertEqual(rotate.rotation, 0);
+ XCTAssertEqual(self.mapView.direction, 0);
+
+ // The direction should be `0`. The default rotation threshold is `3`.
+ XCTAssertEqual(self.mapView.direction, 0);
+ rotate.state = UIGestureRecognizerStateChanged;
+ rotate.rotation = MGLRadiansFromDegrees(2);
+ [self.mapView handleRotateGesture:rotate];
+
+ // The direction should be `0`. The default rotation threshold is `3`.
+ XCTAssertEqual(self.mapView.direction, 0);
+
+ for (NSNumber *degrees in @[@-90, @-10, @10, @10, @30, @90, @180, @240, @460, @500, @590, @800]) {
+ rotate.state = UIGestureRecognizerStateChanged;
+ rotate.rotation = MGLRadiansFromDegrees([degrees doubleValue]);
+ [self.mapView handleRotateGesture:rotate];
+
+ CGFloat wrappedRotation = mbgl::util::wrap(-MGLDegreesFromRadians(rotate.rotation), 0., 360.);
+
+
+ // Check that the direction property now matches the gesture's rotation.
+ XCTAssertEqualWithAccuracy(self.mapView.direction, wrappedRotation, 0.001, @"Map direction should match gesture rotation for input of %@°.", degrees);
+ }
+
+ rotate.state = UIGestureRecognizerStateEnded;
+ pinch.state = UIGestureRecognizerStateEnded;
+
+ [self.mapView handleRotateGesture:rotate];
+ [self.mapView handlePinchGesture:pinch];
+
+ XCTAssertFalse(self.mapView.isZooming);
+}
+
NS_INLINE CGFloat MGLScaleFromZoomLevel(double zoom) {
return pow(2, zoom);
}
diff --git a/platform/ios/test/MGLMockGestureRecognizers.h b/platform/ios/test/MGLMockGestureRecognizers.h
new file mode 100644
index 0000000000..aa5fbec494
--- /dev/null
+++ b/platform/ios/test/MGLMockGestureRecognizers.h
@@ -0,0 +1,10 @@
+
+#import <UIKit/UIKit.h>
+
+@interface UIPinchGestureRecognizerMock : UIPinchGestureRecognizer
+@property (nonatomic, readwrite) CGFloat velocity;
+@property (nonatomic) CGPoint locationInViewOverride;
+@end
+
+@interface UIRotationGestureRecognizerMock : UIRotationGestureRecognizer
+@end
diff --git a/platform/ios/test/MGLMockGestureRecognizers.m b/platform/ios/test/MGLMockGestureRecognizers.m
new file mode 100644
index 0000000000..89df6750a9
--- /dev/null
+++ b/platform/ios/test/MGLMockGestureRecognizers.m
@@ -0,0 +1,11 @@
+
+#import "MGLMockGestureRecognizers.h"
+
+@implementation UIPinchGestureRecognizerMock
+@synthesize velocity;
+- (CGPoint)locationInView:(nullable UIView *)view { return self.locationInViewOverride; }
+@end
+
+@implementation UIRotationGestureRecognizerMock
+- (CGPoint)locationInView:(nullable UIView*)view { return view.center; }
+@end
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index 377be60c6f..076bc64a6e 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -9,9 +9,11 @@
* The `MGLIdeographicFontFamilyName` Info.plist key now also accepts an array of font family names, to customize font fallback behavior. It can also be set to a Boolean value of `NO` to force the SDK to typeset CJK characters in a remote font specified by `MGLSymbolStyleLayer.textFontNames`. ([#14862](https://github.com/mapbox/mapbox-gl-native/pull/14862))
* Performance improvements for queryRenderedFeatures API and optimization that allocates containers based on a number of rendered layers. ([#14930](https://github.com/mapbox/mapbox-gl-native/pull/14930))
* Fixed rendering layers after fill-extrusion regression caused by optimization of fill-extrusion rendering. ([#15065](https://github.com/mapbox/mapbox-gl-native/pull/15065))
-* `MGLLoggingLevel` has been updated for better matching core log levels. Now can use `[MGLLoggingConfiguration sharedConfiguration].loggingLevel` to filter logs from core . [#15120](https://github.com/mapbox/mapbox-gl-native/pull/15120)
-* Fixed an issue where animated camera transitions zoomed in or out too dramatically. [#15281](https://github.com/mapbox/mapbox-gl-native/pull/15281)
+* `MGLLoggingLevel` has been updated for better matching core log levels. Now can use `[MGLLoggingConfiguration sharedConfiguration].loggingLevel` to filter logs from core . ([#15120](https://github.com/mapbox/mapbox-gl-native/pull/15120))
+* Fixed an issue where animated camera transitions zoomed in or out too dramatically. ([#15281](https://github.com/mapbox/mapbox-gl-native/pull/15281))
* Fixed rendering and collision detection issues with using `text-variable-anchor` and `icon-text-fit` properties on the same layer. ([#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367))
+* Fixed symbol overlap when zooming out quickly. ([15416](https://github.com/mapbox/mapbox-gl-native/pull/15416))
+* Fixed a rendering issue that non-SDF icon would be treated as SDF icon if they are in the same layer. ([#15456](https://github.com/mapbox/mapbox-gl-native/pull/15456))
### Styles and rendering
diff --git a/platform/macos/src/MGLMapView+Impl.h b/platform/macos/src/MGLMapView+Impl.h
index 2d523716d4..de235fa147 100644
--- a/platform/macos/src/MGLMapView+Impl.h
+++ b/platform/macos/src/MGLMapView+Impl.h
@@ -30,7 +30,7 @@ public:
void onDidFinishLoadingMap() override;
void onDidFailLoadingMap(mbgl::MapLoadError mapError, const std::string& what) override;
void onWillStartRenderingFrame() override;
- void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode) override;
+ void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode, bool /*placementChanged*/) override;
void onWillStartRenderingMap() override;
void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode) override;
void onDidFinishLoadingStyle() override;
diff --git a/platform/macos/src/MGLMapView+Impl.mm b/platform/macos/src/MGLMapView+Impl.mm
index 2354f67a6d..1ed5e2ceef 100644
--- a/platform/macos/src/MGLMapView+Impl.mm
+++ b/platform/macos/src/MGLMapView+Impl.mm
@@ -67,7 +67,7 @@ void MGLMapViewImpl::onWillStartRenderingFrame() {
[mapView mapViewWillStartRenderingFrame];
}
-void MGLMapViewImpl::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode) {
+void MGLMapViewImpl::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode, bool) {
bool fullyRendered = mode == mbgl::MapObserver::RenderMode::Full;
[mapView mapViewDidFinishRenderingFrameFullyRendered:fullyRendered];
}
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 3c9647571e..9a7cb437ec 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -276,7 +276,7 @@ public:
MGLRendererConfiguration *config = [MGLRendererConfiguration currentConfiguration];
- auto renderer = std::make_unique<mbgl::Renderer>(_mbglView->getRendererBackend(), config.scaleFactor, config.cacheDir, config.localFontFamilyName);
+ auto renderer = std::make_unique<mbgl::Renderer>(_mbglView->getRendererBackend(), config.scaleFactor, config.localFontFamilyName);
BOOL enableCrossSourceCollisions = !config.perSourceCollisions;
_rendererFrontend = std::make_unique<MGLRenderFrontend>(std::move(renderer), self, _mbglView->getRendererBackend(), true);
diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md
index fa798d2676..9338409b3e 100644
--- a/platform/node/CHANGELOG.md
+++ b/platform/node/CHANGELOG.md
@@ -1,15 +1,16 @@
# master
* Introduce `text-writing-mode` layout property for symbol layer ([#14932](https://github.com/mapbox/mapbox-gl-native/pull/14932)). The `text-writing-mode` layout property allows control over symbol's preferred writing mode. The new property value is an array, whose values are enumeration values from a ( `horizontal` | `vertical` ) set.
* Fixed rendering and collision detection issues with using `text-variable-anchor` and `icon-text-fit` properties on the same layer ([#15367](https://github.com/mapbox/mapbox-gl-native/pull/15367)).
+* Fixed a rendering issue that non-SDF icon would be treated as SDF icon if they are in the same layer. ([#15456](https://github.com/mapbox/mapbox-gl-native/pull/15456))
# 4.2.0
- Add an option to set whether or not an image should be treated as a SDF ([#15054](https://github.com/mapbox/mapbox-gl-native/issues/15054))
-- Fix problems associated with node 10 and NAN [#14847](https://github.com/mapbox/mapbox-gl-native/pull/14847)
+- Fix problems associated with node 10 and NAN ([#14847](https://github.com/mapbox/mapbox-gl-native/pull/14847))
# 4.1.0
-- Add `symbol-z-order` symbol layout property to style spec [#12783](https://github.com/mapbox/mapbox-gl-native/pull/12783)
-- Add `crossSourceCollisions` map option, with default of `true`. When set to `false`, cross-source collision detection is disabled. ([#12820] (https://github.com/mapbox/mapbox-gl-native/issues/12820))
-- Fixed bugs in coercion expression operators ("to-array" applied to empty arrays, "to-color" applied to colors, and "to-number" applied to null) [#12864](https://github.com/mapbox/mapbox-gl-native/pull/12864)
+- Add `symbol-z-order` symbol layout property to style spec ([#12783](https://github.com/mapbox/mapbox-gl-native/pull/12783))
+- Add `crossSourceCollisions` map option, with default of `true`. When set to `false`, cross-source collision detection is disabled. ([#12820](https://github.com/mapbox/mapbox-gl-native/issues/12820))
+- Fixed bugs in coercion expression operators ("to-array" applied to empty arrays, "to-color" applied to colors, and "to-number" applied to null) ([#12864](https://github.com/mapbox/mapbox-gl-native/pull/12864))
- Fixed an issue where fill and line layers would occasionally flicker on zoom ([#12982](https://github.com/mapbox/mapbox-gl-native/pull/12982))
# 4.0.0
diff --git a/platform/node/test/ignores.json b/platform/node/test/ignores.json
index 0595d61297..8079c4cabb 100644
--- a/platform/node/test/ignores.json
+++ b/platform/node/test/ignores.json
@@ -40,10 +40,6 @@
"render-tests/custom-layer-js/tent-3d": "skip - js specific",
"render-tests/regressions/mapbox-gl-js#7708": "skip - js specific",
"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",
- "render-tests/debug/collision-lines-overscaled": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
- "render-tests/debug/collision-lines-pitched": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
- "render-tests/debug/collision-pitched-wrapped": "https://github.com/mapbox/mapbox-gl-native/issues/10412",
"render-tests/debug/tile": "https://github.com/mapbox/mapbox-gl-native/issues/3841",
"render-tests/debug/tile-overscaled": "https://github.com/mapbox/mapbox-gl-native/issues/3841",
"render-tests/extent/1024-circle": "needs investigation",
@@ -73,10 +69,6 @@
"render-tests/regressions/mapbox-gl-js#7302": "skip - js specific",
"render-tests/regressions/mapbox-gl-native#7357": "https://github.com/mapbox/mapbox-gl-native/issues/7357",
"render-tests/symbol-cross-fade/chinese": "https://github.com/mapbox/mapbox-gl-native/issues/10619",
- "render-tests/symbol-visibility/visible": "https://github.com/mapbox/mapbox-gl-native/issues/10409",
- "render-tests/text-pitch-alignment/auto-text-rotation-alignment-map": "https://github.com/mapbox/mapbox-gl-native/issues/9732",
- "render-tests/text-pitch-alignment/map-text-rotation-alignment-map": "https://github.com/mapbox/mapbox-gl-native/issues/9732",
- "render-tests/text-pitch-alignment/viewport-text-rotation-alignment-map": "https://github.com/mapbox/mapbox-gl-native/issues/9732",
"render-tests/video/default": "skip - https://github.com/mapbox/mapbox-gl-native/issues/601",
"render-tests/background-color/colorSpace-hcl": "needs issue",
"render-tests/feature-state/composite-expression": "https://github.com/mapbox/mapbox-gl-native/issues/12613",
diff --git a/platform/qt/src/local_glyph_rasterizer.cpp b/platform/qt/src/local_glyph_rasterizer.cpp
index 3f8df5d876..f62975b377 100644
--- a/platform/qt/src/local_glyph_rasterizer.cpp
+++ b/platform/qt/src/local_glyph_rasterizer.cpp
@@ -1,5 +1,6 @@
#include <mbgl/text/local_glyph_rasterizer.hpp>
#include <mbgl/util/i18n.hpp>
+#include <mbgl/util/constants.hpp>
#include <QtCore/QFile>
#include <QtGui/QFont>
@@ -17,13 +18,15 @@ public:
optional<std::string> fontFamily;
QFont font;
+ optional<QFontMetrics> metrics;
};
LocalGlyphRasterizer::Impl::Impl(const optional<std::string> fontFamily_)
: fontFamily(fontFamily_) {
if (isConfigured()) {
font.setFamily(QString::fromStdString(*fontFamily));
- font.setPixelSize(24);
+ font.setPixelSize(util::ONE_EM);
+ metrics = QFontMetrics(font);
}
}
@@ -39,29 +42,33 @@ LocalGlyphRasterizer::~LocalGlyphRasterizer() {
}
bool LocalGlyphRasterizer::canRasterizeGlyph(const FontStack&, GlyphID glyphID) {
- return util::i18n::allowsFixedWidthGlyphGeneration(glyphID) && impl->isConfigured();
+ return impl->isConfigured() && impl->metrics->inFont(glyphID) && util::i18n::allowsFixedWidthGlyphGeneration(glyphID);
}
Glyph LocalGlyphRasterizer::rasterizeGlyph(const FontStack&, GlyphID glyphID) {
Glyph glyph;
glyph.id = glyphID;
- QFontMetrics metrics(impl->font);
- Size size(metrics.width(glyphID), metrics.height());
+ if (!impl->isConfigured()) {
+ assert(false);
+ return glyph;
+ }
- glyph.metrics.width = size.width;
- glyph.metrics.height = size.height;
+ glyph.metrics.width = impl->metrics->width(glyphID);
+ glyph.metrics.height = impl->metrics->height();
glyph.metrics.left = 3;
glyph.metrics.top = -8;
- glyph.metrics.advance = metrics.width(glyphID);
+ glyph.metrics.advance = glyph.metrics.width;
+ // Set width of a glyph's backing image to be util::ONE_EM.
+ Size size(util::ONE_EM, glyph.metrics.height);
QImage image(QSize(size.width, size.height), QImage::Format_Alpha8);
image.fill(qRgba(0, 0, 0, 0));
-
QPainter painter(&image);
painter.setFont(impl->font);
painter.setRenderHints(QPainter::TextAntialiasing);
- painter.drawText(QPointF(0, metrics.ascent()), QString(QChar(glyphID)));
+ // Render at constant baseline, to align with glyphs that are rendered by node-fontnik.
+ painter.drawText(QPointF(0, 20), QString(QChar(glyphID)));
auto img = std::make_unique<uint8_t[]>(image.byteCount());
memcpy(img.get(), image.constBits(), image.byteCount());
diff --git a/platform/qt/src/qmapboxgl_map_observer.cpp b/platform/qt/src/qmapboxgl_map_observer.cpp
index 4a842026cd..7d2af08cc4 100644
--- a/platform/qt/src/qmapboxgl_map_observer.cpp
+++ b/platform/qt/src/qmapboxgl_map_observer.cpp
@@ -77,7 +77,7 @@ void QMapboxGLMapObserver::onWillStartRenderingFrame()
emit mapChanged(QMapboxGL::MapChangeWillStartRenderingFrame);
}
-void QMapboxGLMapObserver::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode)
+void QMapboxGLMapObserver::onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode mode, bool)
{
if (mode == mbgl::MapObserver::RenderMode::Partial) {
emit mapChanged(QMapboxGL::MapChangeDidFinishRenderingFrame);
diff --git a/platform/qt/src/qmapboxgl_map_observer.hpp b/platform/qt/src/qmapboxgl_map_observer.hpp
index a12e5e9c70..1620c1ef87 100644
--- a/platform/qt/src/qmapboxgl_map_observer.hpp
+++ b/platform/qt/src/qmapboxgl_map_observer.hpp
@@ -28,7 +28,7 @@ public:
void onDidFinishLoadingMap() final;
void onDidFailLoadingMap(mbgl::MapLoadError, const std::string&) final;
void onWillStartRenderingFrame() final;
- void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode) final;
+ void onDidFinishRenderingFrame(mbgl::MapObserver::RenderMode, bool /*placementChanged*/) final;
void onWillStartRenderingMap() final;
void onDidFinishRenderingMap(mbgl::MapObserver::RenderMode) final;
void onDidFinishLoadingStyle() final;
diff --git a/platform/qt/src/qmapboxgl_map_renderer.cpp b/platform/qt/src/qmapboxgl_map_renderer.cpp
index eba50af6bf..8423470323 100644
--- a/platform/qt/src/qmapboxgl_map_renderer.cpp
+++ b/platform/qt/src/qmapboxgl_map_renderer.cpp
@@ -28,7 +28,7 @@ static auto *getScheduler() {
QMapboxGLMapRenderer::QMapboxGLMapRenderer(qreal pixelRatio, QMapboxGLSettings::GLContextMode mode, const QString &localFontFamily)
: m_backend(static_cast<mbgl::gfx::ContextMode>(mode)),
- m_renderer(std::make_unique<mbgl::Renderer>(m_backend, pixelRatio, mbgl::optional<std::string> {},
+ m_renderer(std::make_unique<mbgl::Renderer>(m_backend, pixelRatio,
localFontFamily.isEmpty() ? mbgl::nullopt : mbgl::optional<std::string> { localFontFamily.toStdString() }))
, m_forceScheduler(needsToForceScheduler())
{
diff --git a/platform/qt/src/qmapboxgl_renderer_observer.hpp b/platform/qt/src/qmapboxgl_renderer_observer.hpp
index ee340113ff..78dd6b91d6 100644
--- a/platform/qt/src/qmapboxgl_renderer_observer.hpp
+++ b/platform/qt/src/qmapboxgl_renderer_observer.hpp
@@ -37,8 +37,8 @@ public:
delegate.invoke(&mbgl::RendererObserver::onWillStartRenderingFrame);
}
- void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded) final {
- delegate.invoke(&mbgl::RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded);
+ void onDidFinishRenderingFrame(RenderMode mode, bool repaintNeeded, bool placementChanged) final {
+ delegate.invoke(&mbgl::RendererObserver::onDidFinishRenderingFrame, mode, repaintNeeded, placementChanged);
}
void onDidFinishRenderingMap() final {
diff --git a/render-test/allocation_index.cpp b/render-test/allocation_index.cpp
new file mode 100644
index 0000000000..144c18ddd5
--- /dev/null
+++ b/render-test/allocation_index.cpp
@@ -0,0 +1,101 @@
+#include "allocation_index.hpp"
+
+#include <atomic>
+#include <cassert>
+#include <cstdlib>
+#include <mutex>
+#include <unordered_map>
+
+namespace {
+
+std::atomic_size_t indexedMemorySize{0};
+std::atomic_size_t indexedMemoryPeak{0};
+std::atomic_size_t allocationsCount{0};
+std::unordered_map<void*, size_t> memoryIndex;
+std::atomic_bool suppresIndexing{false};
+std::atomic_bool active{false};
+std::mutex indexMutex;
+
+class FlagGuard {
+public:
+ explicit FlagGuard(std::atomic_bool& flag_)
+ : flag(flag_) { flag = true; }
+ ~FlagGuard() { flag = false; }
+
+private:
+ std::atomic_bool& flag;
+};
+
+void addToIndex(std::size_t sz, void* ptr) {
+ std::lock_guard<std::mutex> mlk(indexMutex);
+ FlagGuard flk(suppresIndexing);
+ allocationsCount++;
+ indexedMemorySize += sz;
+ if (indexedMemoryPeak < indexedMemorySize) indexedMemoryPeak = size_t(indexedMemorySize);
+ memoryIndex[ptr] = sz;
+}
+
+void removeFromIndex(void* ptr) {
+ std::lock_guard<std::mutex> mlk(indexMutex);
+ FlagGuard flk(suppresIndexing);
+ auto it = memoryIndex.find(ptr);
+ if (it == memoryIndex.end()) return;
+
+ assert(indexedMemorySize >= it->second);
+ indexedMemorySize -= it->second;
+ memoryIndex.erase(it);
+}
+
+inline bool canModifyIndex() {
+ return active && !suppresIndexing;
+}
+
+} // namespace
+
+// static
+void AllocationIndex::setActive(bool active_) {
+ active = active_;
+}
+
+// static
+bool AllocationIndex::isActive() {
+ return active;
+}
+
+// static
+void AllocationIndex::reset() {
+ std::lock_guard<std::mutex> mlk(indexMutex);
+ FlagGuard flk(suppresIndexing);
+ memoryIndex.clear();
+ indexedMemorySize = 0;
+ allocationsCount = 0;
+ indexedMemoryPeak = 0;
+}
+
+// static
+void* AllocationIndex::allocate(size_t size) {
+ void *ptr = std::malloc(size);
+ if (ptr && canModifyIndex()) addToIndex(size, ptr);
+ return ptr;
+}
+
+// static
+void AllocationIndex::deallocate(void* ptr) noexcept {
+ if (canModifyIndex()) removeFromIndex(ptr);
+ std::free(ptr);
+}
+
+// static
+size_t AllocationIndex::getAllocatedSize() {
+ return indexedMemorySize;
+}
+
+// static
+size_t AllocationIndex::getAllocationsCount() {
+ return allocationsCount;
+}
+
+// static
+size_t AllocationIndex::getAllocatedSizePeak() {
+ return indexedMemoryPeak;
+}
diff --git a/render-test/allocation_index.hpp b/render-test/allocation_index.hpp
new file mode 100644
index 0000000000..71da441c1f
--- /dev/null
+++ b/render-test/allocation_index.hpp
@@ -0,0 +1,53 @@
+#pragma once
+
+#include <cstddef>
+
+class AllocationIndex {
+public:
+ AllocationIndex() = delete;
+ /**
+ * @brief Starts/stops allocated memory indexing.
+ */
+ static void setActive(bool);
+ /**
+ * @brief Returns memory indexing activity status.
+ */
+ static bool isActive();
+ /**
+ * @brief Resets the allocated memory index and all statistics data.
+ */
+ static void reset();
+ /**
+ * @brief Same as `malloc()` + indexes the allocated data,
+ * if indexing is active.
+ *
+ * @return void*
+ */
+ static void* allocate(size_t);
+ /**
+ * @brief Same as `free()` + removes the corresponding data from index,
+ * if these data are present in the index and indexing is active.
+ *
+ * @return void*
+ */
+ static void deallocate(void*) noexcept;
+ /**
+ * @brief Returns the size (in bytes) of allocated data, currently present in the index.
+ *
+ * @return size_t
+ */
+ static size_t getAllocatedSize();
+ /**
+ * @brief Returns the total amount of allocations since indexing start.
+ *
+ * @return size_t
+ */
+ static size_t getAllocationsCount();
+
+ /**
+ * @brief Returns the maximum size (in bytes) of the allocated data in the index, since last `reset()` call.
+ *
+ * @return size_t
+ */
+ static size_t getAllocatedSizePeak();
+};
diff --git a/render-test/expected/debug/collision-lines-overscaled/expected.png b/render-test/expected/debug/collision-lines-overscaled/expected.png
new file mode 100644
index 0000000000..38eb0d2da6
--- /dev/null
+++ b/render-test/expected/debug/collision-lines-overscaled/expected.png
Binary files differ
diff --git a/render-test/expected/debug/collision-lines-pitched/expected.png b/render-test/expected/debug/collision-lines-pitched/expected.png
new file mode 100644
index 0000000000..416d7d5715
--- /dev/null
+++ b/render-test/expected/debug/collision-lines-pitched/expected.png
Binary files differ
diff --git a/render-test/expected/debug/collision-lines/expected.png b/render-test/expected/debug/collision-lines/expected.png
new file mode 100644
index 0000000000..3f4790a585
--- /dev/null
+++ b/render-test/expected/debug/collision-lines/expected.png
Binary files differ
diff --git a/render-test/expected/debug/collision-pitched-wrapped/expected.png b/render-test/expected/debug/collision-pitched-wrapped/expected.png
new file mode 100644
index 0000000000..9b718c09c0
--- /dev/null
+++ b/render-test/expected/debug/collision-pitched-wrapped/expected.png
Binary files differ
diff --git a/render-test/expected/symbol-visibility/visible/expected.png b/render-test/expected/symbol-visibility/visible/expected.png
new file mode 100644
index 0000000000..8da157772a
--- /dev/null
+++ b/render-test/expected/symbol-visibility/visible/expected.png
Binary files differ
diff --git a/render-test/expected/text-pitch-alignment/auto-text-rotation-alignment-map/expected.png b/render-test/expected/text-pitch-alignment/auto-text-rotation-alignment-map/expected.png
new file mode 100644
index 0000000000..cd690ca152
--- /dev/null
+++ b/render-test/expected/text-pitch-alignment/auto-text-rotation-alignment-map/expected.png
Binary files differ
diff --git a/render-test/expected/text-pitch-alignment/map-text-rotation-alignment-map/expected.png b/render-test/expected/text-pitch-alignment/map-text-rotation-alignment-map/expected.png
new file mode 100644
index 0000000000..cd690ca152
--- /dev/null
+++ b/render-test/expected/text-pitch-alignment/map-text-rotation-alignment-map/expected.png
Binary files differ
diff --git a/render-test/expected/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.png b/render-test/expected/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.png
new file mode 100644
index 0000000000..764d4a0b24
--- /dev/null
+++ b/render-test/expected/text-pitch-alignment/viewport-text-rotation-alignment-map/expected.png
Binary files differ
diff --git a/render-test/main.cpp b/render-test/main.cpp
index ef9352d21d..3ab48fe5b2 100644
--- a/render-test/main.cpp
+++ b/render-test/main.cpp
@@ -1,13 +1,13 @@
+#include "allocation_index.hpp"
+
#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/io.hpp>
-#include "filesystem.hpp"
#include "metadata.hpp"
#include "parser.hpp"
#include "runner.hpp"
#include <random>
-#include <regex>
#define ANSI_COLOR_RED "\x1b[31m"
#define ANSI_COLOR_GREEN "\x1b[32m"
@@ -19,49 +19,33 @@
#define ANSI_COLOR_LIGHT_GRAY "\x1b[90m"
#define ANSI_COLOR_RESET "\x1b[0m"
-namespace {
-
-TestPaths makeTestPaths(mbgl::filesystem::path stylePath) {
- std::vector<mbgl::filesystem::path> expectations{ stylePath };
- expectations.front().remove_filename();
+void* operator new(std::size_t sz) {
+ void* ptr = AllocationIndex::allocate(sz);
+ if (!ptr) throw std::bad_alloc{};
- const static std::regex regex{ TestRunner::getBasePath() };
- for (const std::string& path : TestRunner::getPlatformExpectationsPaths()) {
- expectations.emplace_back(std::regex_replace(expectations.front().string(), regex, path));
- assert(!expectations.back().empty());
- }
+ return ptr;
+}
- return {
- std::move(stylePath),
- std::move(expectations)
- };
+void operator delete(void* ptr) noexcept {
+ AllocationIndex::deallocate(ptr);
}
-} // namespace
+void operator delete(void* ptr, size_t) noexcept {
+ AllocationIndex::deallocate(ptr);
+}
int main(int argc, char** argv) {
bool recycleMap;
bool shuffle;
uint32_t seed;
std::string testRootPath;
- std::vector<std::string> ids;
+ std::vector<TestPaths> testPaths;
- std::tie(recycleMap, shuffle, seed, testRootPath, ids) = parseArguments(argc, argv);
+ std::tie(recycleMap, shuffle, seed, testRootPath, testPaths) = parseArguments(argc, argv);
const std::string::size_type rootLength = testRootPath.length();
const auto ignores = parseIgnores();
- // Recursively traverse through the test paths and collect test directories containing "style.json".
- std::vector<TestPaths> testPaths;
- testPaths.reserve(ids.size());
- for (const auto& id : ids) {
- for (auto& testPath : mbgl::filesystem::recursive_directory_iterator(mbgl::filesystem::path(id))) {
- if (testPath.path().filename() == "style.json") {
- testPaths.emplace_back(makeTestPaths(testPath));
- }
- }
- }
-
if (shuffle) {
printf(ANSI_COLOR_YELLOW "Shuffle seed: %d" ANSI_COLOR_RESET "\n", seed);
@@ -108,7 +92,7 @@ int main(int argc, char** argv) {
bool errored = !metadata.errorMessage.empty();
if (!errored) {
- errored = runner.run(metadata) && !metadata.errorMessage.empty();
+ errored = !runner.run(metadata) || !metadata.errorMessage.empty();
}
bool passed = !errored && !metadata.diff.empty() && metadata.difference <= metadata.allowed;
diff --git a/render-test/metadata.hpp b/render-test/metadata.hpp
index 98e208fe54..d23a0fb296 100644
--- a/render-test/metadata.hpp
+++ b/render-test/metadata.hpp
@@ -7,6 +7,8 @@
#include "filesystem.hpp"
+#include <map>
+
struct TestStatistics {
TestStatistics() = default;
@@ -27,6 +29,22 @@ struct TestPaths {
}
};
+struct MemoryProbe {
+ MemoryProbe() = default;
+ MemoryProbe(size_t peak_, size_t allocations_)
+ : peak(peak_)
+ , allocations(allocations_) {}
+
+ size_t peak;
+ size_t allocations;
+};
+
+class TestMetrics {
+public:
+ bool isEmpty() const { return memory.empty(); }
+ std::map<std::string, MemoryProbe> memory;
+};
+
struct TestMetadata {
TestMetadata() = default;
@@ -59,4 +77,7 @@ struct TestMetadata {
std::string errorMessage;
double difference = 0.0;
-}; \ No newline at end of file
+
+ TestMetrics metrics;
+ TestMetrics expectedMetrics;
+};
diff --git a/render-test/parser.cpp b/render-test/parser.cpp
index 49f084465c..9b462dee72 100644
--- a/render-test/parser.cpp
+++ b/render-test/parser.cpp
@@ -13,8 +13,9 @@
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/ostream_iterator.hpp>
-#include "parser.hpp"
+#include "filesystem.hpp"
#include "metadata.hpp"
+#include "parser.hpp"
#include "runner.hpp"
#include <sstream>
@@ -162,6 +163,22 @@ mbgl::optional<std::string> localizeMapboxTilesetURL(const std::string& url) {
return getIntegrationPath(url, "tilesets/", regex);
}
+TestPaths makeTestPaths(mbgl::filesystem::path stylePath) {
+ std::vector<mbgl::filesystem::path> expectations{ stylePath };
+ expectations.front().remove_filename();
+
+ const static std::regex regex{ TestRunner::getBasePath() };
+ for (const std::string& path : TestRunner::getPlatformExpectationsPaths()) {
+ expectations.emplace_back(std::regex_replace(expectations.front().string(), regex, path));
+ assert(!expectations.back().empty());
+ }
+
+ return {
+ std::move(stylePath),
+ std::move(expectations)
+ };
+}
+
} // namespace
JSONReply readJson(const mbgl::filesystem::path& jsonPath) {
@@ -187,6 +204,29 @@ std::string serializeJsonValue(const mbgl::JSValue& value) {
return buffer.GetString();
}
+std::string serializeMetrics(const TestMetrics& metrics) {
+ rapidjson::StringBuffer s;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(s);
+
+ writer.StartObject();
+ // Start memory section.
+ writer.Key("memory");
+ writer.StartArray();
+ for (const auto& memoryProbe : metrics.memory) {
+ assert(!memoryProbe.first.empty());
+ writer.StartArray();
+ writer.String(memoryProbe.first.c_str());
+ writer.Uint64(memoryProbe.second.peak);
+ writer.Uint64(memoryProbe.second.allocations);
+ writer.EndArray();
+ }
+ // End memory section.
+ writer.EndArray();
+ writer.EndObject();
+
+ return s.GetString();
+}
+
std::vector<std::string> readExpectedEntries(const mbgl::filesystem::path& base) {
static const std::regex regex(".*expected.*.png");
@@ -216,6 +256,8 @@ ArgumentsTuple parseArguments(int argc, char** argv) {
{ "seed" });
args::ValueFlag<std::string> testPathValue(argumentParser, "rootPath", "Test root rootPath",
{ 'p', "rootPath" });
+ args::ValueFlag<std::regex> testFilterValue(argumentParser, "filter", "Test filter regex",
+ { 'f', "filter" });
args::PositionalList<std::string> testNameValues(argumentParser, "URL", "Test name(s)");
try {
@@ -237,25 +279,50 @@ ArgumentsTuple parseArguments(int argc, char** argv) {
mbgl::Log::Info(mbgl::Event::General, stream.str());
mbgl::Log::Error(mbgl::Event::General, e.what());
exit(2);
+ } catch (const std::regex_error& e) {
+ mbgl::Log::Error(mbgl::Event::General, "Invalid filter regular expression: %s", e.what());
+ exit(3);
}
- const std::string testDefaultPath =
- std::string(TEST_RUNNER_ROOT_PATH).append("/mapbox-gl-js/test/integration/render-tests");
+ mbgl::filesystem::path rootPath {testPathValue ? args::get(testPathValue) : TestRunner::getBasePath()};
+ if (!mbgl::filesystem::exists(rootPath)) {
+ mbgl::Log::Error(mbgl::Event::General, "Provided rootPath '%s' does not exist.", rootPath.string().c_str());
+ exit(4);
+ }
- std::vector<std::string> ids;
+ std::vector<mbgl::filesystem::path> paths;
for (const auto& id : args::get(testNameValues)) {
- ids.emplace_back(TestRunner::getBasePath() + "/" + id);
+ paths.emplace_back(TestRunner::getBasePath() + "/" + id);
}
- if (ids.empty()) {
- ids.emplace_back(TestRunner::getBasePath());
+ if (paths.empty()) {
+ paths.emplace_back(TestRunner::getBasePath());
+ }
+
+ // Recursively traverse through the test paths and collect test directories containing "style.json".
+ std::vector<TestPaths> testPaths;
+ testPaths.reserve(paths.size());
+ for (const auto& path : paths) {
+ if (!mbgl::filesystem::exists(path)) {
+ mbgl::Log::Warning(mbgl::Event::General, "Provided test folder '%s' does not exist.", path.string().c_str());
+ continue;
+ }
+ for (auto& testPath : mbgl::filesystem::recursive_directory_iterator(path)) {
+ // Skip paths that fail regexp match.
+ if (testFilterValue && !std::regex_match(testPath.path().string(), args::get(testFilterValue))) {
+ continue;
+ }
+ if (testPath.path().filename() == "style.json") {
+ testPaths.emplace_back(makeTestPaths(testPath));
+ }
+ }
}
return ArgumentsTuple {
recycleMapFlag ? args::get(recycleMapFlag) : false,
shuffleFlag ? args::get(shuffleFlag) : false, seedValue ? args::get(seedValue) : 1u,
- testPathValue ? args::get(testPathValue) : testDefaultPath,
- std::move(ids)
+ testPathValue ? args::get(testPathValue) : TestRunner::getBasePath(),
+ std::move(testPaths)
};
}
@@ -290,6 +357,36 @@ std::vector<std::pair<std::string, std::string>> parseIgnores() {
return ignores;
}
+TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path) {
+ TestMetrics result;
+
+ auto maybeJson = readJson(path.string());
+ if (!maybeJson.is<mbgl::JSDocument>()) { // NOLINT
+ return result;
+ }
+
+ const auto& document = maybeJson.get<mbgl::JSDocument>();
+ if (document.HasMember("memory")) {
+ const mbgl::JSValue& memoryValue = document["memory"];
+ assert(memoryValue.IsArray());
+ for (auto& probeValue : memoryValue.GetArray()) {
+ assert(probeValue.IsArray());
+ assert(probeValue.Size() >= 3u);
+ assert(probeValue[0].IsString());
+ assert(probeValue[1].IsNumber());
+ assert(probeValue[2].IsNumber());
+
+ const std::string mark { probeValue[0].GetString(), probeValue[0].GetStringLength() };
+ assert(!mark.empty());
+ result.memory.emplace(std::piecewise_construct,
+ std::forward_as_tuple(std::move(mark)),
+ std::forward_as_tuple(probeValue[1].GetUint64(), probeValue[2].GetUint64()));
+ }
+ }
+
+ return result;
+}
+
TestMetadata parseTestMetadata(const TestPaths& paths) {
TestMetadata metadata;
metadata.paths = paths;
diff --git a/render-test/parser.hpp b/render-test/parser.hpp
index 3e69968152..94fb212944 100644
--- a/render-test/parser.hpp
+++ b/render-test/parser.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include "metadata.hpp"
+
#include <mbgl/util/rapidjson.hpp>
#include <mbgl/util/variant.hpp>
@@ -7,22 +9,19 @@
#include <string>
#include <vector>
-#include "filesystem.hpp"
-
-struct TestMetadata;
-struct TestStatistics;
-struct TestPaths;
-
using ErrorMessage = std::string;
using JSONReply = mbgl::variant<mbgl::JSDocument, ErrorMessage>;
-using ArgumentsTuple = std::tuple<bool, bool, uint32_t, std::string, std::vector<std::string>>;
+using ArgumentsTuple = std::tuple<bool, bool, uint32_t, std::string, std::vector<TestPaths>>;
JSONReply readJson(const mbgl::filesystem::path&);
std::string serializeJsonValue(const mbgl::JSValue&);
+std::string serializeMetrics(const TestMetrics&);
std::vector<std::string> readExpectedEntries(const mbgl::filesystem::path& base);
+TestMetrics readExpectedMetrics(const mbgl::filesystem::path& path);
+
ArgumentsTuple parseArguments(int argc, char** argv);
std::vector<std::pair<std::string, std::string>> parseIgnores();
diff --git a/render-test/runner.cpp b/render-test/runner.cpp
index 192978ffa5..54660979cf 100644
--- a/render-test/runner.cpp
+++ b/render-test/runner.cpp
@@ -18,6 +18,7 @@
#include <mapbox/pixelmatch.hpp>
+#include "allocation_index.hpp"
#include "metadata.hpp"
#include "parser.hpp"
#include "runner.hpp"
@@ -25,7 +26,8 @@
#include <algorithm>
#include <cassert>
#include <regex>
-
+#include <utility>
+#include <sstream>
// static
const std::string& TestRunner::getBasePath() {
@@ -43,13 +45,13 @@ const std::vector<std::string>& TestRunner::getPlatformExpectationsPaths() {
return result;
}
-bool TestRunner::checkImage(mbgl::PremultipliedImage&& actual, TestMetadata& metadata) {
+bool TestRunner::checkResults(mbgl::PremultipliedImage&& actualImage, TestMetadata& metadata) {
const std::string& base = metadata.paths.defaultExpectations();
const std::vector<mbgl::filesystem::path>& expectations = metadata.paths.expectations;
- metadata.actual = mbgl::encodePNG(actual);
+ metadata.actual = mbgl::encodePNG(actualImage);
- if (actual.size.isEmpty()) {
+ if (actualImage.size.isEmpty()) {
metadata.errorMessage = "Invalid size for actual image";
return false;
}
@@ -57,34 +59,46 @@ bool TestRunner::checkImage(mbgl::PremultipliedImage&& actual, TestMetadata& met
#if !TEST_READ_ONLY
if (getenv("UPDATE_PLATFORM")) {
mbgl::filesystem::create_directories(expectations.back());
- mbgl::util::write_file(expectations.back().string() + "/expected.png", mbgl::encodePNG(actual));
+ mbgl::util::write_file(expectations.back().string() + "/expected.png", mbgl::encodePNG(actualImage));
return true;
} else if (getenv("UPDATE_DEFAULT")) {
- mbgl::util::write_file(base + "/expected.png", mbgl::encodePNG(actual));
+ mbgl::util::write_file(base + "/expected.png", mbgl::encodePNG(actualImage));
return true;
+ } else if (getenv("UPDATE_METRICS")) {
+ if (!metadata.metrics.isEmpty()) {
+ mbgl::filesystem::create_directories(expectations.back());
+ mbgl::util::write_file(expectations.back().string() + "/metrics.json", serializeMetrics(metadata.metrics));
+ return true;
+ }
}
mbgl::util::write_file(base + "/actual.png", metadata.actual);
#endif
- mbgl::PremultipliedImage expected { actual.size };
- mbgl::PremultipliedImage diff { actual.size };
+ mbgl::PremultipliedImage expectedImage { actualImage.size };
+ mbgl::PremultipliedImage imageDiff { actualImage.size };
double pixels = 0.0;
- mbgl::filesystem::path expectedPath;
+ std::vector<std::string> expectedImagesPaths;
+ mbgl::filesystem::path expectedMetricsPath;
for (auto rit = expectations.rbegin(); rit!= expectations.rend(); ++rit) {
if (mbgl::filesystem::exists(*rit)) {
- expectedPath = *rit;
- break;
+ if (metadata.expectedMetrics.isEmpty()) {
+ mbgl::filesystem::path maybeExpectedMetricsPath{ *rit };
+ maybeExpectedMetricsPath.replace_filename("metrics.json");
+ metadata.expectedMetrics = readExpectedMetrics(maybeExpectedMetricsPath);
+ }
+ expectedImagesPaths = readExpectedEntries(*rit);
+ if (!expectedImagesPaths.empty()) break;
}
}
- if (expectedPath.empty()) {
+ if (expectedImagesPaths.empty()) {
metadata.errorMessage = "Failed to find expectations for: " + metadata.paths.stylePath.string();
return false;
}
- for (const auto& entry: readExpectedEntries(expectedPath)) {
+ for (const auto& entry: expectedImagesPaths) {
mbgl::optional<std::string> maybeExpectedImage = mbgl::util::readFile(entry);
if (!maybeExpectedImage) {
metadata.errorMessage = "Failed to load expected image " + entry;
@@ -93,23 +107,48 @@ bool TestRunner::checkImage(mbgl::PremultipliedImage&& actual, TestMetadata& met
metadata.expected = *maybeExpectedImage;
- expected = mbgl::decodeImage(*maybeExpectedImage);
+ expectedImage = mbgl::decodeImage(*maybeExpectedImage);
pixels = // implicitly converting from uint64_t
- mapbox::pixelmatch(actual.data.get(), expected.data.get(), expected.size.width,
- expected.size.height, diff.data.get(), 0.1285); // Defined in GL JS
+ mapbox::pixelmatch(actualImage.data.get(), expectedImage.data.get(), expectedImage.size.width,
+ expectedImage.size.height, imageDiff.data.get(), 0.1285); // Defined in GL JS
- metadata.diff = mbgl::encodePNG(diff);
+ metadata.diff = mbgl::encodePNG(imageDiff);
#if !TEST_READ_ONLY
mbgl::util::write_file(base + "/diff.png", metadata.diff);
#endif
- metadata.difference = pixels / expected.size.area();
+ metadata.difference = pixels / expectedImage.size.area();
if (metadata.difference <= metadata.allowed) {
break;
}
}
+ // Check memory metrics.
+ for (const auto& expected : metadata.expectedMetrics.memory) {
+ auto actual = metadata.metrics.memory.find(expected.first);
+ if (actual == metadata.metrics.memory.end()) {
+ metadata.errorMessage = "Failed to find memory probe: " + expected.first;
+ return false;
+ }
+ if (actual->second.peak > expected.second.peak) {
+ std::stringstream ss;
+ ss << "Allocated memory peak size at probe \"" << expected.first << "\" is "
+ << actual->second.peak << " bytes, expected is " << expected.second.peak << " bytes.";
+
+ metadata.errorMessage = ss.str();
+ return false;
+ }
+
+ if (actual->second.allocations > expected.second.allocations) {
+ std::stringstream ss;
+ ss << "Number of allocations at probe \"" << expected.first << "\" is "
+ << actual->second.allocations << ", expected is " << expected.second.allocations << ".";
+
+ metadata.errorMessage = ss.str();
+ return false;
+ }
+ }
return true;
}
@@ -155,6 +194,9 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) {
static const std::string removeSourceOp("removeSource");
static const std::string setPaintPropertyOp("setPaintProperty");
static const std::string setLayoutPropertyOp("setLayoutProperty");
+ static const std::string memoryProbeOp("probeMemory");
+ static const std::string memoryProbeStartOp("probeMemoryStart");
+ static const std::string memoryProbeEndOp("probeMemoryEnd");
// wait
if (operationArray[0].GetString() == waitOp) {
@@ -392,7 +434,25 @@ bool TestRunner::runOperations(const std::string& key, TestMetadata& metadata) {
const mbgl::JSValue* propertyValue = &operationArray[3];
layer->setLayoutProperty(propertyName, propertyValue);
}
-
+ // probeMemoryStart
+ } else if (operationArray[0].GetString() == memoryProbeStartOp) {
+ assert(!AllocationIndex::isActive());
+ AllocationIndex::setActive(true);
+ // probeMemory
+ } else if (operationArray[0].GetString() == memoryProbeOp) {
+ assert(AllocationIndex::isActive());
+ assert(operationArray.Size() >= 2u);
+ assert(operationArray[1].IsString());
+ std::string mark = std::string(operationArray[1].GetString(), operationArray[1].GetStringLength());
+
+ metadata.metrics.memory.emplace(std::piecewise_construct,
+ std::forward_as_tuple(std::move(mark)),
+ std::forward_as_tuple(AllocationIndex::getAllocatedSizePeak(), AllocationIndex::getAllocationsCount()));
+ // probeMemoryEnd
+ } else if (operationArray[0].GetString() == memoryProbeEndOp) {
+ assert(AllocationIndex::isActive());
+ AllocationIndex::setActive(false);
+ AllocationIndex::reset();
} else {
metadata.errorMessage = std::string("Unsupported operation: ") + operationArray[0].GetString();
return false;
@@ -414,6 +474,8 @@ TestRunner::Impl::Impl(const TestMetadata& metadata)
mbgl::ResourceOptions().withCacheOnlyRequestsSupport(false)) {}
bool TestRunner::run(TestMetadata& metadata) {
+ AllocationIndex::setActive(false);
+ AllocationIndex::reset();
std::string key = mbgl::util::toString(uint32_t(metadata.mapMode))
+ "/" + mbgl::util::toString(metadata.pixelRatio)
+ "/" + mbgl::util::toString(uint32_t(metadata.crossSourceCollisions));
@@ -445,7 +507,7 @@ bool TestRunner::run(TestMetadata& metadata) {
return false;
}
- return checkImage(std::move(image), metadata);
+ return checkResults(std::move(image), metadata);
}
void TestRunner::reset() {
diff --git a/render-test/runner.hpp b/render-test/runner.hpp
index 74cc03ba03..fdea65e104 100644
--- a/render-test/runner.hpp
+++ b/render-test/runner.hpp
@@ -21,7 +21,7 @@ public:
private:
bool runOperations(const std::string& key, TestMetadata&);
- bool checkImage(mbgl::PremultipliedImage&& image, TestMetadata&);
+ bool checkResults(mbgl::PremultipliedImage&& image, TestMetadata&);
struct Impl {
Impl(const TestMetadata&);
diff --git a/src/mbgl/layout/symbol_instance.cpp b/src/mbgl/layout/symbol_instance.cpp
index 8be025afe1..ad36e6c38c 100644
--- a/src/mbgl/layout/symbol_instance.cpp
+++ b/src/mbgl/layout/symbol_instance.cpp
@@ -88,12 +88,11 @@ SymbolInstance::SymbolInstance(Anchor& anchor_,
const float iconRotation,
const float textRotation,
float radialTextOffset_,
- bool allowVerticalPlacement) :
+ bool allowVerticalPlacement,
+ const SymbolContent iconType) :
sharedData(std::move(sharedData_)),
anchor(anchor_),
- // 'hasText' depends on finding at least one glyph in the shaping that's also in the GlyphPositionMap
- hasText(!sharedData->empty()),
- hasIcon(shapedIcon),
+ symbolContent(iconType),
// Create the collision features that will be used to check whether this symbol instance can be placed
// As a collision approximation, we can use either the vertical or any of the horizontal versions of the feature
textCollisionFeature(sharedData->line, anchor, getAnyShaping(shapedTextOrientations), textBoxScale_, textPadding, textPlacement, indexedFeature, overscaling, textRotation),
@@ -107,7 +106,8 @@ SymbolInstance::SymbolInstance(Anchor& anchor_,
textBoxScale(textBoxScale_),
radialTextOffset(radialTextOffset_),
singleLine(shapedTextOrientations.singleLine) {
-
+ // 'hasText' depends on finding at least one glyph in the shaping that's also in the GlyphPositionMap
+ if(!sharedData->empty()) symbolContent |= SymbolContent::Text;
if (allowVerticalPlacement && shapedTextOrientations.vertical) {
const float verticalPointLabelAngle = 90.0f;
verticalTextCollisionFeature = CollisionFeature(line(), anchor, shapedTextOrientations.vertical, textBoxScale_, textPadding, textPlacement, indexedFeature, overscaling, textRotation + verticalPointLabelAngle);
@@ -164,6 +164,18 @@ const optional<SymbolQuad>& SymbolInstance::iconQuad() const {
assert(sharedData);
return sharedData->iconQuad;
}
+
+bool SymbolInstance::hasText() const {
+ return static_cast<bool>(symbolContent & SymbolContent::Text);
+}
+
+bool SymbolInstance::hasIcon() const {
+ return static_cast<bool>(symbolContent & SymbolContent::IconRGBA) || hasSdfIcon();
+}
+
+bool SymbolInstance::hasSdfIcon() const {
+ return static_cast<bool>(symbolContent & SymbolContent::IconSDF);
+}
const optional<SymbolQuad>& SymbolInstance::verticalIconQuad() const {
assert(sharedData);
diff --git a/src/mbgl/layout/symbol_instance.hpp b/src/mbgl/layout/symbol_instance.hpp
index 60883c12db..7d002d2285 100644
--- a/src/mbgl/layout/symbol_instance.hpp
+++ b/src/mbgl/layout/symbol_instance.hpp
@@ -4,7 +4,8 @@
#include <mbgl/text/glyph_atlas.hpp>
#include <mbgl/text/collision_feature.hpp>
#include <mbgl/style/layers/symbol_layer_properties.hpp>
-
+#include <mbgl/util/traits.hpp>
+#include <mbgl/util/util.hpp>
namespace mbgl {
@@ -42,6 +43,25 @@ struct SymbolInstanceSharedData {
optional<SymbolQuad> verticalIconQuad;
};
+enum class SymbolContent : uint8_t {
+ None = 0,
+ Text = 1 << 0,
+ IconRGBA = 1 << 1,
+ IconSDF = 1 << 2
+};
+
+MBGL_CONSTEXPR SymbolContent operator|(SymbolContent a, SymbolContent b) {
+ return SymbolContent(mbgl::underlying_type(a) | mbgl::underlying_type(b));
+}
+
+MBGL_CONSTEXPR SymbolContent& operator|=(SymbolContent& a, SymbolContent b) {
+ return (a = a | b);
+}
+
+MBGL_CONSTEXPR SymbolContent operator&(SymbolContent a, SymbolContent b) {
+ return SymbolContent(mbgl::underlying_type(a) & mbgl::underlying_type(b));
+}
+
class SymbolInstance {
public:
SymbolInstance(Anchor& anchor_,
@@ -64,7 +84,8 @@ public:
const float iconRotation,
const float textRotation,
float radialTextOffset,
- bool allowVerticalPlacement);
+ bool allowVerticalPlacement,
+ const SymbolContent iconType = SymbolContent::None);
optional<size_t> getDefaultHorizontalPlacedTextIndex() const;
const GeometryCoordinates& line() const;
@@ -72,6 +93,9 @@ public:
const SymbolQuads& leftJustifiedGlyphQuads() const;
const SymbolQuads& centerJustifiedGlyphQuads() const;
const SymbolQuads& verticalGlyphQuads() const;
+ bool hasText() const;
+ bool hasIcon() const;
+ bool hasSdfIcon() const;
const optional<SymbolQuad>& iconQuad() const;
const optional<SymbolQuad>& verticalIconQuad() const;
void releaseSharedData();
@@ -81,8 +105,7 @@ private:
public:
Anchor anchor;
- bool hasText;
- bool hasIcon;
+ SymbolContent symbolContent;
std::size_t rightJustifiedGlyphQuadsSize;
std::size_t centerJustifiedGlyphQuadsSize;
diff --git a/src/mbgl/layout/symbol_layout.cpp b/src/mbgl/layout/symbol_layout.cpp
index 6a13bb22ae..fe169785ce 100644
--- a/src/mbgl/layout/symbol_layout.cpp
+++ b/src/mbgl/layout/symbol_layout.cpp
@@ -398,16 +398,18 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
}
// if feature has icon, get sprite atlas position
+ SymbolContent iconType{SymbolContent::None};
if (feature.icon) {
auto image = imageMap.find(*feature.icon);
if (image != imageMap.end()) {
+ iconType = SymbolContent::IconRGBA;
shapedIcon = PositionedIcon::shapeIcon(
imagePositions.at(*feature.icon),
layout->evaluate<IconOffset>(zoom, feature),
layout->evaluate<IconAnchor>(zoom, feature),
layout->evaluate<IconRotate>(zoom, feature) * util::DEG2RAD);
if (image->second->sdf) {
- sdfIcons = true;
+ iconType = SymbolContent::IconSDF;
}
if (image->second->pixelRatio != pixelRatio) {
iconsNeedLinear = true;
@@ -419,7 +421,7 @@ void SymbolLayout::prepareSymbols(const GlyphMap& glyphMap, const GlyphPositions
// if either shapedText or icon position is present, add the feature
if (getDefaultHorizontalShaping(shapedTextOrientations) || shapedIcon) {
- addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, std::move(shapedIcon), glyphPositions, textOffset);
+ addFeature(std::distance(features.begin(), it), feature, shapedTextOrientations, std::move(shapedIcon), glyphPositions, textOffset, iconType);
}
feature.geometry.clear();
@@ -433,7 +435,8 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
const ShapedTextOrientations& shapedTextOrientations,
optional<PositionedIcon> shapedIcon,
const GlyphPositions& glyphPositions,
- Point<float> offset) {
+ Point<float> offset,
+ const SymbolContent iconType) {
const float minScale = 0.5f;
const float glyphSize = 24.0f;
@@ -500,7 +503,7 @@ void SymbolLayout::addFeature(const std::size_t layoutFeatureIndex,
iconBoxScale, iconPadding, iconOffset, indexedFeature,
layoutFeatureIndex, feature.index,
feature.formattedText ? feature.formattedText->rawText() : std::u16string(),
- overscaling, iconRotation, textRotation, radialTextOffset, allowVerticalPlacement);
+ overscaling, iconRotation, textRotation, radialTextOffset, allowVerticalPlacement, iconType);
}
};
@@ -620,14 +623,14 @@ std::vector<float> CalculateTileDistances(const GeometryCoordinates& line, const
}
void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIndex>&, std::unordered_map<std::string, LayerRenderData>& renderData, const bool firstLoad, const bool showCollisionBoxes) {
- auto bucket = std::make_shared<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, sdfIcons, iconsNeedLinear,
+ auto bucket = std::make_shared<SymbolBucket>(layout, layerPaintProperties, textSize, iconSize, zoom, iconsNeedLinear,
sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), tilePixelRatio,
allowVerticalPlacement,
std::move(placementModes));
for (SymbolInstance &symbolInstance : bucket->symbolInstances) {
- const bool hasText = symbolInstance.hasText;
- const bool hasIcon = symbolInstance.hasIcon;
+ const bool hasText = symbolInstance.hasText();
+ const bool hasIcon = symbolInstance.hasIcon();
const bool singleLine = symbolInstance.singleLine;
const auto& feature = features.at(symbolInstance.layoutFeatureIndex);
@@ -637,26 +640,25 @@ void SymbolLayout::createBucket(const ImagePositions&, std::unique_ptr<FeatureIn
// Process icon first, so that text symbols would have reference to iconIndex which
// is used when dynamic vertices for icon-text-fit image have to be updated.
if (hasIcon) {
- if (symbolInstance.hasIcon) {
- const Range<float> sizeData = bucket->iconSizeBinder->getVertexSizeData(feature);
- const auto placeIcon = [&] (const SymbolQuad& iconQuad, auto& index, const WritingModeType writingMode) {
- bucket->icon.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
- symbolInstance.iconOffset, writingMode, symbolInstance.line(), std::vector<float>());
- index = bucket->icon.placedSymbols.size() - 1;
- PlacedSymbol& iconSymbol = bucket->icon.placedSymbols.back();
- iconSymbol.angle = (allowVerticalPlacement && writingMode == WritingModeType::Vertical) ? M_PI_2 : 0;
- iconSymbol.vertexStartIndex = addSymbol(bucket->icon, sizeData, iconQuad,
- symbolInstance.anchor, iconSymbol, feature.sortKey);
- };
-
- placeIcon(*symbolInstance.iconQuad(), symbolInstance.placedIconIndex, WritingModeType::None);
- if (symbolInstance.verticalIconQuad()) {
- placeIcon(*symbolInstance.verticalIconQuad(), symbolInstance.placedVerticalIconIndex, WritingModeType::Vertical);
- }
+ const Range<float> sizeData = bucket->iconSizeBinder->getVertexSizeData(feature);
+ auto& iconBuffer = symbolInstance.hasSdfIcon() ? bucket->sdfIcon : bucket->icon;
+ const auto placeIcon = [&] (const SymbolQuad& iconQuad, auto& index, const WritingModeType writingMode) {
+ iconBuffer.placedSymbols.emplace_back(symbolInstance.anchor.point, symbolInstance.anchor.segment, sizeData.min, sizeData.max,
+ symbolInstance.iconOffset, writingMode, symbolInstance.line(), std::vector<float>());
+ index = iconBuffer.placedSymbols.size() - 1;
+ PlacedSymbol& iconSymbol = iconBuffer.placedSymbols.back();
+ iconSymbol.angle = (allowVerticalPlacement && writingMode == WritingModeType::Vertical) ? M_PI_2 : 0;
+ iconSymbol.vertexStartIndex = addSymbol(iconBuffer, sizeData, iconQuad,
+ symbolInstance.anchor, iconSymbol, feature.sortKey);
+ };
- for (auto& pair : bucket->paintProperties) {
- pair.second.iconBinders.populateVertexVectors(feature, bucket->icon.vertices.elements(), {}, {});
- }
+ placeIcon(*symbolInstance.iconQuad(), symbolInstance.placedIconIndex, WritingModeType::None);
+ if (symbolInstance.verticalIconQuad()) {
+ placeIcon(*symbolInstance.verticalIconQuad(), symbolInstance.placedVerticalIconIndex, WritingModeType::Vertical);
+ }
+
+ for (auto& pair : bucket->paintProperties) {
+ pair.second.iconBinders.populateVertexVectors(feature, iconBuffer.vertices.elements(), {}, {});
}
}
diff --git a/src/mbgl/layout/symbol_layout.hpp b/src/mbgl/layout/symbol_layout.hpp
index 6cc21c6d91..8d4c51148a 100644
--- a/src/mbgl/layout/symbol_layout.hpp
+++ b/src/mbgl/layout/symbol_layout.hpp
@@ -53,7 +53,8 @@ private:
const ShapedTextOrientations& shapedTextOrientations,
optional<PositionedIcon> shapedIcon,
const GlyphPositions&,
- Point<float> textOffset);
+ Point<float> textOffset,
+ const SymbolContent iconType);
bool anchorIsTooClose(const std::u16string& text, const float repeatDistance, const Anchor&);
std::map<std::u16string, std::vector<Anchor>> compareText;
@@ -93,7 +94,6 @@ private:
const uint32_t tileSize;
const float tilePixelRatio;
- bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
bool allowVerticalPlacement = false;
diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp
index c35f33305c..649e0e321e 100644
--- a/src/mbgl/map/map.cpp
+++ b/src/mbgl/map/map.cpp
@@ -124,7 +124,7 @@ bool Map::isPanning() const {
#pragma mark -
-CameraOptions Map::getCameraOptions(const EdgeInsets& padding) const {
+CameraOptions Map::getCameraOptions(optional<EdgeInsets> padding) const {
return impl->transform.getCameraOptions(padding);
}
diff --git a/src/mbgl/map/map_impl.cpp b/src/mbgl/map/map_impl.cpp
index ce36583ab3..ea55dfd1a8 100644
--- a/src/mbgl/map/map_impl.cpp
+++ b/src/mbgl/map/map_impl.cpp
@@ -130,11 +130,11 @@ void Map::Impl::onWillStartRenderingFrame() {
}
}
-void Map::Impl::onDidFinishRenderingFrame(RenderMode renderMode, bool needsRepaint) {
+void Map::Impl::onDidFinishRenderingFrame(RenderMode renderMode, bool needsRepaint, bool placemenChanged) {
rendererFullyLoaded = renderMode == RenderMode::Full;
if (mode == MapMode::Continuous) {
- observer.onDidFinishRenderingFrame(MapObserver::RenderMode(renderMode));
+ observer.onDidFinishRenderingFrame(MapObserver::RenderMode(renderMode), placemenChanged);
if (needsRepaint || transform.inTransition()) {
onUpdate();
diff --git a/src/mbgl/map/map_impl.hpp b/src/mbgl/map/map_impl.hpp
index 13a68fb25e..416662f9e5 100644
--- a/src/mbgl/map/map_impl.hpp
+++ b/src/mbgl/map/map_impl.hpp
@@ -42,7 +42,7 @@ public:
void onInvalidate() final;
void onResourceError(std::exception_ptr) final;
void onWillStartRenderingFrame() final;
- void onDidFinishRenderingFrame(RenderMode, bool) final;
+ void onDidFinishRenderingFrame(RenderMode, bool, bool) final;
void onWillStartRenderingMap() final;
void onDidFinishRenderingMap() final;
void onStyleImageMissing(const std::string&, std::function<void()>) final;
diff --git a/src/mbgl/map/transform.cpp b/src/mbgl/map/transform.cpp
index d386898c3b..925893b2d6 100644
--- a/src/mbgl/map/transform.cpp
+++ b/src/mbgl/map/transform.cpp
@@ -63,7 +63,7 @@ void Transform::resize(const Size size) {
#pragma mark - Camera
-CameraOptions Transform::getCameraOptions(const EdgeInsets& padding) const {
+CameraOptions Transform::getCameraOptions(optional<EdgeInsets> padding) const {
return state.getCameraOptions(padding);
}
diff --git a/src/mbgl/map/transform.hpp b/src/mbgl/map/transform.hpp
index ffeff3859c..30ce8a37a4 100644
--- a/src/mbgl/map/transform.hpp
+++ b/src/mbgl/map/transform.hpp
@@ -29,7 +29,7 @@ public:
// Camera
/** Returns the current camera options. */
- CameraOptions getCameraOptions(const EdgeInsets&) const;
+ CameraOptions getCameraOptions(optional<EdgeInsets>) const;
/** Instantaneously, synchronously applies the given camera options. */
void jumpTo(const CameraOptions&);
diff --git a/src/mbgl/map/transform_state.cpp b/src/mbgl/map/transform_state.cpp
index 77309a2a55..61007422cb 100644
--- a/src/mbgl/map/transform_state.cpp
+++ b/src/mbgl/map/transform_state.cpp
@@ -3,6 +3,7 @@
#include <mbgl/util/constants.hpp>
#include <mbgl/util/interpolate.hpp>
#include <mbgl/util/projection.hpp>
+#include <mbgl/util/tile_coordinate.hpp>
#include <mbgl/math/log2.hpp>
#include <mbgl/math/clamp.hpp>
@@ -145,10 +146,10 @@ ViewportMode TransformState::getViewportMode() const {
#pragma mark - Camera options
-CameraOptions TransformState::getCameraOptions(const EdgeInsets& padding) const {
+CameraOptions TransformState::getCameraOptions(optional<EdgeInsets> padding) const {
return CameraOptions()
.withCenter(getLatLng())
- .withPadding(padding)
+ .withPadding(padding ? padding : edgeInsets)
.withZoom(getZoom())
.withBearing(-bearing * util::RAD2DEG)
.withPitch(pitch * util::RAD2DEG);
@@ -289,9 +290,9 @@ ScreenCoordinate TransformState::latLngToScreenCoordinate(const LatLng& latLng)
return { p[0] / p[3], size.height - p[1] / p[3] };
}
-LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, LatLng::WrapMode wrapMode) const {
+TileCoordinate TransformState::screenCoordinateToTileCoordinate(const ScreenCoordinate& point, uint8_t atZoom) const {
if (size.isEmpty()) {
- return {};
+ return { {}, 0 };
}
float targetZ = 0;
@@ -325,7 +326,13 @@ LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, L
double z1 = coord1[2] / w1;
double t = z0 == z1 ? 0 : (targetZ - z0) / (z1 - z0);
- return Projection::unproject(util::interpolate(p0, p1, t), scale / util::tileSize, wrapMode);
+ Point<double> p = util::interpolate(p0, p1, t) / scale * static_cast<double>(1 << atZoom);
+ return { { p.x, p.y }, static_cast<double>(atZoom) };
+}
+
+LatLng TransformState::screenCoordinateToLatLng(const ScreenCoordinate& point, LatLng::WrapMode wrapMode) const {
+ auto coord = screenCoordinateToTileCoordinate(point, 0);
+ return Projection::unproject(coord.p, 1 / util::tileSize, wrapMode);
}
mat4 TransformState::coordinatePointMatrix() const {
diff --git a/src/mbgl/map/transform_state.hpp b/src/mbgl/map/transform_state.hpp
index cca42db20f..10a92187d5 100644
--- a/src/mbgl/map/transform_state.hpp
+++ b/src/mbgl/map/transform_state.hpp
@@ -17,6 +17,7 @@
namespace mbgl {
class UnwrappedTileID;
+class TileCoordinate;
class TransformState {
friend class Transform;
@@ -42,7 +43,7 @@ public:
// Viewport mode
ViewportMode getViewportMode() const;
- CameraOptions getCameraOptions(const EdgeInsets&) const;
+ CameraOptions getCameraOptions(optional<EdgeInsets>) const;
// Position
LatLng getLatLng(LatLng::WrapMode = LatLng::Unwrapped) const;
@@ -81,6 +82,8 @@ public:
// Conversion
ScreenCoordinate latLngToScreenCoordinate(const LatLng&) const;
LatLng screenCoordinateToLatLng(const ScreenCoordinate&, LatLng::WrapMode = LatLng::Unwrapped) const;
+ // Implements mapbox-gl-js pointCoordinate() : MercatorCoordinate.
+ TileCoordinate screenCoordinateToTileCoordinate(const ScreenCoordinate&, uint8_t atZoom) const;
double zoomScale(double zoom) const;
double scaleZoom(double scale) const;
diff --git a/src/mbgl/programs/program_parameters.cpp b/src/mbgl/programs/program_parameters.cpp
index a49dc2bc88..95d2d0f668 100644
--- a/src/mbgl/programs/program_parameters.cpp
+++ b/src/mbgl/programs/program_parameters.cpp
@@ -4,8 +4,7 @@
namespace mbgl {
ProgramParameters::ProgramParameters(const float pixelRatio,
- const bool overdraw,
- optional<std::string> cacheDir_)
+ const bool overdraw)
: defines([&] {
std::string result;
result.reserve(32);
@@ -16,28 +15,11 @@ ProgramParameters::ProgramParameters(const float pixelRatio,
result += "#define OVERDRAW_INSPECTOR\n";
}
return result;
- }()),
- cacheDir(std::move(cacheDir_)) {
+ }()) {
}
const std::string& ProgramParameters::getDefines() const {
return defines;
}
-optional<std::string> ProgramParameters::cachePath(const char* name) const {
- if (!cacheDir) {
- return {};
- } else {
- std::string result;
- result.reserve(cacheDir->length() + 64);
- result += *cacheDir;
- result += "/com.mapbox.gl.shader.";
- result += name;
- result += '.';
- result += util::toHex(static_cast<uint64_t>(std::hash<std::string>()(defines)));
- result += ".pbf";
- return result;
- }
-}
-
} // namespace mbgl
diff --git a/src/mbgl/programs/program_parameters.hpp b/src/mbgl/programs/program_parameters.hpp
index 71ad454399..8af7ab50c0 100644
--- a/src/mbgl/programs/program_parameters.hpp
+++ b/src/mbgl/programs/program_parameters.hpp
@@ -8,14 +8,12 @@ namespace mbgl {
class ProgramParameters {
public:
- ProgramParameters(float pixelRatio, bool overdraw, optional<std::string> cacheDir);
+ ProgramParameters(float pixelRatio, bool overdraw);
const std::string& getDefines() const;
- optional<std::string> cachePath(const char* name) const;
private:
std::string defines;
- optional<std::string> cacheDir;
};
} // namespace mbgl
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.cpp b/src/mbgl/renderer/buckets/symbol_bucket.cpp
index 681a492e73..a46c25a13b 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.cpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.cpp
@@ -18,7 +18,6 @@ SymbolBucket::SymbolBucket(Immutable<style::SymbolLayoutProperties::PossiblyEval
const style::PropertyValue<float>& textSize,
const style::PropertyValue<float>& iconSize,
float zoom,
- bool sdfIcons_,
bool iconsNeedLinear_,
bool sortFeaturesByY_,
const std::string bucketName_,
@@ -28,7 +27,6 @@ SymbolBucket::SymbolBucket(Immutable<style::SymbolLayoutProperties::PossiblyEval
std::vector<style::TextWritingModeType> placementModes_)
: layout(std::move(layout_)),
bucketLeaderID(std::move(bucketName_)),
- sdfIcons(sdfIcons_),
iconsNeedLinear(iconsNeedLinear_ || iconSize.isDataDriven() || !iconSize.isZoomConstant()),
sortFeaturesByY(sortFeaturesByY_),
staticUploaded(false),
@@ -87,30 +85,37 @@ void SymbolBucket::upload(gfx::UploadPass& uploadPass) {
}
}
- if (hasIconData()) {
+ auto updateIconBuffer = [&](Buffer& iconBuffer) {
if (!staticUploaded) {
- icon.indexBuffer = uploadPass.createIndexBuffer(std::move(icon.triangles), sortFeaturesByY ? gfx::BufferUsageType::StreamDraw : gfx::BufferUsageType::StaticDraw);
- icon.vertexBuffer = uploadPass.createVertexBuffer(std::move(icon.vertices));
+ iconBuffer.indexBuffer = uploadPass.createIndexBuffer(std::move(iconBuffer.triangles), sortFeaturesByY ? gfx::BufferUsageType::StreamDraw : gfx::BufferUsageType::StaticDraw);
+ iconBuffer.vertexBuffer = uploadPass.createVertexBuffer(std::move(iconBuffer.vertices));
for (auto& pair : paintProperties) {
pair.second.iconBinders.upload(uploadPass);
}
} else if (!sortUploaded) {
- uploadPass.updateIndexBuffer(*icon.indexBuffer, std::move(icon.triangles));
+ uploadPass.updateIndexBuffer(*iconBuffer.indexBuffer, std::move(iconBuffer.triangles));
}
if (!dynamicUploaded) {
- if (!icon.dynamicVertexBuffer) {
- icon.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(icon.dynamicVertices), gfx::BufferUsageType::StreamDraw);
+ if (!iconBuffer.dynamicVertexBuffer) {
+ iconBuffer.dynamicVertexBuffer = uploadPass.createVertexBuffer(std::move(iconBuffer.dynamicVertices), gfx::BufferUsageType::StreamDraw);
} else {
- uploadPass.updateVertexBuffer(*icon.dynamicVertexBuffer, std::move(icon.dynamicVertices));
+ uploadPass.updateVertexBuffer(*iconBuffer.dynamicVertexBuffer, std::move(iconBuffer.dynamicVertices));
}
}
if (!placementChangesUploaded) {
- if (!icon.opacityVertexBuffer) {
- icon.opacityVertexBuffer = uploadPass.createVertexBuffer(std::move(icon.opacityVertices), gfx::BufferUsageType::StreamDraw);
+ if (!iconBuffer.opacityVertexBuffer) {
+ iconBuffer.opacityVertexBuffer = uploadPass.createVertexBuffer(std::move(iconBuffer.opacityVertices), gfx::BufferUsageType::StreamDraw);
} else {
- uploadPass.updateVertexBuffer(*icon.opacityVertexBuffer, std::move(icon.opacityVertices));
+ uploadPass.updateVertexBuffer(*iconBuffer.opacityVertexBuffer, std::move(iconBuffer.opacityVertices));
}
}
+ };
+ if (hasIconData()) {
+ updateIconBuffer(icon);
+ }
+
+ if (hasSdfIconData()) {
+ updateIconBuffer(sdfIcon);
}
if (hasCollisionBoxData()) {
@@ -149,7 +154,7 @@ void SymbolBucket::upload(gfx::UploadPass& uploadPass) {
}
bool SymbolBucket::hasData() const {
- return hasTextData() || hasIconData() || hasCollisionBoxData();
+ return hasTextData() || hasIconData() || hasSdfIconData() || hasCollisionBoxData();
}
bool SymbolBucket::hasTextData() const {
@@ -160,6 +165,10 @@ bool SymbolBucket::hasIconData() const {
return !icon.segments.empty();
}
+bool SymbolBucket::hasSdfIconData() const {
+ return !sdfIcon.segments.empty();
+}
+
bool SymbolBucket::hasCollisionBoxData() const {
return collisionBox && !collisionBox->segments.empty();
}
@@ -188,9 +197,9 @@ void SymbolBucket::sortFeatures(const float angle) {
sortedAngle = angle;
- // The current approach to sorting doesn't sort across segments so don't try.
+ // The current approach to sorting doesn't sort across text and icon segments so don't try.
// Sorting within segments separately seemed not to be worth the complexity.
- if (text.segments.size() > 1 || icon.segments.size() > 1) {
+ if (text.segments.size() > 1 || (icon.segments.size() > 1 || sdfIcon.segments.size() > 1)) {
return;
}
@@ -199,6 +208,7 @@ void SymbolBucket::sortFeatures(const float angle) {
text.triangles.clear();
icon.triangles.clear();
+ sdfIcon.triangles.clear();
featureSortOrder = std::make_unique<std::vector<size_t>>();
featureSortOrder->reserve(symbolInstances.size());
@@ -225,12 +235,13 @@ void SymbolBucket::sortFeatures(const float angle) {
addPlacedSymbol(text.triangles, text.placedSymbols[*symbolInstance.placedVerticalTextIndex]);
}
+ auto& iconBuffer = symbolInstance.hasSdfIcon() ? sdfIcon : icon;
if (symbolInstance.placedIconIndex) {
- addPlacedSymbol(icon.triangles, icon.placedSymbols[*symbolInstance.placedIconIndex]);
+ addPlacedSymbol(iconBuffer.triangles, iconBuffer.placedSymbols[*symbolInstance.placedIconIndex]);
}
if (symbolInstance.placedVerticalIconIndex) {
- addPlacedSymbol(icon.triangles, icon.placedSymbols[*symbolInstance.placedVerticalIconIndex]);
+ addPlacedSymbol(iconBuffer.triangles, iconBuffer.placedSymbols[*symbolInstance.placedVerticalIconIndex]);
}
}
}
diff --git a/src/mbgl/renderer/buckets/symbol_bucket.hpp b/src/mbgl/renderer/buckets/symbol_bucket.hpp
index 20c0c5b790..d813707c2f 100644
--- a/src/mbgl/renderer/buckets/symbol_bucket.hpp
+++ b/src/mbgl/renderer/buckets/symbol_bucket.hpp
@@ -55,7 +55,6 @@ public:
const style::PropertyValue<float>& textSize,
const style::PropertyValue<float>& iconSize,
float zoom,
- bool sdfIcons,
bool iconsNeedLinear,
bool sortFeaturesByY,
const std::string bucketLeaderID,
@@ -72,6 +71,7 @@ public:
void updateVertices(Placement&, bool updateOpacities, const TransformState&, const RenderTile&, std::set<uint32_t>&) override;
bool hasTextData() const;
bool hasIconData() const;
+ bool hasSdfIconData() const;
bool hasCollisionBoxData() const;
bool hasCollisionCircleData() const;
bool hasFormatSectionOverrides() const;
@@ -86,7 +86,6 @@ public:
float sortedAngle = std::numeric_limits<float>::max();
// Flags
- const bool sdfIcons : 1;
const bool iconsNeedLinear : 1;
const bool sortFeaturesByY : 1;
bool staticUploaded : 1;
@@ -124,7 +123,8 @@ public:
std::unique_ptr<SymbolSizeBinder> iconSizeBinder;
Buffer icon;
-
+ Buffer sdfIcon;
+
struct CollisionBuffer {
gfx::VertexVector<gfx::Vertex<CollisionBoxLayoutAttributes>> vertices;
gfx::VertexVector<gfx::Vertex<CollisionBoxDynamicAttributes>> dynamicVertices;
diff --git a/src/mbgl/renderer/layers/render_symbol_layer.cpp b/src/mbgl/renderer/layers/render_symbol_layer.cpp
index ffb32b9746..d0c038222a 100644
--- a/src/mbgl/renderer/layers/render_symbol_layer.cpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.cpp
@@ -67,20 +67,20 @@ struct RenderableSegment {
const LayerRenderData& renderData_,
const SymbolBucket::PaintProperties& bucketPaintProperties_,
float sortKey_,
- bool isText_) :
+ const SymbolType type_) :
segment(std::move(segment_)),
tile(tile_),
renderData(renderData_),
bucketPaintProperties(bucketPaintProperties_),
sortKey(sortKey_),
- isText(isText_) {}
+ type(type_) {}
SegmentWrapper segment;
const RenderTile& tile;
const LayerRenderData& renderData;
const SymbolBucket::PaintProperties& bucketPaintProperties;
float sortKey;
- bool isText;
+ SymbolType type;
friend bool operator < (const RenderableSegment& lhs, const RenderableSegment& rhs) {
// Sort renderable segments by a sort key.
@@ -91,11 +91,11 @@ struct RenderableSegment {
// In cases when sort key is the same, sort by the type of a segment (text over icons),
// and for segments of the same type with the same sort key, sort by a tile id.
if (lhs.sortKey == rhs.sortKey) {
- if (!lhs.isText && rhs.isText) {
+ if (lhs.type != SymbolType::Text && rhs.type == SymbolType::Text) {
return true;
}
- if (lhs.isText == rhs.isText) {
+ if (lhs.type == rhs.type) {
return lhs.tile.id < rhs.tile.id;
}
}
@@ -110,7 +110,8 @@ void drawIcon(const DrawFn& draw,
const LayerRenderData& renderData,
SegmentsWrapper iconSegments,
const SymbolBucket::PaintProperties& bucketPaintProperties,
- const PaintParameters& parameters) {
+ const PaintParameters& parameters,
+ const bool sdfIcons) {
auto& bucket = static_cast<SymbolBucket&>(*renderData.bucket);
const auto& evaluated = getEvaluated<SymbolLayerProperties>(renderData.layerProperties);
const auto& layout = *bucket.layout;
@@ -124,7 +125,7 @@ void drawIcon(const DrawFn& draw,
const bool iconTransformed = values.rotationAlignment == AlignmentType::Map || parameters.state.getPitch() != 0;
const gfx::TextureBinding textureBinding{ tile.getIconAtlasTexture().getResource(),
- bucket.sdfIcons ||
+ sdfIcons ||
parameters.state.isChanging() ||
iconScaled || iconTransformed
? gfx::TextureFilterType::Linear
@@ -133,11 +134,11 @@ void drawIcon(const DrawFn& draw,
const Size& iconSize = tile.getIconAtlasTexture().size;
const bool variablePlacedIcon = bucket.hasVariablePlacement && layout.get<IconTextFit>() != IconTextFitType::None;
- if (bucket.sdfIcons) {
+ if (sdfIcons) {
if (values.hasHalo) {
draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF,
SymbolSDFIconProgram::layoutUniformValues(false, variablePlacedIcon, values, iconSize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Halo),
- bucket.icon,
+ bucket.sdfIcon,
iconSegments,
bucket.iconSizeBinder,
bucketPaintProperties.iconBinders,
@@ -151,7 +152,7 @@ void drawIcon(const DrawFn& draw,
if (values.hasFill) {
draw(parameters.programs.getSymbolLayerPrograms().symbolIconSDF,
SymbolSDFIconProgram::layoutUniformValues(false, variablePlacedIcon, values, iconSize, parameters.pixelsToGLUnits, parameters.pixelRatio, alongLine, tile, parameters.state, parameters.symbolFadeChange, SymbolSDFPart::Fill),
- bucket.icon,
+ bucket.sdfIcon,
iconSegments,
bucket.iconSizeBinder,
bucketPaintProperties.iconBinders,
@@ -361,23 +362,31 @@ void RenderSymbolLayer::render(PaintParameters& parameters) {
assert(bucket.paintProperties.find(getID()) != bucket.paintProperties.end());
const auto& bucketPaintProperties = bucket.paintProperties.at(getID());
- auto addRenderables = [&renderableSegments, &tile, renderData, &bucketPaintProperties, it = renderableSegments.begin()] (auto& segments, bool isText) mutable {
+ auto addRenderables = [&renderableSegments, &tile, renderData, &bucketPaintProperties, it = renderableSegments.begin()] (auto& segments, const SymbolType type) mutable {
for (auto& segment : segments) {
- it = renderableSegments.emplace_hint(it, SegmentWrapper{std::ref(segment)}, tile, *renderData, bucketPaintProperties, segment.sortKey, isText);
+ it = renderableSegments.emplace_hint(it, SegmentWrapper{std::ref(segment)}, tile, *renderData, bucketPaintProperties, segment.sortKey, type);
}
};
if (bucket.hasIconData()) {
if (sortFeaturesByKey) {
- addRenderables(bucket.icon.segments, false /*isText*/);
+ addRenderables(bucket.icon.segments, SymbolType::IconRGBA);
+ } else {
+ drawIcon(draw, tile, *renderData, std::ref(bucket.icon.segments), bucketPaintProperties, parameters, false /*sdfIcon*/);
+ }
+ }
+
+ if (bucket.hasSdfIconData()) {
+ if (sortFeaturesByKey) {
+ addRenderables(bucket.sdfIcon.segments, SymbolType::IconSDF);
} else {
- drawIcon(draw, tile, *renderData, std::ref(bucket.icon.segments), bucketPaintProperties, parameters);
+ drawIcon(draw, tile, *renderData, std::ref(bucket.sdfIcon.segments), bucketPaintProperties, parameters, true /*sdfIcon*/);
}
}
if (bucket.hasTextData()) {
if (sortFeaturesByKey) {
- addRenderables(bucket.text.segments, true /*isText*/);
+ addRenderables(bucket.text.segments, SymbolType::Text);
} else {
drawText(draw, tile, *renderData, std::ref(bucket.text.segments), bucketPaintProperties, parameters);
}
@@ -460,10 +469,10 @@ void RenderSymbolLayer::render(PaintParameters& parameters) {
if (sortFeaturesByKey) {
for (auto& renderable : renderableSegments) {
- if (renderable.isText) {
+ if (renderable.type == SymbolType::Text) {
drawText(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters);
} else {
- drawIcon(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters);
+ drawIcon(draw, renderable.tile, renderable.renderData, renderable.segment, renderable.bucketPaintProperties, parameters, renderable.type == SymbolType::IconSDF);
}
}
}
diff --git a/src/mbgl/renderer/layers/render_symbol_layer.hpp b/src/mbgl/renderer/layers/render_symbol_layer.hpp
index d9ce8c688d..5fcb9e2c8c 100644
--- a/src/mbgl/renderer/layers/render_symbol_layer.hpp
+++ b/src/mbgl/renderer/layers/render_symbol_layer.hpp
@@ -50,6 +50,12 @@ public:
bool hasFill;
};
+enum class SymbolType : uint8_t {
+ Text,
+ IconRGBA,
+ IconSDF
+};
+
} // namespace style
class RenderSymbolLayer final: public RenderLayer {
diff --git a/src/mbgl/renderer/render_orchestrator.cpp b/src/mbgl/renderer/render_orchestrator.cpp
index f9956dbc2a..983bc09485 100644
--- a/src/mbgl/renderer/render_orchestrator.cpp
+++ b/src/mbgl/renderer/render_orchestrator.cpp
@@ -361,9 +361,9 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar
}
bool symbolBucketsChanged = false;
- const bool placementChanged = !placement->stillRecent(updateParameters.timePoint, updateParameters.transformState.getZoom());
+ renderTreeParameters->placementChanged = !placement->stillRecent(updateParameters.timePoint, updateParameters.transformState.getZoom());
std::set<std::string> usedSymbolLayers;
- if (placementChanged) {
+ if (renderTreeParameters->placementChanged) {
placement = std::make_unique<Placement>(
updateParameters.transformState, updateParameters.mode,
updateParameters.transitionOptions, updateParameters.crossSourceCollisions,
@@ -374,13 +374,13 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar
const RenderLayer& layer = *it;
if (crossTileSymbolIndex.addLayer(layer, updateParameters.transformState.getLatLng().longitude())) symbolBucketsChanged = true;
- if (placementChanged) {
+ if (renderTreeParameters->placementChanged) {
usedSymbolLayers.insert(layer.getID());
placement->placeLayer(layer, renderTreeParameters->transformParams.projMatrix, updateParameters.debugOptions & MapDebugOptions::Collision);
}
}
- if (placementChanged) {
+ if (renderTreeParameters->placementChanged) {
placement->commit(updateParameters.timePoint, updateParameters.transformState.getZoom());
crossTileSymbolIndex.pruneUnusedLayers(usedSymbolLayers);
for (const auto& entry : renderSources) {
@@ -391,7 +391,7 @@ std::unique_ptr<RenderTree> RenderOrchestrator::createRenderTree(const UpdatePar
}
for (auto it = layersNeedPlacement.rbegin(); it != layersNeedPlacement.rend(); ++it) {
- placement->updateLayerBuckets(*it, updateParameters.transformState, placementChanged || symbolBucketsChanged);
+ placement->updateLayerBuckets(*it, updateParameters.transformState, renderTreeParameters->placementChanged || symbolBucketsChanged);
}
renderTreeParameters->symbolFadeChange = placement->symbolFadeChange(updateParameters.timePoint);
diff --git a/src/mbgl/renderer/render_static_data.cpp b/src/mbgl/renderer/render_static_data.cpp
index 9090ef6579..6378ad9989 100644
--- a/src/mbgl/renderer/render_static_data.cpp
+++ b/src/mbgl/renderer/render_static_data.cpp
@@ -49,10 +49,10 @@ static gfx::VertexVector<HeatmapTextureLayoutVertex> heatmapTextureVertices() {
return result;
}
-RenderStaticData::RenderStaticData(gfx::Context& context, float pixelRatio, const optional<std::string>& programCacheDir)
- : programs(context, ProgramParameters { pixelRatio, false, programCacheDir })
+RenderStaticData::RenderStaticData(gfx::Context& context, float pixelRatio)
+ : programs(context, ProgramParameters { pixelRatio, false })
#ifndef NDEBUG
- , overdrawPrograms(context, ProgramParameters { pixelRatio, true, programCacheDir })
+ , overdrawPrograms(context, ProgramParameters { pixelRatio, true })
#endif
{
tileTriangleSegments.emplace_back(0, 0, 4, 6);
diff --git a/src/mbgl/renderer/render_static_data.hpp b/src/mbgl/renderer/render_static_data.hpp
index 5b409933af..6bf2c846f4 100644
--- a/src/mbgl/renderer/render_static_data.hpp
+++ b/src/mbgl/renderer/render_static_data.hpp
@@ -19,7 +19,7 @@ class UploadPass;
class RenderStaticData {
public:
- RenderStaticData(gfx::Context&, float pixelRatio, const optional<std::string>& programCacheDir);
+ RenderStaticData(gfx::Context&, float pixelRatio);
void upload(gfx::UploadPass&);
diff --git a/src/mbgl/renderer/render_tree.hpp b/src/mbgl/renderer/render_tree.hpp
index cf62ccb03e..557442c0fa 100644
--- a/src/mbgl/renderer/render_tree.hpp
+++ b/src/mbgl/renderer/render_tree.hpp
@@ -52,6 +52,7 @@ public:
float symbolFadeChange = 0.0f;
bool needsRepaint = false;
bool loaded = false;
+ bool placementChanged = false;
};
class RenderTree {
diff --git a/src/mbgl/renderer/renderer.cpp b/src/mbgl/renderer/renderer.cpp
index dd715bd3bc..52cd7a4351 100644
--- a/src/mbgl/renderer/renderer.cpp
+++ b/src/mbgl/renderer/renderer.cpp
@@ -10,11 +10,9 @@ namespace mbgl {
Renderer::Renderer(gfx::RendererBackend& backend,
float pixelRatio_,
- const optional<std::string> programCacheDir_,
const optional<std::string> localFontFamily_)
: impl(std::make_unique<Impl>(backend,
pixelRatio_,
- std::move(programCacheDir_),
std::move(localFontFamily_))) {
}
diff --git a/src/mbgl/renderer/renderer_impl.cpp b/src/mbgl/renderer/renderer_impl.cpp
index 990d9cd3ab..113840d059 100644
--- a/src/mbgl/renderer/renderer_impl.cpp
+++ b/src/mbgl/renderer/renderer_impl.cpp
@@ -26,13 +26,11 @@ static RendererObserver& nullObserver() {
Renderer::Impl::Impl(gfx::RendererBackend& backend_,
float pixelRatio_,
- optional<std::string> programCacheDir_,
optional<std::string> localFontFamily_)
: orchestrator(!backend_.contextIsShared(), std::move(localFontFamily_))
, backend(backend_)
, observer(&nullObserver())
- , pixelRatio(pixelRatio_)
- , programCacheDir(std::move(programCacheDir_)) {
+ , pixelRatio(pixelRatio_) {
}
@@ -53,7 +51,7 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
const auto& renderTreeParameters = renderTree.getParameters();
if (!staticData) {
- staticData = std::make_unique<RenderStaticData>(backend.getContext(), pixelRatio, programCacheDir);
+ staticData = std::make_unique<RenderStaticData>(backend.getContext(), pixelRatio);
}
staticData->has3D = renderTreeParameters.has3D;
@@ -212,7 +210,8 @@ void Renderer::Impl::render(const RenderTree& renderTree) {
observer->onDidFinishRenderingFrame(
renderTreeParameters.loaded ? RendererObserver::RenderMode::Full : RendererObserver::RenderMode::Partial,
- renderTreeParameters.needsRepaint
+ renderTreeParameters.needsRepaint,
+ renderTreeParameters.placementChanged
);
if (!renderTreeParameters.loaded) {
diff --git a/src/mbgl/renderer/renderer_impl.hpp b/src/mbgl/renderer/renderer_impl.hpp
index 85e37a014a..5f04bfdfed 100644
--- a/src/mbgl/renderer/renderer_impl.hpp
+++ b/src/mbgl/renderer/renderer_impl.hpp
@@ -19,7 +19,6 @@ class Renderer::Impl {
public:
Impl(gfx::RendererBackend&,
float pixelRatio_,
- optional<std::string> programCacheDir,
optional<std::string> localFontFamily_);
~Impl();
@@ -40,7 +39,6 @@ private:
RendererObserver* observer;
const float pixelRatio;
- const optional<std::string> programCacheDir;
std::unique_ptr<RenderStaticData> staticData;
enum class RenderState {
diff --git a/src/mbgl/renderer/sources/render_geojson_source.cpp b/src/mbgl/renderer/sources/render_geojson_source.cpp
index e451dab6d3..035244e371 100644
--- a/src/mbgl/renderer/sources/render_geojson_source.cpp
+++ b/src/mbgl/renderer/sources/render_geojson_source.cpp
@@ -94,7 +94,7 @@ void RenderGeoJSONSource::update(Immutable<style::Source::Impl> baseImpl_,
const uint8_t maxZ = impl().getZoomRange().max;
for (const auto& pair : tilePyramid.getTiles()) {
if (pair.first.canonical.z <= maxZ) {
- static_cast<GeoJSONTile*>(pair.second.get())->updateData(data_->getTile(pair.first.canonical));
+ static_cast<GeoJSONTile*>(pair.second.get())->updateData(data_->getTile(pair.first.canonical), needsRelayout);
}
}
}
diff --git a/src/mbgl/style/layers/fill_layer_impl.cpp b/src/mbgl/style/layers/fill_layer_impl.cpp
index 4df32e02fa..45e350e00e 100644
--- a/src/mbgl/style/layers/fill_layer_impl.cpp
+++ b/src/mbgl/style/layers/fill_layer_impl.cpp
@@ -8,6 +8,7 @@ bool FillLayer::Impl::hasLayoutDifference(const Layer::Impl& other) const {
const auto& impl = static_cast<const style::FillLayer::Impl&>(other);
return filter != impl.filter ||
visibility != impl.visibility ||
+ paint.get<FillPattern>().value != impl.paint.get<FillPattern>().value ||
paint.hasDataDrivenPropertyDifference(impl.paint);
}
diff --git a/src/mbgl/text/glyph_manager.cpp b/src/mbgl/text/glyph_manager.cpp
index 990e8be945..35ea1031d5 100644
--- a/src/mbgl/text/glyph_manager.cpp
+++ b/src/mbgl/text/glyph_manager.cpp
@@ -99,8 +99,10 @@ void GlyphManager::processResponse(const Response& res, const FontStack& fontSta
for (auto& glyph : glyphs) {
auto id = glyph.id;
- entry.glyphs.erase(id);
- entry.glyphs.emplace(id, makeMutable<Glyph>(std::move(glyph)));
+ if (!localGlyphRasterizer->canRasterizeGlyph(fontStack, id)) {
+ entry.glyphs.erase(id);
+ entry.glyphs.emplace(id, makeMutable<Glyph>(std::move(glyph)));
+ }
}
}
diff --git a/src/mbgl/text/placement.cpp b/src/mbgl/text/placement.cpp
index 9f9d948b94..9bc87911de 100644
--- a/src/mbgl/text/placement.cpp
+++ b/src/mbgl/text/placement.cpp
@@ -153,7 +153,7 @@ void Placement::placeBucket(
// This is the reverse of our normal policy of "fade in on pan", but should look like any other
// collision and hopefully not be too noticeable.
// See https://github.com/mapbox/mapbox-gl-native/issues/12683
- const bool alwaysShowText = textAllowOverlap && (iconAllowOverlap || !bucket.hasIconData() || layout.get<style::IconOptional>());
+ const bool alwaysShowText = textAllowOverlap && (iconAllowOverlap || !(bucket.hasIconData() || bucket.hasSdfIconData()) || layout.get<style::IconOptional>());
const bool alwaysShowIcon = iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || layout.get<style::TextOptional>());
std::vector<style::TextVariableAnchorType> variableTextAnchors = layout.get<style::TextVariableAnchor>();
const bool rotateWithMap = layout.get<style::TextRotationAlignment>() == style::AlignmentType::Map;
@@ -367,7 +367,8 @@ void Placement::placeBucket(
shift = {0.0f, 0.0f};
}
- const PlacedSymbol& placedSymbol = bucket.icon.placedSymbols.at(*symbolInstance.placedIconIndex);
+ const auto& iconBuffer = symbolInstance.hasSdfIcon() ? bucket.sdfIcon : bucket.icon;
+ const PlacedSymbol& placedSymbol = iconBuffer.placedSymbols.at(*symbolInstance.placedIconIndex);
const float fontSize = evaluateSizeForFeature(partiallyEvaluatedIconSize, placedSymbol);
const auto& placeIconFeature = [&] (const CollisionFeature& collisionFeature) {
return collisionIndex.placeFeature(collisionFeature, shift,
@@ -389,8 +390,8 @@ void Placement::placeBucket(
offscreen &= placedIcon.second;
}
- const bool iconWithoutText = !symbolInstance.hasText || layout.get<style::TextOptional>();
- const bool textWithoutIcon = !symbolInstance.hasIcon || layout.get<style::IconOptional>();
+ const bool iconWithoutText = !symbolInstance.hasText() || layout.get<style::TextOptional>();
+ const bool textWithoutIcon = !symbolInstance.hasIcon() || layout.get<style::IconOptional>();
// combine placements for icon and text
if (!iconWithoutText && !textWithoutIcon) {
@@ -538,17 +539,25 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
const auto& layout = *bucket.layout;
const bool alongLine = layout.get<SymbolPlacement>() != SymbolPlacementType::Point;
const bool hasVariableAnchors = !layout.get<TextVariableAnchor>().empty() && bucket.hasTextData();
- const bool updateTextFitIcon = layout.get<IconTextFit>() != IconTextFitType::None && (bucket.allowVerticalPlacement || hasVariableAnchors) && bucket.hasIconData();
+ const bool updateTextFitIcon = layout.get<IconTextFit>() != IconTextFitType::None && (bucket.allowVerticalPlacement || hasVariableAnchors) && (bucket.hasIconData() || bucket.hasSdfIconData());
bool result = false;
if (alongLine) {
- if (bucket.hasIconData() && layout.get<IconRotationAlignment>() == AlignmentType::Map) {
+ if (layout.get<IconRotationAlignment>() == AlignmentType::Map) {
const bool pitchWithMap = layout.get<style::IconPitchAlignment>() == style::AlignmentType::Map;
const bool keepUpright = layout.get<style::IconKeepUpright>();
- reprojectLineLabels(bucket.icon.dynamicVertices, bucket.icon.placedSymbols,
- tile.matrix, pitchWithMap, true /*rotateWithMap*/, keepUpright,
- tile, *bucket.iconSizeBinder, state);
- result = true;
+ if (bucket.hasSdfIconData()) {
+ reprojectLineLabels(bucket.sdfIcon.dynamicVertices, bucket.sdfIcon.placedSymbols,
+ tile.matrix, pitchWithMap, true /*rotateWithMap*/, keepUpright,
+ tile, *bucket.iconSizeBinder, state);
+ result = true;
+ }
+ if (bucket.hasIconData()) {
+ reprojectLineLabels(bucket.icon.dynamicVertices, bucket.icon.placedSymbols,
+ tile.matrix, pitchWithMap, true /*rotateWithMap*/, keepUpright,
+ tile, *bucket.iconSizeBinder, state);
+ result = true;
+ }
}
if (bucket.hasTextData() && layout.get<TextRotationAlignment>() == AlignmentType::Map) {
@@ -633,22 +642,26 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
}
if (updateTextFitIcon && bucket.hasVariablePlacement) {
- bucket.icon.dynamicVertices.clear();
- for (std::size_t i = 0; i < bucket.icon.placedSymbols.size(); ++i) {
- const PlacedSymbol& placedIcon = bucket.icon.placedSymbols[i];
- if (placedIcon.hidden || (!placedIcon.placedOrientation && bucket.allowVerticalPlacement)) {
- hideGlyphs(placedIcon.glyphOffsets.size(), bucket.icon.dynamicVertices);
- } else {
- const auto& pair = placedTextShifts.find(i);
- if (pair == placedTextShifts.end()) {
- hideGlyphs(placedIcon.glyphOffsets.size(), bucket.icon.dynamicVertices);
+ auto updateIcon = [&](SymbolBucket::Buffer& iconBuffer) {
+ iconBuffer.dynamicVertices.clear();
+ for (std::size_t i = 0; i < iconBuffer.placedSymbols.size(); ++i) {
+ const PlacedSymbol& placedIcon = iconBuffer.placedSymbols[i];
+ if (placedIcon.hidden || (!placedIcon.placedOrientation && bucket.allowVerticalPlacement)) {
+ hideGlyphs(placedIcon.glyphOffsets.size(), iconBuffer.dynamicVertices);
} else {
- for (std::size_t j = 0; j < placedIcon.glyphOffsets.size(); ++j) {
- addDynamicAttributes(pair->second.second, placedIcon.angle, bucket.icon.dynamicVertices);
+ const auto& pair = placedTextShifts.find(i);
+ if (pair == placedTextShifts.end()) {
+ hideGlyphs(placedIcon.glyphOffsets.size(), iconBuffer.dynamicVertices);
+ } else {
+ for (std::size_t j = 0; j < placedIcon.glyphOffsets.size(); ++j) {
+ addDynamicAttributes(pair->second.second, placedIcon.angle, iconBuffer.dynamicVertices);
+ }
}
}
}
- }
+ };
+ updateIcon(bucket.icon);
+ updateIcon(bucket.sdfIcon);
}
result = true;
@@ -670,6 +683,7 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
// When text box is rotated, icon-text-fit icon must be rotated as well.
if (updateTextFitIcon) {
updateDynamicVertices(bucket.icon);
+ updateDynamicVertices(bucket.sdfIcon);
}
result = true;
@@ -681,6 +695,7 @@ bool Placement::updateBucketDynamicVertices(SymbolBucket& bucket, const Transfor
void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState& state, std::set<uint32_t>& seenCrossTileIDs) {
if (bucket.hasTextData()) bucket.text.opacityVertices.clear();
if (bucket.hasIconData()) bucket.icon.opacityVertices.clear();
+ if (bucket.hasSdfIconData()) bucket.sdfIcon.opacityVertices.clear();
if (bucket.hasCollisionBoxData()) bucket.collisionBox->dynamicVertices.clear();
if (bucket.hasCollisionCircleData()) bucket.collisionCircle->dynamicVertices.clear();
@@ -698,7 +713,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
// with allow-overlap: false.
// See https://github.com/mapbox/mapbox-gl-native/issues/12483
JointOpacityState defaultOpacityState(
- textAllowOverlap && (iconAllowOverlap || !bucket.hasIconData() || bucket.layout->get<style::IconOptional>()),
+ textAllowOverlap && (iconAllowOverlap || !(bucket.hasIconData() || bucket.hasSdfIconData()) || bucket.layout->get<style::IconOptional>()),
iconAllowOverlap && (textAllowOverlap || !bucket.hasTextData() || bucket.layout->get<style::TextOptional>()),
true);
@@ -719,7 +734,7 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
seenCrossTileIDs.insert(symbolInstance.crossTileID);
- if (symbolInstance.hasText) {
+ if (symbolInstance.hasText()) {
size_t textOpacityVerticesSize = 0u;
const auto& opacityVertex = SymbolSDFTextProgram::opacityVertex(opacityState.text.placed, opacityState.text.opacity);
if (symbolInstance.placedRightTextIndex) {
@@ -758,16 +773,18 @@ void Placement::updateBucketOpacities(SymbolBucket& bucket, const TransformState
markUsedJustification(bucket, prevOffset->second.anchor, symbolInstance, previousOrientation);
}
}
- if (symbolInstance.hasIcon) {
+ if (symbolInstance.hasIcon()) {
const auto& opacityVertex = SymbolIconProgram::opacityVertex(opacityState.icon.placed, opacityState.icon.opacity);
+ auto& iconBuffer = symbolInstance.hasSdfIcon() ? bucket.sdfIcon : bucket.icon;
+
if (symbolInstance.placedIconIndex) {
- bucket.icon.opacityVertices.extend(4, opacityVertex);
- bucket.icon.placedSymbols[*symbolInstance.placedIconIndex].hidden = opacityState.isHidden();
+ iconBuffer.opacityVertices.extend(4, opacityVertex);
+ iconBuffer.placedSymbols[*symbolInstance.placedIconIndex].hidden = opacityState.isHidden();
}
if (symbolInstance.placedVerticalIconIndex) {
- bucket.icon.opacityVertices.extend(4, opacityVertex);
- bucket.icon.placedSymbols[*symbolInstance.placedVerticalIconIndex].hidden = opacityState.isHidden();
+ iconBuffer.opacityVertices.extend(4, opacityVertex);
+ iconBuffer.placedSymbols[*symbolInstance.placedVerticalIconIndex].hidden = opacityState.isHidden();
}
}
@@ -919,12 +936,13 @@ void Placement::markUsedOrientation(SymbolBucket& bucket, style::TextWritingMode
bucket.text.placedSymbols.at(*symbolInstance.placedVerticalTextIndex).placedOrientation = vertical;
}
+ auto& iconBuffer = symbolInstance.hasSdfIcon() ? bucket.sdfIcon : bucket.icon;
if (symbolInstance.placedIconIndex) {
- bucket.icon.placedSymbols.at(*symbolInstance.placedIconIndex).placedOrientation = horizontal;
+ iconBuffer.placedSymbols.at(*symbolInstance.placedIconIndex).placedOrientation = horizontal;
}
if (symbolInstance.placedVerticalIconIndex) {
- bucket.icon.placedSymbols.at(*symbolInstance.placedVerticalIconIndex).placedOrientation = vertical;
+ iconBuffer.placedSymbols.at(*symbolInstance.placedVerticalIconIndex).placedOrientation = vertical;
}
}
diff --git a/src/mbgl/tile/geojson_tile.cpp b/src/mbgl/tile/geojson_tile.cpp
index 4cf971df84..0782f74d5d 100644
--- a/src/mbgl/tile/geojson_tile.cpp
+++ b/src/mbgl/tile/geojson_tile.cpp
@@ -13,8 +13,8 @@ GeoJSONTile::GeoJSONTile(const OverscaledTileID& overscaledTileID,
updateData(std::move(features));
}
-void GeoJSONTile::updateData(mapbox::feature::feature_collection<int16_t> features) {
- setData(std::make_unique<GeoJSONTileData>(std::move(features)));
+void GeoJSONTile::updateData(mapbox::feature::feature_collection<int16_t> features, bool resetLayers) {
+ setData(std::make_unique<GeoJSONTileData>(std::move(features)), resetLayers);
}
void GeoJSONTile::querySourceFeatures(
diff --git a/src/mbgl/tile/geojson_tile.hpp b/src/mbgl/tile/geojson_tile.hpp
index 725dc4850c..9161e33f0c 100644
--- a/src/mbgl/tile/geojson_tile.hpp
+++ b/src/mbgl/tile/geojson_tile.hpp
@@ -14,7 +14,7 @@ public:
const TileParameters&,
mapbox::feature::feature_collection<int16_t>);
- void updateData(mapbox::feature::feature_collection<int16_t>);
+ void updateData(mapbox::feature::feature_collection<int16_t>, bool resetLayers = false);
void querySourceFeatures(
std::vector<Feature>& result,
diff --git a/src/mbgl/tile/geometry_tile.cpp b/src/mbgl/tile/geometry_tile.cpp
index a431ae423e..3087b4fc6a 100644
--- a/src/mbgl/tile/geometry_tile.cpp
+++ b/src/mbgl/tile/geometry_tile.cpp
@@ -176,13 +176,13 @@ void GeometryTile::setError(std::exception_ptr err) {
observer->onTileError(*this, err);
}
-void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_) {
+void GeometryTile::setData(std::unique_ptr<const GeometryTileData> data_, bool resetLayers) {
// Mark the tile as pending again if it was complete before to prevent signaling a complete
// state despite pending parse operations.
pending = true;
++correlationID;
- worker.self().invoke(&GeometryTileWorker::setData, std::move(data_), correlationID);
+ worker.self().invoke(&GeometryTileWorker::setData, std::move(data_), resetLayers, correlationID);
}
std::unique_ptr<TileRenderData> GeometryTile::createRenderData() {
diff --git a/src/mbgl/tile/geometry_tile.hpp b/src/mbgl/tile/geometry_tile.hpp
index 7c46edfc1d..8682c8c76b 100644
--- a/src/mbgl/tile/geometry_tile.hpp
+++ b/src/mbgl/tile/geometry_tile.hpp
@@ -34,7 +34,7 @@ public:
~GeometryTile() override;
void setError(std::exception_ptr);
- void setData(std::unique_ptr<const GeometryTileData>);
+ void setData(std::unique_ptr<const GeometryTileData>, bool resetLayers = false);
std::unique_ptr<TileRenderData> createRenderData() override;
void setLayers(const std::vector<Immutable<style::LayerProperties>>&) override;
diff --git a/src/mbgl/tile/geometry_tile_worker.cpp b/src/mbgl/tile/geometry_tile_worker.cpp
index f4d57e5bfc..428a5b0d5e 100644
--- a/src/mbgl/tile/geometry_tile_worker.cpp
+++ b/src/mbgl/tile/geometry_tile_worker.cpp
@@ -117,10 +117,11 @@ GeometryTileWorker::~GeometryTileWorker() = default;
completed parse.
*/
-void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_, uint64_t correlationID_) {
+void GeometryTileWorker::setData(std::unique_ptr<const GeometryTileData> data_, bool resetLayers_, uint64_t correlationID_) {
try {
data = std::move(data_);
correlationID = correlationID_;
+ if (resetLayers_) layers = nullopt;
switch (state) {
case Idle:
diff --git a/src/mbgl/tile/geometry_tile_worker.hpp b/src/mbgl/tile/geometry_tile_worker.hpp
index 258f2cd186..96b4e2e83a 100644
--- a/src/mbgl/tile/geometry_tile_worker.hpp
+++ b/src/mbgl/tile/geometry_tile_worker.hpp
@@ -39,7 +39,7 @@ public:
~GeometryTileWorker();
void setLayers(std::vector<Immutable<style::LayerProperties>>, uint64_t correlationID);
- void setData(std::unique_ptr<const GeometryTileData>, uint64_t correlationID);
+ void setData(std::unique_ptr<const GeometryTileData>, bool resetLayers, uint64_t correlationID);
void setShowCollisionBoxes(bool showCollisionBoxes_, uint64_t correlationID_);
void onGlyphsAvailable(GlyphMap glyphs);
diff --git a/src/mbgl/util/tile_coordinate.hpp b/src/mbgl/util/tile_coordinate.hpp
index b6bdc5f590..6d78804947 100644
--- a/src/mbgl/util/tile_coordinate.hpp
+++ b/src/mbgl/util/tile_coordinate.hpp
@@ -13,6 +13,7 @@ using TileCoordinatePoint = Point<double>;
// Has floating point x/y coordinates.
// Used for computing the tiles that need to be visible in the viewport.
+// In mapbox-gl-js, this is named MercatorCoordinate.
class TileCoordinate {
public:
TileCoordinatePoint p;
@@ -23,8 +24,8 @@ public:
return { Projection::project(latLng, scale) / util::tileSize, zoom };
}
- static TileCoordinate fromScreenCoordinate(const TransformState& state, double zoom, const ScreenCoordinate& screenCoordinate) {
- return fromLatLng(zoom, state.screenCoordinateToLatLng(screenCoordinate));
+ static TileCoordinate fromScreenCoordinate(const TransformState& state, uint8_t zoom, const ScreenCoordinate& screenCoordinate) {
+ return state.screenCoordinateToTileCoordinate(screenCoordinate, zoom);
}
TileCoordinate zoomTo(double zoom) const {
diff --git a/src/mbgl/util/tile_cover.cpp b/src/mbgl/util/tile_cover.cpp
index 5189b79f26..9e2451e1af 100644
--- a/src/mbgl/util/tile_cover.cpp
+++ b/src/mbgl/util/tile_cover.cpp
@@ -84,7 +84,7 @@ std::vector<UnwrappedTileID> tileCover(const Point<double>& tl,
const Point<double>& br,
const Point<double>& bl,
const Point<double>& c,
- int32_t z) {
+ uint8_t z) {
const int32_t tiles = 1 << z;
struct ID {
@@ -139,7 +139,7 @@ int32_t coveringZoomLevel(double zoom, style::SourceType type, uint16_t size) {
}
}
-std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, int32_t z) {
+std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, uint8_t z) {
if (bounds_.isEmpty() ||
bounds_.south() > util::LATITUDE_MAX ||
bounds_.north() < -util::LATITUDE_MAX) {
@@ -159,7 +159,7 @@ std::vector<UnwrappedTileID> tileCover(const LatLngBounds& bounds_, int32_t z) {
z);
}
-std::vector<UnwrappedTileID> tileCover(const TransformState& state, int32_t z) {
+std::vector<UnwrappedTileID> tileCover(const TransformState& state, uint8_t z) {
assert(state.valid());
const double w = state.getSize().width;
@@ -173,7 +173,7 @@ 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> tileCover(const Geometry<double>& geometry, uint8_t z) {
std::vector<UnwrappedTileID> result;
TileCover tc(geometry, z, true);
while (tc.hasNext()) {
@@ -213,7 +213,7 @@ uint64_t tileCount(const Geometry<double>& geometry, uint8_t z) {
return tileCount;
}
-TileCover::TileCover(const LatLngBounds&bounds_, int32_t z) {
+TileCover::TileCover(const LatLngBounds&bounds_, uint8_t z) {
LatLngBounds bounds = LatLngBounds::hull(
{ std::max(bounds_.south(), -util::LATITUDE_MAX), bounds_.west() },
{ std::min(bounds_.north(), util::LATITUDE_MAX), bounds_.east() });
@@ -233,7 +233,7 @@ TileCover::TileCover(const LatLngBounds&bounds_, int32_t z) {
impl = std::make_unique<TileCover::Impl>(z, p, false);
}
-TileCover::TileCover(const Geometry<double>& geom, int32_t z, bool project/* = true*/)
+TileCover::TileCover(const Geometry<double>& geom, uint8_t z, bool project/* = true*/)
: impl( std::make_unique<TileCover::Impl>(z, geom, project)) {
}
diff --git a/src/mbgl/util/tile_cover.hpp b/src/mbgl/util/tile_cover.hpp
index c953d764d2..5ac3537bf6 100644
--- a/src/mbgl/util/tile_cover.hpp
+++ b/src/mbgl/util/tile_cover.hpp
@@ -18,9 +18,9 @@ namespace util {
// Helper class to stream tile-cover results per row
class TileCover {
public:
- TileCover(const LatLngBounds&, int32_t z);
+ TileCover(const LatLngBounds&, uint8_t z);
// When project == true, projects the geometry points to tile coordinates
- TileCover(const Geometry<double>&, int32_t z, bool project = true);
+ TileCover(const Geometry<double>&, uint8_t z, bool project = true);
~TileCover();
optional<UnwrappedTileID> next();
@@ -33,9 +33,9 @@ private:
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);
+std::vector<UnwrappedTileID> tileCover(const TransformState&, uint8_t z);
+std::vector<UnwrappedTileID> tileCover(const LatLngBounds&, uint8_t z);
+std::vector<UnwrappedTileID> tileCover(const Geometry<double>&, uint8_t z);
// Compute only the count of tiles needed for tileCover
uint64_t tileCount(const LatLngBounds&, uint8_t z);
diff --git a/test/fixtures/local_glyphs/mixed.json b/test/fixtures/local_glyphs/mixed.json
index b982fd9641..3d943084e4 100644
--- a/test/fixtures/local_glyphs/mixed.json
+++ b/test/fixtures/local_glyphs/mixed.json
@@ -68,7 +68,7 @@
{
"type": "Feature",
"properties": {
- "name": "身什戰アあ"
+ "name": "안녕 세상 KR"
},
"geometry": {
"type": "LineString",
@@ -144,7 +144,7 @@
{
"type": "Feature",
"properties": {
- "name": "8身什戰アあ"
+ "name": "안녕 세상8"
},
"geometry": {
"type": "LineString",
diff --git a/test/fixtures/local_glyphs/no_local/expected.png b/test/fixtures/local_glyphs/no_local/expected.png
index 77552c32fa..7e2049518b 100644
--- a/test/fixtures/local_glyphs/no_local/expected.png
+++ b/test/fixtures/local_glyphs/no_local/expected.png
Binary files differ
diff --git a/test/fixtures/local_glyphs/no_local_with_content_insets/expected.png b/test/fixtures/local_glyphs/no_local_with_content_insets/expected.png
index 52ef264590..da5e6957dd 100644
--- a/test/fixtures/local_glyphs/no_local_with_content_insets/expected.png
+++ b/test/fixtures/local_glyphs/no_local_with_content_insets/expected.png
Binary files differ
diff --git a/test/fixtures/local_glyphs/no_local_with_content_insets_and_pitch/expected.png b/test/fixtures/local_glyphs/no_local_with_content_insets_and_pitch/expected.png
index a1aa5fcb52..2501471562 100644
--- a/test/fixtures/local_glyphs/no_local_with_content_insets_and_pitch/expected.png
+++ b/test/fixtures/local_glyphs/no_local_with_content_insets_and_pitch/expected.png
Binary files differ
diff --git a/test/fixtures/local_glyphs/noto_sans_cjk_kr_regular_qt/expected.png b/test/fixtures/local_glyphs/noto_sans_cjk_kr_regular_qt/expected.png
new file mode 100644
index 0000000000..0d69075172
--- /dev/null
+++ b/test/fixtures/local_glyphs/noto_sans_cjk_kr_regular_qt/expected.png
Binary files differ
diff --git a/test/fixtures/local_glyphs/ping_fang/expected.png b/test/fixtures/local_glyphs/ping_fang/expected.png
index 44c24c276a..2ec62e1bc6 100644
--- a/test/fixtures/local_glyphs/ping_fang/expected.png
+++ b/test/fixtures/local_glyphs/ping_fang/expected.png
Binary files differ
diff --git a/test/fixtures/local_glyphs/ping_fang_qt/expected.png b/test/fixtures/local_glyphs/ping_fang_qt/expected.png
index 465bce5b77..0ede615967 100644
--- a/test/fixtures/local_glyphs/ping_fang_qt/expected.png
+++ b/test/fixtures/local_glyphs/ping_fang_qt/expected.png
Binary files differ
diff --git a/test/fixtures/resources/glyphs-12244-12543.pbf b/test/fixtures/resources/glyphs-12244-12543.pbf
new file mode 100644
index 0000000000..cbc4a52056
--- /dev/null
+++ b/test/fixtures/resources/glyphs-12244-12543.pbf
Binary files differ
diff --git a/test/gl/bucket.test.cpp b/test/gl/bucket.test.cpp
index cd21a027a2..f30606ee42 100644
--- a/test/gl/bucket.test.cpp
+++ b/test/gl/bucket.test.cpp
@@ -115,15 +115,15 @@ TEST(Buckets, SymbolBucket) {
gfx::BackendScope scope { backend };
auto layout = makeMutable<style::SymbolLayoutProperties::PossiblyEvaluated>();
- bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
std::string bucketLeaderID = "test";
std::vector<SymbolInstance> symbolInstances;
gl::Context context{ backend };
- SymbolBucket bucket { std::move(layout), {}, 16.0f, 1.0f, 0, sdfIcons, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), 1.0f, false, {}};
+ SymbolBucket bucket { std::move(layout), {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(symbolInstances), 1.0f, false, {}};
ASSERT_FALSE(bucket.hasIconData());
+ ASSERT_FALSE(bucket.hasSdfIconData());
ASSERT_FALSE(bucket.hasTextData());
ASSERT_FALSE(bucket.hasCollisionBoxData());
ASSERT_FALSE(bucket.hasData());
diff --git a/test/gl/context.test.cpp b/test/gl/context.test.cpp
index 4b6bad6f65..770434c5be 100644
--- a/test/gl/context.test.cpp
+++ b/test/gl/context.test.cpp
@@ -91,7 +91,7 @@ TEST(GLContextMode, Shared) {
util::RunLoop loop;
- HeadlessFrontend frontend { 1, {}, gfx::ContextMode::Shared };
+ HeadlessFrontend frontend { 1, gfx::ContextMode::Shared };
Map map(frontend, MapObserver::nullObserver(),
MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize()),
diff --git a/test/src/mbgl/test/stub_map_observer.hpp b/test/src/mbgl/test/stub_map_observer.hpp
index 00a039e732..da150ea83c 100644
--- a/test/src/mbgl/test/stub_map_observer.hpp
+++ b/test/src/mbgl/test/stub_map_observer.hpp
@@ -32,7 +32,7 @@ public:
}
}
- void onDidFinishRenderingFrame(RenderMode mode) final {
+ void onDidFinishRenderingFrame(RenderMode mode, bool) final {
if (didFinishRenderingFrameCallback) {
didFinishRenderingFrameCallback(mode);
}
diff --git a/test/storage/offline_database.test.cpp b/test/storage/offline_database.test.cpp
index 3f6db527d4..24234b0624 100644
--- a/test/storage/offline_database.test.cpp
+++ b/test/storage/offline_database.test.cpp
@@ -1093,8 +1093,8 @@ TEST(OfflineDatabase, HasRegionResource) {
auto region = db.createRegion(definition, OfflineRegionMetadata());
ASSERT_TRUE(region);
- EXPECT_FALSE(bool(db.hasRegionResource(region->getID(), Resource::style("http://example.com/1"))));
- EXPECT_FALSE(bool(db.hasRegionResource(region->getID(), Resource::style("http://example.com/20"))));
+ EXPECT_FALSE(bool(db.hasRegionResource(Resource::style("http://example.com/1"))));
+ EXPECT_FALSE(bool(db.hasRegionResource(Resource::style("http://example.com/20"))));
Response response;
response.data = randomString(1024);
@@ -1103,9 +1103,9 @@ TEST(OfflineDatabase, HasRegionResource) {
db.putRegionResource(region->getID(), Resource::style("http://example.com/"s + util::toString(i)), response);
}
- EXPECT_TRUE(bool(db.hasRegionResource(region->getID(), Resource::style("http://example.com/1"))));
- EXPECT_TRUE(bool(db.hasRegionResource(region->getID(), Resource::style("http://example.com/20"))));
- EXPECT_EQ(1024, *(db.hasRegionResource(region->getID(), Resource::style("http://example.com/20"))));
+ EXPECT_TRUE(bool(db.hasRegionResource(Resource::style("http://example.com/1"))));
+ EXPECT_TRUE(bool(db.hasRegionResource(Resource::style("http://example.com/20"))));
+ EXPECT_EQ(1024, *(db.hasRegionResource(Resource::style("http://example.com/20"))));
EXPECT_EQ(0u, log.uncheckedCount());
}
@@ -1131,16 +1131,16 @@ TEST(OfflineDatabase, HasRegionResourceTile) {
response.data = std::make_shared<std::string>("first");
- EXPECT_FALSE(bool(db.hasRegionResource(region->getID(), resource)));
+ EXPECT_FALSE(bool(db.hasRegionResource(resource)));
db.putRegionResource(region->getID(), resource, response);
- EXPECT_TRUE(bool(db.hasRegionResource(region->getID(), resource)));
- EXPECT_EQ(5, *(db.hasRegionResource(region->getID(), resource)));
+ EXPECT_TRUE(bool(db.hasRegionResource(resource)));
+ EXPECT_EQ(5, *(db.hasRegionResource(resource)));
auto anotherRegion = db.createRegion(definition, OfflineRegionMetadata());
ASSERT_TRUE(anotherRegion);
EXPECT_LT(region->getID(), anotherRegion->getID());
- EXPECT_TRUE(bool(db.hasRegionResource(anotherRegion->getID(), resource)));
- EXPECT_EQ(5, *(db.hasRegionResource(anotherRegion->getID(), resource)));
+ EXPECT_TRUE(bool(db.hasRegionResource(resource)));
+ EXPECT_EQ(5, *(db.hasRegionResource(resource)));
EXPECT_EQ(0u, log.uncheckedCount());
@@ -1488,12 +1488,12 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(DisallowedIO)) {
EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't update region metadata: authorization denied")));
EXPECT_EQ(0u, log.uncheckedCount());
- EXPECT_EQ(nullopt, db.getRegionResource(region->getID(), fixture::resource));
+ EXPECT_EQ(nullopt, db.getRegionResource(fixture::resource));
EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't update timestamp: authorization denied")));
EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't read region resource: authorization denied")));
EXPECT_EQ(0u, log.uncheckedCount());
- EXPECT_EQ(nullopt, db.hasRegionResource(region->getID(), fixture::resource));
+ EXPECT_EQ(nullopt, db.hasRegionResource(fixture::resource));
EXPECT_EQ(1u, log.count(warning(ResultCode::Auth, "Can't query region resource: authorization denied")));
EXPECT_EQ(0u, log.uncheckedCount());
@@ -1566,7 +1566,7 @@ TEST(OfflineDatabase, TEST_REQUIRES_WRITE(MergeDatabaseWithSingleRegion_Update))
EXPECT_EQ(1u, status->completedTileCount);
//Verify the modified timestamp matches the tile in the sideloaded db.
- auto updatedTile = db.getRegionResource(regionId,
+ auto updatedTile = db.getRegionResource(
Resource::tile("mapbox://tiles/mapbox.satellite/{z}/{x}/{y}{ratio}.webp",
1, 0, 0, 1, Tileset::Scheme::XYZ));
EXPECT_EQ(Timestamp{ Seconds(1520409600) }, *(updatedTile->first.modified));
@@ -1586,8 +1586,7 @@ TEST(OfflineDatabase, MergeDatabaseWithSingleRegion_NoUpdate) {
EXPECT_EQ(1u, result->size());
EXPECT_EQ(1u, db.listRegions()->size());
- auto regionId = result->front().getID();
- auto updatedTile = db.getRegionResource(regionId,
+ auto updatedTile = db.getRegionResource(
Resource::tile("mapbox://tiles/mapbox.satellite/{z}/{x}/{y}{ratio}.webp",
1, 0, 0, 1, Tileset::Scheme::XYZ));
@@ -1601,14 +1600,13 @@ TEST(OfflineDatabase, MergeDatabaseWithSingleRegion_AmbientTiles) {
OfflineDatabase db(":memory:");
auto result = db.mergeDatabase(filename_sideload);
- auto regionId = result->front().getID();
- EXPECT_TRUE(bool(db.hasRegionResource(regionId, Resource::tile("mapbox://tiles/mapbox.satellite/{z}/{x}/{y}{ratio}.png", 1, 0, 0, 1, Tileset::Scheme::XYZ))));
+ EXPECT_TRUE(bool(db.hasRegionResource(Resource::tile("mapbox://tiles/mapbox.satellite/{z}/{x}/{y}{ratio}.png", 1, 0, 0, 1, Tileset::Scheme::XYZ))));
//Ambient resources should not be copied
- EXPECT_FALSE(bool(db.hasRegionResource(regionId, Resource::style("mapbox://styles/mapbox/streets-v9"))));
- EXPECT_FALSE(bool(db.hasRegionResource(regionId, Resource::tile("mapbox://tiles/mapbox.satellite/{z}/{x}/{y}{ratio}.png", 1, 0, 1, 2, Tileset::Scheme::XYZ))));
- EXPECT_FALSE(bool(db.hasRegionResource(regionId, Resource::tile("mapbox://tiles/mapbox.satellite/{z}/{x}/{y}{ratio}.png", 1, 1, 1, 2, Tileset::Scheme::XYZ))));
+ EXPECT_FALSE(bool(db.hasRegionResource(Resource::style("mapbox://styles/mapbox/streets-v9"))));
+ EXPECT_FALSE(bool(db.hasRegionResource(Resource::tile("mapbox://tiles/mapbox.satellite/{z}/{x}/{y}{ratio}.png", 1, 0, 1, 2, Tileset::Scheme::XYZ))));
+ EXPECT_FALSE(bool(db.hasRegionResource(Resource::tile("mapbox://tiles/mapbox.satellite/{z}/{x}/{y}{ratio}.png", 1, 1, 1, 2, Tileset::Scheme::XYZ))));
}
TEST(OfflineDatabase, MergeDatabaseWithMultipleRegions_New) {
diff --git a/test/storage/offline_download.test.cpp b/test/storage/offline_download.test.cpp
index 9cdafaaf1e..2256e04bf1 100644
--- a/test/storage/offline_download.test.cpp
+++ b/test/storage/offline_download.test.cpp
@@ -150,6 +150,7 @@ TEST(OfflineDownload, InlineSource) {
observer->statusChangedFn = [&] (OfflineRegionStatus status) {
if (status.complete()) {
+ EXPECT_EQ(1u, status.completedTileCount);
EXPECT_EQ(2u, status.completedResourceCount);
EXPECT_EQ(test.size, status.completedResourceSize);
EXPECT_TRUE(status.requiredResourceCountIsPrecise);
@@ -253,6 +254,7 @@ TEST(OfflineDownload, Activate) {
observer->statusChangedFn = [&] (OfflineRegionStatus status) {
if (status.complete()) {
+ EXPECT_EQ(status.completedTileCount, status.requiredTileCount);
EXPECT_EQ(264u, status.completedResourceCount); // 256 glyphs, 2 sprite images, 2 sprite jsons, 1 tile, 1 style, source, image
EXPECT_EQ(test.size, status.completedResourceSize);
@@ -260,6 +262,7 @@ TEST(OfflineDownload, Activate) {
OfflineRegionStatus computedStatus = download.getStatus();
EXPECT_EQ(OfflineRegionDownloadState::Inactive, computedStatus.downloadState);
EXPECT_EQ(status.requiredResourceCount, computedStatus.requiredResourceCount);
+ EXPECT_EQ(status.requiredTileCount, computedStatus.requiredTileCount);
EXPECT_EQ(status.completedResourceCount, computedStatus.completedResourceCount);
EXPECT_EQ(status.completedResourceSize, computedStatus.completedResourceSize);
EXPECT_EQ(status.completedTileCount, computedStatus.completedTileCount);
@@ -330,6 +333,7 @@ TEST(OfflineDownload, ExcludeIdeographs) {
observer->statusChangedFn = [&] (OfflineRegionStatus status) {
if (status.complete()) {
+ EXPECT_EQ(status.completedTileCount, status.requiredTileCount);
EXPECT_EQ(138u, status.completedResourceCount); // 130 glyphs, 2 sprite images, 2 sprite jsons, 1 tile, 1 style, source, image
EXPECT_EQ(test.size, status.completedResourceSize);
@@ -337,6 +341,7 @@ TEST(OfflineDownload, ExcludeIdeographs) {
OfflineRegionStatus computedStatus = download.getStatus();
EXPECT_EQ(OfflineRegionDownloadState::Inactive, computedStatus.downloadState);
EXPECT_EQ(status.requiredResourceCount, computedStatus.requiredResourceCount);
+ EXPECT_EQ(status.requiredTileCount, computedStatus.requiredTileCount);
EXPECT_EQ(status.completedResourceCount, computedStatus.completedResourceCount);
EXPECT_EQ(status.completedResourceSize, computedStatus.completedResourceSize);
EXPECT_EQ(status.completedTileCount, computedStatus.completedTileCount);
@@ -391,6 +396,8 @@ TEST(OfflineDownload, GetStatusNoResources) {
EXPECT_EQ(0u, status.completedResourceCount);
EXPECT_EQ(0u, status.completedResourceSize);
EXPECT_EQ(1u, status.requiredResourceCount);
+ EXPECT_EQ(0u, status.completedTileCount);
+ EXPECT_EQ(0u, status.requiredTileCount);
EXPECT_FALSE(status.requiredResourceCountIsPrecise);
EXPECT_FALSE(status.complete());
}
@@ -414,6 +421,8 @@ TEST(OfflineDownload, GetStatusStyleComplete) {
EXPECT_EQ(1u, status.completedResourceCount);
EXPECT_EQ(test.size, status.completedResourceSize);
EXPECT_EQ(263u, status.requiredResourceCount);
+ EXPECT_EQ(0u, status.completedTileCount);
+ EXPECT_EQ(0u, status.requiredTileCount);
EXPECT_FALSE(status.requiredResourceCountIsPrecise);
EXPECT_FALSE(status.complete());
}
@@ -441,6 +450,8 @@ TEST(OfflineDownload, GetStatusStyleAndSourceComplete) {
EXPECT_EQ(2u, status.completedResourceCount);
EXPECT_EQ(test.size, status.completedResourceSize);
EXPECT_EQ(264u, status.requiredResourceCount);
+ EXPECT_EQ(0u, status.completedTileCount);
+ EXPECT_EQ(1u, status.requiredTileCount);
EXPECT_TRUE(status.requiredResourceCountIsPrecise);
EXPECT_FALSE(status.complete());
}
diff --git a/test/text/cross_tile_symbol_index.test.cpp b/test/text/cross_tile_symbol_index.test.cpp
index a1385dfa8a..11d6fc7de3 100644
--- a/test/text/cross_tile_symbol_index.test.cpp
+++ b/test/text/cross_tile_symbol_index.test.cpp
@@ -30,7 +30,6 @@ TEST(CrossTileSymbolLayerIndex, addBucket) {
Immutable<style::SymbolLayoutProperties::PossiblyEvaluated> layout =
makeMutable<style::SymbolLayoutProperties::PossiblyEvaluated>();
- bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
std::string bucketLeaderID = "test";
@@ -39,7 +38,7 @@ TEST(CrossTileSymbolLayerIndex, addBucket) {
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, bucketLeaderID, std::move(mainInstances), 1.0f, false, {} };
+ SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances), 1.0f, false, {} };
mainBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(mainID, mainBucket, maxCrossTileID);
@@ -54,7 +53,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, bucketLeaderID, std::move(childInstances), 1.0f, false, {} };
+ SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances), 1.0f, false, {} };
childBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(childID, childBucket, maxCrossTileID);
@@ -70,7 +69,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, bucketLeaderID, std::move(parentInstances), 1.0f, false, {} };
+ SymbolBucket parentBucket { layout, {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(parentInstances), 1.0f, false, {} };
parentBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(parentID, parentBucket, maxCrossTileID);
@@ -86,7 +85,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, bucketLeaderID, std::move(grandchildInstances), 1.0f, false, {} };
+ SymbolBucket grandchildBucket { layout, {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(grandchildInstances), 1.0f, false, {} };
grandchildBucket.bucketInstanceId = ++maxBucketInstanceId;
index.addBucket(grandchildID, grandchildBucket, maxCrossTileID);
@@ -105,7 +104,6 @@ TEST(CrossTileSymbolLayerIndex, resetIDs) {
Immutable<style::SymbolLayoutProperties::PossiblyEvaluated> layout =
makeMutable<style::SymbolLayoutProperties::PossiblyEvaluated>();
- bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
std::string bucketLeaderID = "test";
@@ -113,13 +111,13 @@ TEST(CrossTileSymbolLayerIndex, resetIDs) {
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, bucketLeaderID, std::move(mainInstances), 1.0f, false, {} };
+ SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances), 1.0f, false, {} };
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, bucketLeaderID, std::move(childInstances), 1.0f, false, {} };
+ SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances), 1.0f, false, {} };
childBucket.bucketInstanceId = ++maxBucketInstanceId;
// assigns a new id
@@ -146,7 +144,6 @@ TEST(CrossTileSymbolLayerIndex, noDuplicatesWithinZoomLevel) {
Immutable<style::SymbolLayoutProperties::PossiblyEvaluated> layout =
makeMutable<style::SymbolLayoutProperties::PossiblyEvaluated>();
- bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
std::string bucketLeaderID = "test";
@@ -155,7 +152,7 @@ TEST(CrossTileSymbolLayerIndex, noDuplicatesWithinZoomLevel) {
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, bucketLeaderID, std::move(mainInstances), 1.0f, false, {} };
+ SymbolBucket mainBucket { layout, {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(mainInstances), 1.0f, false, {} };
mainBucket.bucketInstanceId = ++maxBucketInstanceId;
OverscaledTileID childID(7, 0, 7, 16, 16);
@@ -163,7 +160,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, bucketLeaderID, std::move(childInstances), 1.0f, false, {} };
+ SymbolBucket childBucket { layout, {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(childInstances), 1.0f, false, {} };
childBucket.bucketInstanceId = ++maxBucketInstanceId;
// assigns new ids
@@ -185,7 +182,6 @@ TEST(CrossTileSymbolLayerIndex, bucketReplacement) {
Immutable<style::SymbolLayoutProperties::PossiblyEvaluated> layout =
makeMutable<style::SymbolLayoutProperties::PossiblyEvaluated>();
- bool sdfIcons = false;
bool iconsNeedLinear = false;
bool sortFeaturesByY = false;
std::string bucketLeaderID = "test";
@@ -194,14 +190,14 @@ TEST(CrossTileSymbolLayerIndex, bucketReplacement) {
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, bucketLeaderID, std::move(firstInstances), 1.0f, false, {} };
+ SymbolBucket firstBucket { layout, {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(firstInstances), 1.0f, false, {} };
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, bucketLeaderID, std::move(secondInstances), 1.0f, false, {} };
+ SymbolBucket secondBucket { layout, {}, 16.0f, 1.0f, 0, iconsNeedLinear, sortFeaturesByY, bucketLeaderID, std::move(secondInstances), 1.0f, false, {} };
secondBucket.bucketInstanceId = ++maxBucketInstanceId;
// assigns new ids
diff --git a/test/text/glyph_manager.test.cpp b/test/text/glyph_manager.test.cpp
index 1193780631..1e9aef38ed 100644
--- a/test/text/glyph_manager.test.cpp
+++ b/test/text/glyph_manager.test.cpp
@@ -20,7 +20,7 @@ static constexpr const size_t stubBitmapLength = 900;
class StubLocalGlyphRasterizer : public LocalGlyphRasterizer {
public:
bool canRasterizeGlyph(const FontStack&, GlyphID glyphID) override {
- return util::i18n::allowsIdeographicBreaking(glyphID);
+ return util::i18n::allowsFixedWidthGlyphGeneration(glyphID);
}
Glyph rasterizeGlyph(const FontStack&, GlyphID glyphID) override {
@@ -253,6 +253,57 @@ TEST(GlyphManager, LoadLocalCJKGlyph) {
});
}
+TEST(GlyphManager, LoadLocalCJKGlyphAfterLoadingRangeFromURL) {
+ GlyphManagerTest test;
+ int firstGlyphResponse = false;
+
+ test.fileSource.glyphsResponse = [&] (const Resource&) {
+ firstGlyphResponse = true;
+ Response response;
+ response.data = std::make_shared<std::string>(util::read_file("test/fixtures/resources/glyphs-12244-12543.pbf"));
+ return response;
+
+ };
+
+ test.requestor.glyphsAvailable = [&] (GlyphMap glyphs) {
+ const auto& testPositions = glyphs.at(FontStackHasher()({{"Test Stack"}}));
+
+ if (firstGlyphResponse == true) {
+ firstGlyphResponse = false;
+ ASSERT_EQ(testPositions.size(), 1u);
+ ASSERT_EQ(testPositions.count(u'々'), 1u);
+
+ //Katakana letter te, should be locally rasterized
+ // instead of using the glyph recieved from the range
+ // for the ideagraphic mark
+ test.glyphManager.getGlyphs(test.requestor,
+ GlyphDependencies {
+ {{{"Test Stack"}}, {u'テ'}} // 0x30c6
+ },
+ test.fileSource);
+ } else {
+ ASSERT_EQ(testPositions.size(), 1u);
+ ASSERT_EQ(testPositions.count(u'テ'), 1u);
+
+ Immutable<Glyph> glyph = *testPositions.at(u'テ');
+ EXPECT_EQ(glyph->id, u'テ');
+ EXPECT_EQ(glyph->metrics.width, 24ul);
+ EXPECT_EQ(glyph->metrics.height, 24ul);
+ EXPECT_EQ(glyph->metrics.left, 0);
+ EXPECT_EQ(glyph->metrics.top, -8);
+ EXPECT_EQ(glyph->metrics.advance, 24ul);
+ EXPECT_EQ(glyph->bitmap.size, Size(30, 30));
+
+ test.end();
+ }
+ };
+
+ test.run(
+ "test/fixtures/resources/glyphs-12244-12543.pbf",
+ GlyphDependencies {
+ {{{"Test Stack"}}, {u'々'}} //0x3005
+ });
+}
TEST(GlyphManager, LoadingInvalid) {
GlyphManagerTest test;
diff --git a/test/text/local_glyph_rasterizer.test.cpp b/test/text/local_glyph_rasterizer.test.cpp
index 86dc87b6c7..2722ee5849 100644
--- a/test/text/local_glyph_rasterizer.test.cpp
+++ b/test/text/local_glyph_rasterizer.test.cpp
@@ -33,7 +33,7 @@ namespace {
class LocalGlyphRasterizerTest {
public:
LocalGlyphRasterizerTest(const optional<std::string> fontFamily)
- : frontend(1, optional<std::string>(), gfx::ContextMode::Unique, fontFamily)
+ : frontend(1, gfx::ContextMode::Unique, fontFamily)
{
}
@@ -43,7 +43,7 @@ public:
MapAdapter map { frontend, MapObserver::nullObserver(), fileSource,
MapOptions().withMapMode(MapMode::Static).withSize(frontend.getSize())};
- void checkRendering(const char * name, double imageMatchPixelsThreshold = 0.05, double pixelMatchThreshold = 0.1) {
+ void checkRendering(const char * name, double imageMatchPixelsThreshold = 0.015, double pixelMatchThreshold = 0.1) {
test::checkImage(std::string("test/fixtures/local_glyphs/") + name,
frontend.render(map), imageMatchPixelsThreshold, pixelMatchThreshold);
}
@@ -64,7 +64,7 @@ TEST(LocalGlyphRasterizer, PingFang) {
return response;
};
test.map.getStyle().loadJSON(util::read_file("test/fixtures/local_glyphs/mixed.json"));
-#if defined(__APPLE__)
+#if defined(__APPLE__) && !defined(__QT__)
test.checkRendering("ping_fang");
#elif defined(__QT__)
test.checkRendering("ping_fang_qt");
@@ -73,6 +73,22 @@ TEST(LocalGlyphRasterizer, PingFang) {
#endif // defined(__APPLE__)
+#if defined(__linux__) && defined(__QT__)
+TEST(LocalGlyphRasterizer, NotoSansCJK) {
+ LocalGlyphRasterizerTest test(std::string("Noto Sans CJK KR Regular"));
+
+ test.fileSource->glyphsResponse = [&] (const Resource& resource) {
+ EXPECT_EQ(Resource::Kind::Glyphs, resource.kind);
+ Response response;
+ response.data = std::make_shared<std::string>(util::read_file("test/fixtures/resources/glyphs.pbf"));
+ return response;
+ };
+
+ test.map.getStyle().loadJSON(util::read_file("test/fixtures/local_glyphs/mixed.json"));
+ test.checkRendering("noto_sans_cjk_kr_regular_qt");
+}
+#endif // defined(__linux__) && defined(__QT__)
+
TEST(LocalGlyphRasterizer, NoLocal) {
// Expectation: without any local fonts set, and without any CJK glyphs provided,
// the output should just contain basic latin characters.
diff --git a/test/util/tile_cover.test.cpp b/test/util/tile_cover.test.cpp
index e35e6e2e99..af9f0c4884 100644
--- a/test/util/tile_cover.test.cpp
+++ b/test/util/tile_cover.test.cpp
@@ -43,6 +43,20 @@ TEST(TileCover, Pitch) {
util::tileCover(transform.getState(), 2));
}
+TEST(TileCover, PitchIssue15442) {
+ Transform transform;
+ transform.resize({ 412, 691 });
+
+ transform.jumpTo(CameraOptions().withCenter(LatLng { 59.116898740996106, 91.565660781803615, })
+ .withZoom(2.0551126748417214).withBearing(0.74963938256567264 * util::RAD2DEG)
+ .withPitch(1.0471975511965976 * util::RAD2DEG));
+
+ EXPECT_EQ((std::vector<UnwrappedTileID>{
+ { 2, 3, 1 }, { 2, 2, 1 }, { 2, 3, 0 }, { 2, 2, 0 }, { 1, { 2, 0, 0 } }, { 1, { 2, 1, 0 } }
+ }),
+ util::tileCover(transform.getState(), 2));
+}
+
TEST(TileCover, PitchOverAllowedByContentInsets) {
Transform transform;
transform.resize({ 512, 512 });