summaryrefslogtreecommitdiff
path: root/platform
diff options
context:
space:
mode:
Diffstat (limited to 'platform')
-rw-r--r--platform/android/CHANGELOG.md4
-rw-r--r--platform/android/MapboxGLAndroidSDK/build.gradle7
-rw-r--r--platform/android/MapboxGLAndroidSDK/gradle-tests-staticblockremover.gradle59
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java15
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java1
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java87
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java86
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java449
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java25
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java19
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java267
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java39
-rwxr-xr-xplatform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/NativeMapView.java33
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java104
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java105
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java22
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java45
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java4
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java3
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java10
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java137
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/constants/AppConstant.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/constants/AppConstant.java)2
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java81
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java)0
-rw-r--r--platform/android/MapboxGLAndroidSDK/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker (renamed from platform/android/MapboxGLAndroidSDKTestApp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker)0
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/build.gradle6
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java112
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml11
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java17
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/AnimatedImageSourceActivity.java132
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java37
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_0.pngbin0 -> 172489 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_1.pngbin0 -> 177163 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_2.pngbin0 -> 179236 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_3.pngbin0 -> 177074 bytes
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_image_source.xml29
-rw-r--r--platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml2
-rw-r--r--platform/android/bitrise.yml235
-rw-r--r--platform/android/config.cmake4
-rw-r--r--platform/android/src/asset_manager_file_source.cpp18
-rw-r--r--platform/android/src/asset_manager_file_source.hpp5
-rw-r--r--platform/android/src/conversion/constant.hpp1
-rw-r--r--platform/android/src/file_source.cpp22
-rw-r--r--platform/android/src/file_source.hpp8
-rw-r--r--platform/android/src/geometry/lat_lng_quad.cpp39
-rw-r--r--platform/android/src/geometry/lat_lng_quad.hpp30
-rwxr-xr-xplatform/android/src/jni.cpp2
-rwxr-xr-xplatform/android/src/native_map_view.cpp89
-rwxr-xr-xplatform/android/src/native_map_view.hpp9
-rw-r--r--platform/android/src/run_loop.cpp13
-rw-r--r--platform/android/src/style/android_conversion.hpp9
-rw-r--r--platform/android/src/style/conversion/latlngquad.hpp24
-rw-r--r--platform/android/src/style/conversion/transition_options.hpp1
-rw-r--r--platform/android/src/style/layers/custom_layer.cpp4
-rw-r--r--platform/android/src/style/layers/custom_layer.hpp2
-rw-r--r--platform/android/src/style/layers/layer.cpp96
-rw-r--r--platform/android/src/style/layers/layers.cpp82
-rw-r--r--platform/android/src/style/sources/image_source.cpp73
-rw-r--r--platform/android/src/style/sources/image_source.hpp38
-rw-r--r--platform/android/src/style/sources/source.cpp3
-rw-r--r--platform/android/src/style/sources/sources.cpp5
-rw-r--r--platform/darwin/docs/guides/For Style Authors.md.ejs10
-rw-r--r--platform/darwin/src/MGLCircleStyleLayer.h10
-rw-r--r--platform/darwin/src/MGLConversion.h8
-rw-r--r--platform/darwin/src/MGLFillExtrusionStyleLayer.h6
-rw-r--r--platform/darwin/src/MGLFillStyleLayer.h5
-rw-r--r--platform/darwin/src/MGLGeometry.h54
-rw-r--r--platform/darwin/src/MGLGeometry_Private.h15
-rw-r--r--platform/darwin/src/MGLImageSource.h94
-rw-r--r--platform/darwin/src/MGLImageSource.mm93
-rw-r--r--platform/darwin/src/MGLLight.h2
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.h19
-rw-r--r--platform/darwin/src/MGLLineStyleLayer.mm6
-rw-r--r--platform/darwin/src/MGLOfflineStorage.h2
-rw-r--r--platform/darwin/src/MGLOfflineStorage.mm19
-rw-r--r--platform/darwin/src/MGLOpenGLStyleLayer.h3
-rw-r--r--platform/darwin/src/MGLOpenGLStyleLayer.mm37
-rw-r--r--platform/darwin/src/MGLRasterStyleLayer.h3
-rw-r--r--platform/darwin/src/MGLShapeSource.mm5
-rw-r--r--platform/darwin/src/MGLSource.h2
-rw-r--r--platform/darwin/src/MGLSource.mm22
-rw-r--r--platform/darwin/src/MGLSource_Private.h20
-rw-r--r--platform/darwin/src/MGLStyle.h85
-rw-r--r--platform/darwin/src/MGLStyle.mm120
-rw-r--r--platform/darwin/src/MGLStyleLayer.mm18
-rw-r--r--platform/darwin/src/MGLStyleLayer_Private.h6
-rw-r--r--platform/darwin/src/MGLStyle_Private.h9
-rw-r--r--platform/darwin/src/MGLSymbolStyleLayer.h16
-rw-r--r--platform/darwin/src/MGLVectorSource.mm5
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.h14
-rw-r--r--platform/darwin/src/NSValue+MGLAdditions.m10
-rw-r--r--platform/darwin/src/nsthread.mm3
-rw-r--r--platform/darwin/test/MGLDocumentationExampleTests.swift14
-rw-r--r--platform/darwin/test/MGLGeometryTests.mm19
-rw-r--r--platform/darwin/test/MGLImageSourceTests.m42
-rw-r--r--platform/darwin/test/MGLLightTest.mm20
-rw-r--r--platform/darwin/test/MGLLightTest.mm.ejs10
-rw-r--r--platform/darwin/test/MGLLineStyleLayerTests.mm30
-rw-r--r--platform/darwin/test/MGLStyleTests.mm18
-rw-r--r--platform/darwin/test/Media.xcassets/RadarImage.imageset/Contents.json21
-rw-r--r--platform/darwin/test/Media.xcassets/RadarImage.imageset/radar.pngbin0 -> 44094 bytes
-rw-r--r--platform/default/asset_file_source.cpp17
-rw-r--r--platform/default/async_task.cpp2
-rw-r--r--platform/default/bidi.cpp6
-rw-r--r--platform/default/default_file_source.cpp165
-rw-r--r--platform/default/image.cpp2
-rw-r--r--platform/default/jpeg_reader.cpp8
-rw-r--r--platform/default/local_file_source.cpp15
-rw-r--r--platform/default/mbgl/gl/headless_backend.cpp3
-rw-r--r--platform/default/mbgl/gl/headless_backend.hpp2
-rw-r--r--platform/default/mbgl/gl/offscreen_view.cpp1
-rw-r--r--platform/default/mbgl/gl/offscreen_view.hpp2
-rw-r--r--platform/default/mbgl/storage/offline_download.cpp85
-rw-r--r--platform/default/online_file_source.cpp44
-rw-r--r--platform/default/png_reader.cpp2
-rw-r--r--platform/default/sqlite3.cpp8
-rw-r--r--platform/default/timer.cpp2
-rw-r--r--platform/glfw/glfw_view.cpp129
-rw-r--r--platform/glfw/glfw_view.hpp9
-rw-r--r--platform/glfw/main.cpp33
-rw-r--r--platform/glfw/ny_route.hpp104
-rw-r--r--platform/ios/CHANGELOG.md8
-rw-r--r--platform/ios/app/Info.plist13
-rw-r--r--platform/ios/app/MBXViewController.m80
-rw-r--r--platform/ios/docs/guides/Adding Points to a Map.md1
-rw-r--r--platform/ios/docs/guides/For Style Authors.md10
-rw-r--r--platform/ios/ios.xcodeproj/project.pbxproj23
-rw-r--r--platform/ios/ios.xcodeproj/xcshareddata/xcschemes/bench.xcscheme2
-rw-r--r--platform/ios/jazzy.yml5
-rw-r--r--platform/ios/src/MGLMapView.h29
-rw-r--r--platform/ios/src/MGLMapView.mm79
-rw-r--r--platform/ios/src/Mapbox.h1
-rw-r--r--platform/ios/src/UIImage+MGLAdditions.h4
-rw-r--r--platform/ios/src/UIImage+MGLAdditions.mm14
m---------platform/ios/vendor/SMCalloutView0
-rwxr-xr-xplatform/linux/scripts/coveralls.sh15
-rw-r--r--platform/linux/src/headless_backend_glx.cpp8
-rw-r--r--platform/linux/src/headless_display_glx.cpp5
-rw-r--r--platform/macos/CHANGELOG.md9
-rw-r--r--platform/macos/app/Assets.xcassets/Radar/Contents.json6
-rw-r--r--platform/macos/app/Assets.xcassets/Radar/southeast_0.imageset/Contents.json21
-rw-r--r--platform/macos/app/Assets.xcassets/Radar/southeast_0.imageset/southeast_radar_0.pngbin0 -> 172489 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/Radar/southeast_1.imageset/Contents.json21
-rw-r--r--platform/macos/app/Assets.xcassets/Radar/southeast_1.imageset/southeast_radar_1.pngbin0 -> 177163 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/Radar/southeast_2.imageset/Contents.json21
-rw-r--r--platform/macos/app/Assets.xcassets/Radar/southeast_2.imageset/southeast_radar_2.pngbin0 -> 179236 bytes
-rw-r--r--platform/macos/app/Assets.xcassets/Radar/southeast_3.imageset/Contents.json21
-rw-r--r--platform/macos/app/Assets.xcassets/Radar/southeast_3.imageset/southeast_radar_3.pngbin0 -> 177074 bytes
-rw-r--r--platform/macos/app/Base.lproj/MainMenu.xib6
-rw-r--r--platform/macos/app/MapDocument.m90
-rw-r--r--platform/macos/docs/guides/For Style Authors.md10
-rw-r--r--platform/macos/macos.xcodeproj/project.pbxproj12
-rw-r--r--platform/macos/src/MGLMapView.h9
-rw-r--r--platform/macos/src/MGLMapView.mm70
-rw-r--r--platform/macos/src/Mapbox.h1
-rw-r--r--platform/macos/src/NSImage+MGLAdditions.h4
-rw-r--r--platform/macos/src/NSImage+MGLAdditions.mm24
-rw-r--r--platform/node/CHANGELOG.md13
-rw-r--r--platform/node/README.md6
-rwxr-xr-xplatform/node/scripts/after_success.sh2
-rw-r--r--platform/node/src/node_conversion.hpp8
-rw-r--r--platform/node/src/node_map.cpp60
-rw-r--r--platform/node/src/node_map.hpp1
-rw-r--r--platform/node/test/js/map.test.js1
-rw-r--r--platform/node/test/suite_implementation.js7
-rw-r--r--platform/qt/app/mapwindow.cpp32
-rw-r--r--platform/qt/app/mapwindow.hpp1
-rw-r--r--platform/qt/include/qmapbox.hpp6
-rw-r--r--platform/qt/include/qmapboxgl.hpp12
-rw-r--r--platform/qt/src/qmapbox.cpp10
-rw-r--r--platform/qt/src/qmapboxgl.cpp155
-rw-r--r--platform/qt/src/qt_conversion.hpp7
197 files changed, 3562 insertions, 1715 deletions
diff --git a/platform/android/CHANGELOG.md b/platform/android/CHANGELOG.md
index 6d4bb46357..fa54b1e3ed 100644
--- a/platform/android/CHANGELOG.md
+++ b/platform/android/CHANGELOG.md
@@ -2,6 +2,10 @@
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.
+## 5.2.0 - TBA
+
+* Add support for ImageSource [#9110](https://github.com/mapbox/mapbox-gl-native/pull/9110)
+
## 5.1.0 - June 30, 2017
* Update to MAS 2.1.3 [#9402](https://github.com/mapbox/mapbox-gl-native/pull/9402)
diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle
index 018294d462..8b92fa1af2 100644
--- a/platform/android/MapboxGLAndroidSDK/build.gradle
+++ b/platform/android/MapboxGLAndroidSDK/build.gradle
@@ -9,6 +9,8 @@ dependencies {
compile(rootProject.ext.dep.lost) {
exclude group: 'com.google.guava'
}
+ testCompile rootProject.ext.dep.junit
+ testCompile rootProject.ext.dep.mockito
// Mapbox Android Services (GeoJSON support)
compile(rootProject.ext.dep.mapboxJavaGeoJSON) {
@@ -118,6 +120,10 @@ android {
warningsAsErrors true
}
+ testOptions {
+ unitTests.returnDefaultValues = true
+ }
+
buildTypes {
debug {
jniDebuggable true
@@ -145,3 +151,4 @@ configurations {
apply from: 'gradle-javadoc.gradle'
apply from: 'gradle-publish.gradle'
apply from: 'gradle-checkstyle.gradle'
+apply from: 'gradle-tests-staticblockremover.gradle'
diff --git a/platform/android/MapboxGLAndroidSDK/gradle-tests-staticblockremover.gradle b/platform/android/MapboxGLAndroidSDK/gradle-tests-staticblockremover.gradle
new file mode 100644
index 0000000000..523dc99dd1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/gradle-tests-staticblockremover.gradle
@@ -0,0 +1,59 @@
+buildscript {
+ repositories {
+ mavenCentral()
+ mavenLocal()
+ }
+
+ dependencies {
+ classpath 'com.darylteo.gradle:javassist-plugin:0.4.1'
+ }
+}
+
+import com.darylteo.gradle.javassist.tasks.TransformationTask
+import com.darylteo.gradle.javassist.transformers.ClassTransformer
+import javassist.CtClass
+import javassist.CtConstructor
+
+class StaticBlockRemover extends ClassTransformer {
+
+ private static final NATIVE_MAP_VIEW = "com.mapbox.mapboxsdk.maps.NativeMapView";
+ private static
+ final NATIVE_CONNECTIVITY_LISTENER = "com.mapbox.mapboxsdk.net.NativeConnectivityListener";
+ private static final OFFLINE_MANAGER = "com.mapbox.mapboxsdk.offline.OfflineManager";
+ private static final OFFLINE_REGION = "com.mapbox.mapboxsdk.offline.OfflineRegion";
+
+ public void applyTransformations(CtClass clazz) throws Exception {
+ if (shouldFilter(clazz)) {
+ CtConstructor constructor = clazz.getClassInitializer()
+ if (constructor != null) {
+ clazz.removeConstructor(constructor)
+ }
+ }
+ }
+
+ public boolean shouldFilter(CtClass clazz) {
+ return hasAStaticBlock(clazz);
+ }
+
+ private boolean hasAStaticBlock(CtClass clazz) {
+ String name = clazz.getName();
+ boolean isNativeMapView = name.equals(NATIVE_MAP_VIEW);
+ boolean isNativeConnectivityListener = name.equals(NATIVE_CONNECTIVITY_LISTENER);
+ boolean isOfflineManager = name.equals(OFFLINE_MANAGER);
+ boolean isOfflineRegion = name.equals(OFFLINE_REGION);
+
+ return isNativeMapView || isNativeConnectivityListener || isOfflineManager || isOfflineRegion;
+ }
+}
+
+task removeStatic(type: TransformationTask) {
+ // TODO Find a better way to get output classes path
+ String fromToDirPath = buildDir.getAbsolutePath() + "/intermediates/classes/debug"
+ from fromToDirPath
+ transformation = new StaticBlockRemover()
+ into fromToDirPath
+}
+
+afterEvaluate {
+ compileDebugUnitTestSources.dependsOn(removeStatic)
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java
new file mode 100644
index 0000000000..8a75176ccd
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/LibraryLoader.java
@@ -0,0 +1,15 @@
+package com.mapbox.mapboxsdk;
+
+/**
+ * Centralises the knowledge about "mapbox-gl" library loading.
+ */
+public class LibraryLoader {
+
+ /**
+ * Loads "libmapbox-gl.so" native shared library.
+ */
+ public static void load() {
+ System.loadLibrary("mapbox-gl");
+ }
+
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
index 6722000be7..3af7921596 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/Mapbox.java
@@ -23,6 +23,7 @@ import com.mapbox.services.android.telemetry.location.LocationEnginePriority;
* connectivity state.
* </p>
*/
+@UiThread
public final class Mapbox {
private static Mapbox INSTANCE;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java
new file mode 100644
index 0000000000..e374eee8f3
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngQuad.java
@@ -0,0 +1,87 @@
+package com.mapbox.mapboxsdk.geometry;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A geographical area representing a non-aligned quadrilateral
+ * <p>
+ * This class does not wrap values to the world bounds
+ * </p>
+ */
+public class LatLngQuad implements Parcelable {
+
+ private final LatLng topLeft;
+ private final LatLng topRight;
+ private final LatLng bottomRight;
+ private final LatLng bottomLeft;
+
+ /**
+ * Construct a new LatLngQuad based on its corners,
+ * in order top left, top right, bottom left, bottom right
+ */
+ public LatLngQuad(final LatLng topLeft, final LatLng topRight, final LatLng bottomRight, final LatLng bottomLeft) {
+ this.topLeft = topLeft;
+ this.topRight = topRight;
+ this.bottomRight = bottomRight;
+ this.bottomLeft = bottomLeft;
+ }
+
+ public LatLng getTopLeft() {
+ return this.topLeft;
+ }
+
+ public LatLng getTopRight() {
+ return this.topRight;
+ }
+
+ public LatLng getBottomRight() {
+ return this.bottomRight;
+ }
+
+ public LatLng getBottomLeft() {
+ return this.bottomLeft;
+ }
+
+ public static final Parcelable.Creator<LatLngQuad> CREATOR = new Parcelable.Creator<LatLngQuad>() {
+ @Override
+ public LatLngQuad createFromParcel(final Parcel in) {
+ return readFromParcel(in);
+ }
+
+ @Override
+ public LatLngQuad[] newArray(final int size) {
+ return new LatLngQuad[size];
+ }
+ };
+
+ @Override
+ public int hashCode() {
+ int code = topLeft.hashCode();
+ code = (code ^ code >>> 31) + topRight.hashCode();
+ code = (code ^ code >>> 31) + bottomRight.hashCode();
+ code = (code ^ code >>> 31) + bottomLeft.hashCode();
+ return code;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(final Parcel out, final int arg1) {
+ topLeft.writeToParcel(out, arg1);
+ topRight.writeToParcel(out, arg1);
+ bottomRight.writeToParcel(out, arg1);
+ bottomLeft.writeToParcel(out, arg1);
+ }
+
+ private static LatLngQuad readFromParcel(final Parcel in) {
+ final LatLng topLeft = new LatLng(in);
+ final LatLng topRight = new LatLng(in);
+ final LatLng bottomRight = new LatLng(in);
+ final LatLng bottomLeft = new LatLng(in);
+ return new LatLngQuad(topLeft, topRight, bottomRight, bottomLeft);
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java
new file mode 100644
index 0000000000..939fadc9c2
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationContainer.java
@@ -0,0 +1,86 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+import android.support.v4.util.LongSparseArray;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Encapsulates {@link Annotation}'s functionality..
+ */
+class AnnotationContainer implements Annotations {
+
+ private final NativeMapView nativeMapView;
+ private final LongSparseArray<Annotation> annotations;
+
+ AnnotationContainer(NativeMapView nativeMapView, LongSparseArray<Annotation> annotations) {
+ this.nativeMapView = nativeMapView;
+ this.annotations = annotations;
+ }
+
+ @Override
+ public Annotation obtainBy(long id) {
+ return annotations.get(id);
+ }
+
+ @Override
+ public List<Annotation> obtainAll() {
+ List<Annotation> annotations = new ArrayList<>();
+ for (int i = 0; i < this.annotations.size(); i++) {
+ annotations.add(this.annotations.get(this.annotations.keyAt(i)));
+ }
+ return annotations;
+ }
+
+ @Override
+ public void removeBy(long id) {
+ if (nativeMapView != null) {
+ nativeMapView.removeAnnotation(id);
+ }
+ annotations.remove(id);
+ }
+
+ @Override
+ public void removeBy(@NonNull Annotation annotation) {
+ long id = annotation.getId();
+ removeBy(id);
+ }
+
+ @Override
+ public void removeBy(@NonNull List<? extends Annotation> annotationList) {
+ int count = annotationList.size();
+ long[] ids = new long[count];
+ for (int i = 0; i < count; i++) {
+ ids[i] = annotationList.get(i).getId();
+ }
+
+ removeNativeAnnotations(ids);
+
+ for (long id : ids) {
+ annotations.remove(id);
+ }
+ }
+
+ @Override
+ public void removeAll() {
+ int count = annotations.size();
+ long[] ids = new long[count];
+ for (int i = 0; i < count; i++) {
+ ids[i] = annotations.keyAt(i);
+ }
+
+ removeNativeAnnotations(ids);
+
+ annotations.clear();
+ }
+
+ private void removeNativeAnnotations(long[] ids) {
+ if (nativeMapView != null) {
+ nativeMapView.removeAnnotations(ids);
+ }
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
index 3694668a7e..7e7947047e 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java
@@ -9,7 +9,6 @@ import android.support.v4.util.LongSparseArray;
import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
-import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.MarkerView;
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
@@ -22,8 +21,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import timber.log.Timber;
-
/**
* Responsible for managing and tracking state of Annotations linked to Map. All events related to
* annotations that occur on {@link MapboxMap} are forwarded to this class.
@@ -42,17 +39,28 @@ class AnnotationManager {
private final IconManager iconManager;
private final InfoWindowManager infoWindowManager = new InfoWindowManager();
private final MarkerViewManager markerViewManager;
- private final LongSparseArray<Annotation> annotations = new LongSparseArray<>();
+ private final LongSparseArray<Annotation> annotationsArray;
private final List<Marker> selectedMarkers = new ArrayList<>();
private MapboxMap mapboxMap;
private MapboxMap.OnMarkerClickListener onMarkerClickListener;
-
- AnnotationManager(NativeMapView view, MapView mapView, MarkerViewManager markerViewManager) {
+ private Annotations annotations;
+ private Markers markers;
+ private Polygons polygons;
+ private Polylines polylines;
+
+ AnnotationManager(NativeMapView view, MapView mapView, LongSparseArray<Annotation> annotationsArray,
+ MarkerViewManager markerViewManager, IconManager iconManager, Annotations annotations,
+ Markers markers, Polygons polygons, Polylines polylines) {
this.nativeMapView = view;
this.mapView = mapView;
- this.iconManager = new IconManager(nativeMapView);
+ this.annotationsArray = annotationsArray;
this.markerViewManager = markerViewManager;
+ this.iconManager = iconManager;
+ this.annotations = annotations;
+ this.markers = markers;
+ this.polygons = polygons;
+ this.polylines = polylines;
if (view != null) {
// null checking needed for unit tests
nativeMapView.addOnMapChangedListener(markerViewManager);
@@ -77,15 +85,15 @@ class AnnotationManager {
//
Annotation getAnnotation(long id) {
- return annotations.get(id);
+ return annotations.obtainBy(id);
}
List<Annotation> getAnnotations() {
- List<Annotation> annotations = new ArrayList<>();
- for (int i = 0; i < this.annotations.size(); i++) {
- annotations.add(this.annotations.get(this.annotations.keyAt(i)));
- }
- return annotations;
+ return annotations.obtainAll();
+ }
+
+ void removeAnnotation(long id) {
+ annotations.removeBy(id);
}
void removeAnnotation(@NonNull Annotation annotation) {
@@ -100,25 +108,11 @@ class AnnotationManager {
markerViewManager.removeMarkerView((MarkerView) marker);
}
}
- long id = annotation.getId();
- if (nativeMapView != null) {
- nativeMapView.removeAnnotation(id);
- }
- annotations.remove(id);
- }
-
- void removeAnnotation(long id) {
- if (nativeMapView != null) {
- nativeMapView.removeAnnotation(id);
- }
- annotations.remove(id);
+ annotations.removeBy(annotation);
}
void removeAnnotations(@NonNull List<? extends Annotation> annotationList) {
- int count = annotationList.size();
- long[] ids = new long[count];
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotationList.get(i);
+ for (Annotation annotation : annotationList) {
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
@@ -130,26 +124,18 @@ class AnnotationManager {
markerViewManager.removeMarkerView((MarkerView) marker);
}
}
- ids[i] = annotationList.get(i).getId();
- }
-
- if (nativeMapView != null) {
- nativeMapView.removeAnnotations(ids);
- }
-
- for (long id : ids) {
- annotations.remove(id);
}
+ annotations.removeBy(annotationList);
}
void removeAnnotations() {
Annotation annotation;
- int count = annotations.size();
+ int count = annotationsArray.size();
long[] ids = new long[count];
selectedMarkers.clear();
for (int i = 0; i < count; i++) {
- ids[i] = annotations.keyAt(i);
- annotation = annotations.get(ids[i]);
+ ids[i] = annotationsArray.keyAt(i);
+ annotation = annotationsArray.get(ids[i]);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.hideInfoWindow();
@@ -158,12 +144,7 @@ class AnnotationManager {
}
}
}
-
- if (nativeMapView != null) {
- nativeMapView.removeAnnotations(ids);
- }
-
- annotations.clear();
+ annotations.removeAll();
}
//
@@ -171,139 +152,86 @@ class AnnotationManager {
//
Marker addMarker(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap) {
- Marker marker = prepareMarker(markerOptions);
- long id = nativeMapView != null ? nativeMapView.addMarker(marker) : 0;
- marker.setMapboxMap(mapboxMap);
- marker.setId(id);
- annotations.put(id, marker);
- return marker;
+ return markers.addBy(markerOptions, mapboxMap);
}
List<Marker> addMarkers(@NonNull List<? extends BaseMarkerOptions> markerOptionsList, @NonNull MapboxMap mapboxMap) {
- int count = markerOptionsList.size();
- List<Marker> markers = new ArrayList<>(count);
- if (count > 0) {
- BaseMarkerOptions markerOptions;
- Marker marker;
- for (int i = 0; i < count; i++) {
- markerOptions = markerOptionsList.get(i);
- marker = prepareMarker(markerOptions);
- markers.add(marker);
- }
-
- if (markers.size() > 0) {
- long[] ids = null;
- if (nativeMapView != null) {
- ids = nativeMapView.addMarkers(markers);
- }
+ return markers.addBy(markerOptionsList, mapboxMap);
+ }
- long id = 0;
- Marker m;
- for (int i = 0; i < markers.size(); i++) {
- m = markers.get(i);
- m.setMapboxMap(mapboxMap);
- if (ids != null) {
- id = ids[i];
- } else {
- // unit test
- id++;
- }
- m.setId(id);
- annotations.put(id, m);
- }
+ void updateMarker(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) {
+ markers.update(updatedMarker, mapboxMap);
+ }
- }
- }
- return markers;
+ List<Marker> getMarkers() {
+ return markers.obtainAll();
}
- private Marker prepareMarker(BaseMarkerOptions markerOptions) {
- Marker marker = markerOptions.getMarker();
- Icon icon = iconManager.loadIconForMarker(marker);
- marker.setTopOffsetPixels(iconManager.getTopOffsetPixelsForIcon(icon));
- return marker;
+ @NonNull
+ List<Marker> getMarkersInRect(@NonNull RectF rectangle) {
+ return markers.obtainAllIn(rectangle);
}
MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap,
@Nullable MarkerViewManager.OnMarkerViewAddedListener onMarkerViewAddedListener) {
- final MarkerView marker = prepareViewMarker(markerOptions);
+ return markers.addViewBy(markerOptions, mapboxMap, onMarkerViewAddedListener);
+ }
- // add marker to map
- marker.setMapboxMap(mapboxMap);
- long id = nativeMapView.addMarker(marker);
- marker.setId(id);
- annotations.put(id, marker);
+ List<MarkerView> addMarkerViews(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions,
+ @NonNull MapboxMap mapboxMap) {
+ return markers.addViewsBy(markerViewOptions, mapboxMap);
+ }
- if (onMarkerViewAddedListener != null) {
- markerViewManager.addOnMarkerViewAddedListener(marker, onMarkerViewAddedListener);
- }
- markerViewManager.setEnabled(true);
- markerViewManager.setWaitingForRenderInvoke(true);
- return marker;
+ List<MarkerView> getMarkerViewsInRect(@NonNull RectF rectangle) {
+ return markers.obtainViewsIn(rectangle);
+ }
+
+ void reloadMarkers() {
+ markers.reload();
}
+ //
+ // Polygons
+ //
- List<MarkerView> addMarkerViews(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions,
- @NonNull MapboxMap mapboxMap) {
- List<MarkerView> markers = new ArrayList<>();
- for (BaseMarkerViewOptions markerViewOption : markerViewOptions) {
- // if last marker
- if (markerViewOptions.indexOf(markerViewOption) == markerViewOptions.size() - 1) {
- // get notified when render occurs to invalidate and draw MarkerViews
- markerViewManager.setWaitingForRenderInvoke(true);
- }
- // add marker to map
- MarkerView marker = prepareViewMarker(markerViewOption);
- marker.setMapboxMap(mapboxMap);
- long id = nativeMapView.addMarker(marker);
- marker.setId(id);
- annotations.put(id, marker);
- markers.add(marker);
- }
- markerViewManager.setEnabled(true);
- markerViewManager.update();
- return markers;
+ Polygon addPolygon(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) {
+ return polygons.addBy(polygonOptions, mapboxMap);
}
- private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) {
- MarkerView marker = markerViewOptions.getMarker();
- iconManager.loadIconForMarkerView(marker);
- return marker;
+ List<Polygon> addPolygons(@NonNull List<PolygonOptions> polygonOptionsList, @NonNull MapboxMap mapboxMap) {
+ return polygons.addBy(polygonOptionsList, mapboxMap);
}
- void updateMarker(@NonNull Marker updatedMarker) {
- if (!isAddedToMap(updatedMarker)) {
- Timber.w("Attempting to update non-added Marker with value %s", updatedMarker);
- return;
- }
+ void updatePolygon(Polygon polygon) {
+ polygons.update(polygon);
+ }
+
+ List<Polygon> getPolygons() {
+ return polygons.obtainAll();
+ }
+
+ //
+ // Polylines
+ //
- ensureIconLoaded(updatedMarker);
- nativeMapView.updateMarker(updatedMarker);
- annotations.setValueAt(annotations.indexOfKey(updatedMarker.getId()), updatedMarker);
+ Polyline addPolyline(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) {
+ return polylines.addBy(polylineOptions, mapboxMap);
}
- private boolean isAddedToMap(Annotation annotation) {
- return annotation != null && annotation.getId() != -1 && annotations.indexOfKey(annotation.getId()) != -1;
+ List<Polyline> addPolylines(@NonNull List<PolylineOptions> polylineOptionsList, @NonNull MapboxMap mapboxMap) {
+ return polylines.addBy(polylineOptionsList, mapboxMap);
}
- private void ensureIconLoaded(Marker marker) {
- if (!(marker instanceof MarkerView)) {
- iconManager.ensureIconLoaded(marker, mapboxMap);
- }
+ void updatePolyline(Polyline polyline) {
+ polylines.update(polyline);
}
- List<Marker> getMarkers() {
- List<Marker> markers = new ArrayList<>();
- Annotation annotation;
- for (int i = 0; i < annotations.size(); i++) {
- annotation = annotations.get(annotations.keyAt(i));
- if (annotation instanceof Marker) {
- markers.add((Marker) annotation);
- }
- }
- return markers;
+ List<Polyline> getPolylines() {
+ return polylines.obtainAll();
}
+ // TODO Refactor from here still in progress
+
void setOnMarkerClickListener(@Nullable MapboxMap.OnMarkerClickListener listener) {
onMarkerClickListener = listener;
}
@@ -370,207 +298,6 @@ class AnnotationManager {
return selectedMarkers;
}
- @NonNull
- List<Marker> getMarkersInRect(@NonNull RectF rectangle) {
- // convert Rectangle to be density depedent
- float pixelRatio = nativeMapView.getPixelRatio();
- RectF rect = new RectF(rectangle.left / pixelRatio,
- rectangle.top / pixelRatio,
- rectangle.right / pixelRatio,
- rectangle.bottom / pixelRatio);
-
- long[] ids = nativeMapView.queryPointAnnotations(rect);
-
- List<Long> idsList = new ArrayList<>(ids.length);
- for (long id : ids) {
- idsList.add(id);
- }
-
- List<Marker> annotations = new ArrayList<>(ids.length);
- List<Annotation> annotationList = getAnnotations();
- int count = annotationList.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotationList.get(i);
- if (annotation instanceof com.mapbox.mapboxsdk.annotations.Marker && idsList.contains(annotation.getId())) {
- annotations.add((com.mapbox.mapboxsdk.annotations.Marker) annotation);
- }
- }
-
- return new ArrayList<>(annotations);
- }
-
- List<MarkerView> getMarkerViewsInRect(@NonNull RectF rectangle) {
- float pixelRatio = nativeMapView.getPixelRatio();
- RectF rect = new RectF(rectangle.left / pixelRatio,
- rectangle.top / pixelRatio,
- rectangle.right / pixelRatio,
- rectangle.bottom / pixelRatio);
-
- long[] ids = nativeMapView.queryPointAnnotations(rect);
-
- List<Long> idsList = new ArrayList<>(ids.length);
- for (long id : ids) {
- idsList.add(id);
- }
-
- List<MarkerView> annotations = new ArrayList<>(ids.length);
- List<Annotation> annotationList = getAnnotations();
- int count = annotationList.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotationList.get(i);
- if (annotation instanceof MarkerView && idsList.contains(annotation.getId())) {
- annotations.add((MarkerView) annotation);
- }
- }
-
- return new ArrayList<>(annotations);
- }
-
- //
- // Polygons
- //
-
- Polygon addPolygon(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) {
- Polygon polygon = polygonOptions.getPolygon();
- if (!polygon.getPoints().isEmpty()) {
- long id = nativeMapView != null ? nativeMapView.addPolygon(polygon) : 0;
- polygon.setId(id);
- polygon.setMapboxMap(mapboxMap);
- annotations.put(id, polygon);
- }
- return polygon;
- }
-
- List<Polygon> addPolygons(@NonNull List<PolygonOptions> polygonOptionsList, @NonNull MapboxMap mapboxMap) {
- int count = polygonOptionsList.size();
-
- Polygon polygon;
- List<Polygon> polygons = new ArrayList<>(count);
- if (count > 0) {
- for (PolygonOptions polygonOptions : polygonOptionsList) {
- polygon = polygonOptions.getPolygon();
- if (!polygon.getPoints().isEmpty()) {
- polygons.add(polygon);
- }
- }
-
- long[] ids = null;
- if (nativeMapView != null) {
- ids = nativeMapView.addPolygons(polygons);
- }
-
- long id = 0;
- for (int i = 0; i < polygons.size(); i++) {
- polygon = polygons.get(i);
- polygon.setMapboxMap(mapboxMap);
- if (ids != null) {
- id = ids[i];
- } else {
- // unit test
- id++;
- }
- polygon.setId(id);
- annotations.put(id, polygon);
- }
- }
- return polygons;
- }
-
- void updatePolygon(@NonNull Polygon polygon) {
- if (!isAddedToMap(polygon)) {
- Timber.w("Attempting to update non-added Polygon with value %s", polygon);
- return;
- }
-
- nativeMapView.updatePolygon(polygon);
- annotations.setValueAt(annotations.indexOfKey(polygon.getId()), polygon);
- }
-
- List<Polygon> getPolygons() {
- List<Polygon> polygons = new ArrayList<>();
- Annotation annotation;
- for (int i = 0; i < annotations.size(); i++) {
- annotation = annotations.get(annotations.keyAt(i));
- if (annotation instanceof Polygon) {
- polygons.add((Polygon) annotation);
- }
- }
- return polygons;
- }
-
- //
- // Polylines
- //
-
- Polyline addPolyline(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) {
- Polyline polyline = polylineOptions.getPolyline();
- if (!polyline.getPoints().isEmpty()) {
- long id = nativeMapView != null ? nativeMapView.addPolyline(polyline) : 0;
- polyline.setMapboxMap(mapboxMap);
- polyline.setId(id);
- annotations.put(id, polyline);
- }
- return polyline;
- }
-
- List<Polyline> addPolylines(@NonNull List<PolylineOptions> polylineOptionsList, @NonNull MapboxMap mapboxMap) {
- int count = polylineOptionsList.size();
- Polyline polyline;
- List<Polyline> polylines = new ArrayList<>(count);
-
- if (count > 0) {
- for (PolylineOptions options : polylineOptionsList) {
- polyline = options.getPolyline();
- if (!polyline.getPoints().isEmpty()) {
- polylines.add(polyline);
- }
- }
-
- long[] ids = null;
- if (nativeMapView != null) {
- ids = nativeMapView.addPolylines(polylines);
- }
-
- long id = 0;
- Polyline p;
-
- for (int i = 0; i < polylines.size(); i++) {
- p = polylines.get(i);
- p.setMapboxMap(mapboxMap);
- if (ids != null) {
- id = ids[i];
- } else {
- // unit test
- id++;
- }
- p.setId(id);
- annotations.put(id, p);
- }
- }
- return polylines;
- }
-
- void updatePolyline(@NonNull Polyline polyline) {
- if (!isAddedToMap(polyline)) {
- Timber.w("Attempting to update non-added Polyline with value %s", polyline);
- }
-
- nativeMapView.updatePolyline(polyline);
- annotations.setValueAt(annotations.indexOfKey(polyline.getId()), polyline);
- }
-
- List<Polyline> getPolylines() {
- List<Polyline> polylines = new ArrayList<>();
- Annotation annotation;
- for (int i = 0; i < annotations.size(); i++) {
- annotation = annotations.get(annotations.keyAt(i));
- if (annotation instanceof Polyline) {
- polylines.add((Polyline) annotation);
- }
- }
- return polylines;
- }
-
InfoWindowManager getInfoWindowManager() {
return infoWindowManager;
}
@@ -580,9 +307,9 @@ class AnnotationManager {
}
void adjustTopOffsetPixels(MapboxMap mapboxMap) {
- int count = annotations.size();
+ int count = annotationsArray.size();
for (int i = 0; i < count; i++) {
- Annotation annotation = annotations.get(i);
+ Annotation annotation = annotationsArray.get(i);
if (annotation instanceof Marker) {
Marker marker = (Marker) annotation;
marker.setTopOffsetPixels(
@@ -598,20 +325,6 @@ class AnnotationManager {
}
}
- void reloadMarkers() {
- iconManager.reloadIcons();
- int count = annotations.size();
- for (int i = 0; i < count; i++) {
- Annotation annotation = annotations.get(i);
- if (annotation instanceof Marker) {
- Marker marker = (Marker) annotation;
- nativeMapView.removeAnnotation(annotation.getId());
- long newId = nativeMapView.addMarker(marker);
- marker.setId(newId);
- }
- }
- }
-
//
// Click event
//
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java
new file mode 100644
index 0000000000..ae41cbb0cb
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Annotations.java
@@ -0,0 +1,25 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+
+import java.util.List;
+
+/**
+ * Interface that defines convenient methods for working with a {@link Annotation}'s collection.
+ */
+interface Annotations {
+ Annotation obtainBy(long id);
+
+ List<Annotation> obtainAll();
+
+ void removeBy(long id);
+
+ void removeBy(@NonNull Annotation annotation);
+
+ void removeBy(@NonNull List<? extends Annotation> annotationList);
+
+ void removeAll();
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
index c51d9327d2..a0aebfda50 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java
@@ -11,6 +11,7 @@ import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
+import android.support.v4.util.LongSparseArray;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -26,6 +27,7 @@ import android.widget.ImageView;
import android.widget.ZoomButtonsController;
import com.mapbox.mapboxsdk.R;
+import com.mapbox.mapboxsdk.annotations.Annotation;
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.constants.Style;
@@ -132,16 +134,23 @@ public class MapView extends FrameLayout {
UiSettings uiSettings = new UiSettings(proj, focalPoint, compassView, attrView, view.findViewById(R.id.logoView));
TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPoint, zoomInvalidator);
MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, proj, focalPoint);
+ LongSparseArray<Annotation> annotationsArray = new LongSparseArray<>();
MarkerViewManager markerViewManager = new MarkerViewManager((ViewGroup) findViewById(R.id.markerViewContainer));
- AnnotationManager annotations = new AnnotationManager(nativeMapView, this, markerViewManager);
- Transform transform = new Transform(nativeMapView, annotations.getMarkerViewManager(), trackingSettings,
+ IconManager iconManager = new IconManager(nativeMapView);
+ Annotations annotations = new AnnotationContainer(nativeMapView, annotationsArray);
+ Markers markers = new MarkerContainer(nativeMapView, this, annotationsArray, iconManager, markerViewManager);
+ Polygons polygons = new PolygonContainer(nativeMapView, annotationsArray);
+ Polylines polylines = new PolylineContainer(nativeMapView, annotationsArray);
+ AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, annotationsArray,
+ markerViewManager, iconManager, annotations, markers, polygons, polylines);
+ Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings,
cameraChangeDispatcher);
mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, proj,
- registerTouchListener, annotations, cameraChangeDispatcher);
+ registerTouchListener, annotationManager, cameraChangeDispatcher);
// user input
- mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings, annotations,
- cameraChangeDispatcher);
+ mapGestureDetector = new MapGestureDetector(context, transform, proj, uiSettings, trackingSettings,
+ annotationManager, cameraChangeDispatcher);
mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings);
MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform);
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 d672ab37c3..18bcd4953d 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
@@ -1237,7 +1237,7 @@ public final class MapboxMap {
*/
@UiThread
public void updateMarker(@NonNull Marker updatedMarker) {
- annotationManager.updateMarker(updatedMarker);
+ annotationManager.updateMarker(updatedMarker, this);
}
/**
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java
new file mode 100644
index 0000000000..306ad59b8d
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MarkerContainer.java
@@ -0,0 +1,267 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.graphics.RectF;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v4.util.LongSparseArray;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
+import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
+import com.mapbox.mapboxsdk.annotations.Icon;
+import com.mapbox.mapboxsdk.annotations.IconFactory;
+import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import timber.log.Timber;
+
+/**
+ * Encapsulates {@link Marker}'s functionality.
+ */
+class MarkerContainer implements Markers {
+
+ private final NativeMapView nativeMapView;
+ private final MapView mapView;
+ private final LongSparseArray<Annotation> annotations;
+ private final IconManager iconManager;
+ private final MarkerViewManager markerViewManager;
+
+ MarkerContainer(NativeMapView nativeMapView, MapView mapView, LongSparseArray<Annotation> annotations, IconManager
+ iconManager, MarkerViewManager markerViewManager) {
+ this.nativeMapView = nativeMapView;
+ this.mapView = mapView;
+ this.annotations = annotations;
+ this.iconManager = iconManager;
+ this.markerViewManager = markerViewManager;
+ }
+
+ @Override
+ public Marker addBy(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap) {
+ Marker marker = prepareMarker(markerOptions);
+ long id = nativeMapView != null ? nativeMapView.addMarker(marker) : 0;
+ marker.setMapboxMap(mapboxMap);
+ marker.setId(id);
+ annotations.put(id, marker);
+ return marker;
+ }
+
+ @Override
+ public List<Marker> addBy(@NonNull List<? extends BaseMarkerOptions> markerOptionsList, @NonNull MapboxMap
+ mapboxMap) {
+ int count = markerOptionsList.size();
+ List<Marker> markers = new ArrayList<>(count);
+ if (count > 0) {
+ BaseMarkerOptions markerOptions;
+ Marker marker;
+ for (int i = 0; i < count; i++) {
+ markerOptions = markerOptionsList.get(i);
+ marker = prepareMarker(markerOptions);
+ markers.add(marker);
+ }
+
+ if (markers.size() > 0) {
+ long[] ids = null;
+ if (nativeMapView != null) {
+ ids = nativeMapView.addMarkers(markers);
+ }
+
+ long id = 0;
+ Marker m;
+ for (int i = 0; i < markers.size(); i++) {
+ m = markers.get(i);
+ m.setMapboxMap(mapboxMap);
+ if (ids != null) {
+ id = ids[i];
+ } else {
+ // unit test
+ id++;
+ }
+ m.setId(id);
+ annotations.put(id, m);
+ }
+
+ }
+ }
+ return markers;
+ }
+
+ @Override
+ public void update(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) {
+ if (!isAddedToMap(updatedMarker)) {
+ Timber.w("Attempting to update non-added Marker with value %s", updatedMarker);
+ return;
+ }
+
+ ensureIconLoaded(updatedMarker, mapboxMap);
+ nativeMapView.updateMarker(updatedMarker);
+ annotations.setValueAt(annotations.indexOfKey(updatedMarker.getId()), updatedMarker);
+ }
+
+ @Override
+ public List<Marker> obtainAll() {
+ List<Marker> markers = new ArrayList<>();
+ Annotation annotation;
+ for (int i = 0; i < annotations.size(); i++) {
+ annotation = annotations.get(annotations.keyAt(i));
+ if (annotation instanceof Marker) {
+ markers.add((Marker) annotation);
+ }
+ }
+ return markers;
+ }
+
+ @NonNull
+ @Override
+ public List<Marker> obtainAllIn(@NonNull RectF rectangle) {
+ // convert Rectangle to be density depedent
+ float pixelRatio = nativeMapView.getPixelRatio();
+ RectF rect = new RectF(rectangle.left / pixelRatio,
+ rectangle.top / pixelRatio,
+ rectangle.right / pixelRatio,
+ rectangle.bottom / pixelRatio);
+
+ long[] ids = nativeMapView.queryPointAnnotations(rect);
+
+ List<Long> idsList = new ArrayList<>(ids.length);
+ for (long id : ids) {
+ idsList.add(id);
+ }
+
+ List<Marker> annotations = new ArrayList<>(ids.length);
+ List<Annotation> annotationList = obtainAnnotations();
+ int count = annotationList.size();
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = annotationList.get(i);
+ if (annotation instanceof com.mapbox.mapboxsdk.annotations.Marker && idsList.contains(annotation.getId())) {
+ annotations.add((com.mapbox.mapboxsdk.annotations.Marker) annotation);
+ }
+ }
+
+ return new ArrayList<>(annotations);
+ }
+
+ @Override
+ public MarkerView addViewBy(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap, @Nullable
+ MarkerViewManager.OnMarkerViewAddedListener onMarkerViewAddedListener) {
+ final MarkerView marker = prepareViewMarker(markerOptions);
+
+ // add marker to map
+ marker.setMapboxMap(mapboxMap);
+ long id = nativeMapView.addMarker(marker);
+ marker.setId(id);
+ annotations.put(id, marker);
+
+ if (onMarkerViewAddedListener != null) {
+ markerViewManager.addOnMarkerViewAddedListener(marker, onMarkerViewAddedListener);
+ }
+ markerViewManager.setEnabled(true);
+ markerViewManager.setWaitingForRenderInvoke(true);
+ return marker;
+ }
+
+ @Override
+ public List<MarkerView> addViewsBy(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions, @NonNull
+ MapboxMap mapboxMap) {
+ List<MarkerView> markers = new ArrayList<>();
+ for (BaseMarkerViewOptions markerViewOption : markerViewOptions) {
+ // if last marker
+ if (markerViewOptions.indexOf(markerViewOption) == markerViewOptions.size() - 1) {
+ // get notified when render occurs to invalidate and draw MarkerViews
+ markerViewManager.setWaitingForRenderInvoke(true);
+ }
+ // add marker to map
+ MarkerView marker = prepareViewMarker(markerViewOption);
+ marker.setMapboxMap(mapboxMap);
+ long id = nativeMapView.addMarker(marker);
+ marker.setId(id);
+ annotations.put(id, marker);
+ markers.add(marker);
+ }
+ markerViewManager.setEnabled(true);
+ markerViewManager.update();
+ return markers;
+ }
+
+ @Override
+ public List<MarkerView> obtainViewsIn(@NonNull RectF rectangle) {
+ float pixelRatio = nativeMapView.getPixelRatio();
+ RectF rect = new RectF(rectangle.left / pixelRatio,
+ rectangle.top / pixelRatio,
+ rectangle.right / pixelRatio,
+ rectangle.bottom / pixelRatio);
+
+ long[] ids = nativeMapView.queryPointAnnotations(rect);
+
+ List<Long> idsList = new ArrayList<>(ids.length);
+ for (long id : ids) {
+ idsList.add(id);
+ }
+
+ List<MarkerView> annotations = new ArrayList<>(ids.length);
+ List<Annotation> annotationList = obtainAnnotations();
+ int count = annotationList.size();
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = annotationList.get(i);
+ if (annotation instanceof MarkerView && idsList.contains(annotation.getId())) {
+ annotations.add((MarkerView) annotation);
+ }
+ }
+
+ return new ArrayList<>(annotations);
+ }
+
+ @Override
+ public void reload() {
+ iconManager.reloadIcons();
+ int count = annotations.size();
+ for (int i = 0; i < count; i++) {
+ Annotation annotation = annotations.get(i);
+ if (annotation instanceof Marker) {
+ Marker marker = (Marker) annotation;
+ nativeMapView.removeAnnotation(annotation.getId());
+ long newId = nativeMapView.addMarker(marker);
+ marker.setId(newId);
+ }
+ }
+ }
+
+ private Marker prepareMarker(BaseMarkerOptions markerOptions) {
+ Marker marker = markerOptions.getMarker();
+ Icon icon = iconManager.loadIconForMarker(marker);
+ marker.setTopOffsetPixels(iconManager.getTopOffsetPixelsForIcon(icon));
+ return marker;
+ }
+
+ private boolean isAddedToMap(Annotation annotation) {
+ return annotation != null && annotation.getId() != -1 && annotations.indexOfKey(annotation.getId()) != -1;
+ }
+
+ private void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) {
+ if (!(marker instanceof MarkerView)) {
+ iconManager.ensureIconLoaded(marker, mapboxMap);
+ }
+ }
+
+ private List<Annotation> obtainAnnotations() {
+ List<Annotation> annotations = new ArrayList<>();
+ for (int i = 0; i < this.annotations.size(); i++) {
+ annotations.add(this.annotations.get(this.annotations.keyAt(i)));
+ }
+ return annotations;
+ }
+
+ private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) {
+ MarkerView marker = markerViewOptions.getMarker();
+ Icon icon = markerViewOptions.getIcon();
+ if (icon == null) {
+ icon = IconFactory.getInstance(mapView.getContext()).defaultMarkerView();
+ }
+ marker.setIcon(icon);
+ return marker;
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java
new file mode 100644
index 0000000000..d646e0ac49
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Markers.java
@@ -0,0 +1,39 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.graphics.RectF;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
+import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions;
+import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerView;
+import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
+
+import java.util.List;
+
+/**
+ * Interface that defines convenient methods for working with a {@link Marker}'s collection.
+ */
+interface Markers {
+ Marker addBy(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap);
+
+ List<Marker> addBy(@NonNull List<? extends BaseMarkerOptions> markerOptionsList, @NonNull MapboxMap mapboxMap);
+
+ void update(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap);
+
+ List<Marker> obtainAll();
+
+ List<Marker> obtainAllIn(@NonNull RectF rectangle);
+
+ MarkerView addViewBy(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap,
+ @Nullable MarkerViewManager.OnMarkerViewAddedListener onMarkerViewAddedListener);
+
+ List<MarkerView> addViewsBy(@NonNull List<? extends BaseMarkerViewOptions> markerViewOptions,
+ @NonNull MapboxMap mapboxMap);
+
+ List<MarkerView> obtainViewsIn(@NonNull RectF rectangle);
+
+ void reload();
+}
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 af3b57151d..a88a11d387 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
@@ -1,11 +1,9 @@
package com.mapbox.mapboxsdk.maps;
-import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.PointF;
import android.graphics.RectF;
-import android.os.Build;
import android.support.annotation.IntRange;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
@@ -13,6 +11,7 @@ import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.view.Surface;
+import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.annotations.Icon;
import com.mapbox.mapboxsdk.annotations.Marker;
import com.mapbox.mapboxsdk.annotations.Polygon;
@@ -64,12 +63,8 @@ final class NativeMapView {
// Listener invoked to return a bitmap of the map
private MapboxMap.SnapshotReadyCallback snapshotReadyCallback;
- //
- // Static methods
- //
-
static {
- System.loadLibrary("mapbox-gl");
+ LibraryLoader.load();
}
//
@@ -81,27 +76,11 @@ final class NativeMapView {
fileSource = FileSource.getInstance(context);
pixelRatio = context.getResources().getDisplayMetrics().density;
- int availableProcessors = Runtime.getRuntime().availableProcessors();
- ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();
- ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
- activityManager.getMemoryInfo(memoryInfo);
- long totalMemory = memoryInfo.availMem;
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
- totalMemory = memoryInfo.totalMem;
- }
-
- if (availableProcessors < 0) {
- throw new IllegalArgumentException("availableProcessors cannot be negative.");
- }
-
- if (totalMemory < 0) {
- throw new IllegalArgumentException("totalMemory cannot be negative.");
- }
onMapChangedListeners = new CopyOnWriteArrayList<>();
this.mapView = mapView;
String programCacheDir = context.getCacheDir().getAbsolutePath();
- nativeInitialize(this, fileSource, pixelRatio, programCacheDir, availableProcessors, totalMemory);
+ nativeInitialize(this, fileSource, pixelRatio, programCacheDir);
}
//
@@ -621,7 +600,7 @@ final class NativeMapView {
if (isDestroyedOn("getMetersPerPixelAtLatitude")) {
return 0;
}
- return nativeGetMetersPerPixelAtLatitude(lat, getZoom());
+ return nativeGetMetersPerPixelAtLatitude(lat, getZoom()) / pixelRatio;
}
public ProjectedMeters projectedMetersForLatLng(LatLng latLng) {
@@ -944,9 +923,7 @@ final class NativeMapView {
private native void nativeInitialize(NativeMapView nativeMapView,
FileSource fileSource,
float pixelRatio,
- String programCacheDir,
- int availableProcessors,
- long totalMemory);
+ String programCacheDir);
private native void nativeDestroy();
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java
new file mode 100644
index 0000000000..bcb94a975c
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolygonContainer.java
@@ -0,0 +1,104 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+import android.support.v4.util.LongSparseArray;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+import com.mapbox.mapboxsdk.annotations.Polygon;
+import com.mapbox.mapboxsdk.annotations.PolygonOptions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import timber.log.Timber;
+
+/**
+ * Encapsulates {@link Polygon}'s functionality.
+ */
+class PolygonContainer implements Polygons {
+
+ private final NativeMapView nativeMapView;
+ private final LongSparseArray<Annotation> annotations;
+
+ PolygonContainer(NativeMapView nativeMapView, LongSparseArray<Annotation> annotations) {
+ this.nativeMapView = nativeMapView;
+ this.annotations = annotations;
+ }
+
+ @Override
+ public Polygon addBy(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) {
+ Polygon polygon = polygonOptions.getPolygon();
+ if (!polygon.getPoints().isEmpty()) {
+ long id = nativeMapView != null ? nativeMapView.addPolygon(polygon) : 0;
+ polygon.setId(id);
+ polygon.setMapboxMap(mapboxMap);
+ annotations.put(id, polygon);
+ }
+ return polygon;
+ }
+
+ @Override
+ public List<Polygon> addBy(@NonNull List<PolygonOptions> polygonOptionsList, @NonNull MapboxMap mapboxMap) {
+ int count = polygonOptionsList.size();
+
+ Polygon polygon;
+ List<Polygon> polygons = new ArrayList<>(count);
+ if (count > 0) {
+ for (PolygonOptions polygonOptions : polygonOptionsList) {
+ polygon = polygonOptions.getPolygon();
+ if (!polygon.getPoints().isEmpty()) {
+ polygons.add(polygon);
+ }
+ }
+
+ long[] ids = null;
+ if (nativeMapView != null) {
+ ids = nativeMapView.addPolygons(polygons);
+ }
+
+ long id = 0;
+ for (int i = 0; i < polygons.size(); i++) {
+ polygon = polygons.get(i);
+ polygon.setMapboxMap(mapboxMap);
+ if (ids != null) {
+ id = ids[i];
+ } else {
+ // unit test
+ id++;
+ }
+ polygon.setId(id);
+ annotations.put(id, polygon);
+ }
+ }
+ return polygons;
+ }
+
+ @Override
+ public void update(Polygon polygon) {
+ if (!isAddedToMap(polygon)) {
+ Timber.w("Attempting to update non-added Polygon with value %s", polygon);
+ return;
+ }
+
+ nativeMapView.updatePolygon(polygon);
+ annotations.setValueAt(annotations.indexOfKey(polygon.getId()), polygon);
+ }
+
+ @Override
+ public List<Polygon> obtainAll() {
+ List<Polygon> polygons = new ArrayList<>();
+ Annotation annotation;
+ for (int i = 0; i < annotations.size(); i++) {
+ annotation = annotations.get(annotations.keyAt(i));
+ if (annotation instanceof Polygon) {
+ polygons.add((Polygon) annotation);
+ }
+ }
+ return polygons;
+ }
+
+ private boolean isAddedToMap(Annotation annotation) {
+ return annotation != null && annotation.getId() != -1 && annotations.indexOfKey(annotation.getId()) != -1;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java
new file mode 100644
index 0000000000..2a0190b5ba
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polygons.java
@@ -0,0 +1,22 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.annotations.Polygon;
+import com.mapbox.mapboxsdk.annotations.PolygonOptions;
+
+import java.util.List;
+
+/**
+ * Interface that defines convenient methods for working with a {@link Polygon}'s collection.
+ */
+interface Polygons {
+ Polygon addBy(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap);
+
+ List<Polygon> addBy(@NonNull List<PolygonOptions> polygonOptionsList, @NonNull MapboxMap mapboxMap);
+
+ void update(Polygon polygon);
+
+ List<Polygon> obtainAll();
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java
new file mode 100644
index 0000000000..7483f1082b
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/PolylineContainer.java
@@ -0,0 +1,105 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+import android.support.v4.util.LongSparseArray;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+import com.mapbox.mapboxsdk.annotations.Polyline;
+import com.mapbox.mapboxsdk.annotations.PolylineOptions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import timber.log.Timber;
+
+/**
+ * Encapsulates {@link Polyline}'s functionality.
+ */
+class PolylineContainer implements Polylines {
+
+ private final NativeMapView nativeMapView;
+ private final LongSparseArray<Annotation> annotations;
+
+ PolylineContainer(NativeMapView nativeMapView, LongSparseArray<Annotation> annotations) {
+ this.nativeMapView = nativeMapView;
+ this.annotations = annotations;
+ }
+
+ @Override
+ public Polyline addBy(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) {
+ Polyline polyline = polylineOptions.getPolyline();
+ if (!polyline.getPoints().isEmpty()) {
+ long id = nativeMapView != null ? nativeMapView.addPolyline(polyline) : 0;
+ polyline.setMapboxMap(mapboxMap);
+ polyline.setId(id);
+ annotations.put(id, polyline);
+ }
+ return polyline;
+ }
+
+ @Override
+ public List<Polyline> addBy(@NonNull List<PolylineOptions> polylineOptionsList, @NonNull MapboxMap mapboxMap) {
+ int count = polylineOptionsList.size();
+ Polyline polyline;
+ List<Polyline> polylines = new ArrayList<>(count);
+
+ if (count > 0) {
+ for (PolylineOptions options : polylineOptionsList) {
+ polyline = options.getPolyline();
+ if (!polyline.getPoints().isEmpty()) {
+ polylines.add(polyline);
+ }
+ }
+
+ long[] ids = null;
+ if (nativeMapView != null) {
+ ids = nativeMapView.addPolylines(polylines);
+ }
+
+ long id = 0;
+ Polyline p;
+
+ for (int i = 0; i < polylines.size(); i++) {
+ p = polylines.get(i);
+ p.setMapboxMap(mapboxMap);
+ if (ids != null) {
+ id = ids[i];
+ } else {
+ // unit test
+ id++;
+ }
+ p.setId(id);
+ annotations.put(id, p);
+ }
+ }
+ return polylines;
+ }
+
+ @Override
+ public void update(Polyline polyline) {
+ if (!isAddedToMap(polyline)) {
+ Timber.w("Attempting to update non-added Polyline with value %s", polyline);
+ }
+
+ nativeMapView.updatePolyline(polyline);
+ annotations.setValueAt(annotations.indexOfKey(polyline.getId()), polyline);
+ }
+
+ @Override
+ public List<Polyline> obtainAll() {
+ List<Polyline> polylines = new ArrayList<>();
+ Annotation annotation;
+ for (int i = 0; i < annotations.size(); i++) {
+ annotation = annotations.get(annotations.keyAt(i));
+ if (annotation instanceof Polyline) {
+ polylines.add((Polyline) annotation);
+ }
+ }
+ return polylines;
+ }
+
+ private boolean isAddedToMap(Annotation annotation) {
+ return annotation != null && annotation.getId() != -1 && annotations.indexOfKey(annotation.getId()) != -1;
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java
new file mode 100644
index 0000000000..c9a865cdd0
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/Polylines.java
@@ -0,0 +1,22 @@
+package com.mapbox.mapboxsdk.maps;
+
+
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.annotations.Polyline;
+import com.mapbox.mapboxsdk.annotations.PolylineOptions;
+
+import java.util.List;
+
+/**
+ * Interface that defines convenient methods for working with a {@link Polyline}'s collection.
+ */
+interface Polylines {
+ Polyline addBy(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap);
+
+ List<Polyline> addBy(@NonNull List<PolylineOptions> polylineOptionsList, @NonNull MapboxMap mapboxMap);
+
+ void update(Polyline polyline);
+
+ List<Polyline> obtainAll();
+}
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
index 7f8ba21e3e..e8891429f9 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java
@@ -36,8 +36,14 @@ public final class UiSettings {
private final FocalPointChangeListener focalPointChangeListener;
private final Projection projection;
private final CompassView compassView;
+ private final int[] compassMargins = new int[4];
+
private final ImageView attributionsView;
+ private final int[] attributionsMargins = new int[4];
+
private final View logoView;
+ private final int[] logoMargins = new int[4];
+
private float pixelRatio;
private boolean rotateGesturesEnabled = true;
@@ -368,7 +374,7 @@ public final class UiSettings {
*/
@UiThread
public void setCompassMargins(int left, int top, int right, int bottom) {
- setWidgetMargins(compassView, left, top, right, bottom);
+ setWidgetMargins(compassView, compassMargins, left, top, right, bottom);
}
/**
@@ -377,7 +383,7 @@ public final class UiSettings {
* @return The left margin in pixels
*/
public int getCompassMarginLeft() {
- return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).leftMargin;
+ return compassMargins[0];
}
/**
@@ -386,7 +392,7 @@ public final class UiSettings {
* @return The top margin in pixels
*/
public int getCompassMarginTop() {
- return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).topMargin;
+ return compassMargins[1];
}
/**
@@ -395,7 +401,7 @@ public final class UiSettings {
* @return The right margin in pixels
*/
public int getCompassMarginRight() {
- return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).rightMargin;
+ return compassMargins[2];
}
/**
@@ -404,7 +410,7 @@ public final class UiSettings {
* @return The bottom margin in pixels
*/
public int getCompassMarginBottom() {
- return ((FrameLayout.LayoutParams) compassView.getLayoutParams()).bottomMargin;
+ return compassMargins[3];
}
/**
@@ -477,7 +483,7 @@ public final class UiSettings {
* @param bottom The bottom margin in pixels.
*/
public void setLogoMargins(int left, int top, int right, int bottom) {
- setWidgetMargins(logoView, left, top, right, bottom);
+ setWidgetMargins(logoView, logoMargins, left, top, right, bottom);
}
/**
@@ -486,7 +492,7 @@ public final class UiSettings {
* @return The left margin in pixels
*/
public int getLogoMarginLeft() {
- return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).leftMargin;
+ return logoMargins[0];
}
/**
@@ -495,7 +501,7 @@ public final class UiSettings {
* @return The top margin in pixels
*/
public int getLogoMarginTop() {
- return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).topMargin;
+ return logoMargins[1];
}
/**
@@ -504,7 +510,7 @@ public final class UiSettings {
* @return The right margin in pixels
*/
public int getLogoMarginRight() {
- return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).rightMargin;
+ return logoMargins[2];
}
/**
@@ -513,7 +519,7 @@ public final class UiSettings {
* @return The bottom margin in pixels
*/
public int getLogoMarginBottom() {
- return ((FrameLayout.LayoutParams) logoView.getLayoutParams()).bottomMargin;
+ return logoMargins[3];
}
/**
@@ -567,7 +573,7 @@ public final class UiSettings {
* @param bottom The bottom margin in pixels.
*/
public void setAttributionMargins(int left, int top, int right, int bottom) {
- setWidgetMargins(attributionsView, left, top, right, bottom);
+ setWidgetMargins(attributionsView, attributionsMargins, left, top, right, bottom);
}
/**
@@ -594,7 +600,7 @@ public final class UiSettings {
* @return The left margin in pixels
*/
public int getAttributionMarginLeft() {
- return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).leftMargin;
+ return attributionsMargins[0];
}
/**
@@ -603,7 +609,7 @@ public final class UiSettings {
* @return The top margin in pixels
*/
public int getAttributionMarginTop() {
- return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).topMargin;
+ return attributionsMargins[1];
}
/**
@@ -612,7 +618,7 @@ public final class UiSettings {
* @return The right margin in pixels
*/
public int getAttributionMarginRight() {
- return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).rightMargin;
+ return attributionsMargins[2];
}
/**
@@ -621,7 +627,7 @@ public final class UiSettings {
* @return The bottom margin in pixels
*/
public int getAttributionMarginBottom() {
- return ((FrameLayout.LayoutParams) attributionsView.getLayoutParams()).bottomMargin;
+ return attributionsMargins[3];
}
/**
@@ -925,7 +931,14 @@ public final class UiSettings {
view.setLayoutParams(layoutParams);
}
- private void setWidgetMargins(@NonNull final View view, int left, int top, int right, int bottom) {
+ private void setWidgetMargins(@NonNull final View view, int[] initMargins, int left, int top, int right, int bottom) {
+ // keep state of initially set margins
+ initMargins[0] = left;
+ initMargins[1] = top;
+ initMargins[2] = right;
+ initMargins[3] = bottom;
+
+ // convert inital margins with padding
int[] contentPadding = projection.getContentPadding();
FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view.getLayoutParams();
left += contentPadding[0];
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java
index 76ce1de9d7..ae74859228 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/net/NativeConnectivityListener.java
@@ -1,12 +1,14 @@
package com.mapbox.mapboxsdk.net;
+import com.mapbox.mapboxsdk.LibraryLoader;
+
/**
* Updates the native library's connectivity state
*/
class NativeConnectivityListener implements ConnectivityListener {
static {
- System.loadLibrary("mapbox-gl");
+ LibraryLoader.load();
}
private long nativePtr;
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
index d572d696db..1cf3711255 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineManager.java
@@ -5,6 +5,7 @@ import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
+import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.R;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
@@ -25,7 +26,7 @@ public class OfflineManager {
//
static {
- System.loadLibrary("mapbox-gl");
+ LibraryLoader.load();
}
// Native peer pointer
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
index 1c78d5979e..1b8c4121ef 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/offline/OfflineRegion.java
@@ -6,6 +6,7 @@ import android.support.annotation.IntDef;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
+import com.mapbox.mapboxsdk.LibraryLoader;
import com.mapbox.mapboxsdk.storage.FileSource;
import java.lang.annotation.Retention;
@@ -23,7 +24,7 @@ public class OfflineRegion {
//
static {
- System.loadLibrary("mapbox-gl");
+ LibraryLoader.load();
}
// Members
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
index e4ea9676fa..73896b7901 100644
--- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/layers/PropertyFactory.java
@@ -322,11 +322,11 @@ public class PropertyFactory {
/**
* Stroke thickness.
*
- * @param <Z> the zoom parameter type
- * @param function a wrapper {@link CameraFunction} for Float
+ * @param <T> the function input type
+ * @param function a wrapper function for Float
* @return property wrapper around a Float function
*/
- public static <Z extends Number> PropertyValue<CameraFunction<Z, Float>> lineWidth(CameraFunction<Z, Float> function) {
+ public static <T> PropertyValue<Function<T, Float>> lineWidth(Function<T, Float> function) {
return new PaintPropertyValue<>("line-width", function);
}
@@ -1676,7 +1676,7 @@ public class PropertyFactory {
}
/**
- * Scale factor for icon. 1 is original size, 3 triples the size.
+ * Scales the original size of the icon by the provided factor. The new pixel size of the image will be the original pixel size multiplied by {@link PropertyFactory#iconSize}. 1 is the original size; 3 triples the size of the image.
*
* @param value a Float value
* @return property wrapper around Float
@@ -1688,7 +1688,7 @@ public class PropertyFactory {
/**
- * Scale factor for icon. 1 is original size, 3 triples the size.
+ * Scales the original size of the icon by the provided factor. The new pixel size of the image will be the original pixel size multiplied by {@link PropertyFactory#iconSize}. 1 is the original size; 3 triples the size of the image.
*
* @param <T> the function input type
* @param function a wrapper function for Float
diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java
new file mode 100644
index 0000000000..84e5e96fa4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/style/sources/ImageSource.java
@@ -0,0 +1,137 @@
+package com.mapbox.mapboxsdk.style.sources;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.DrawableRes;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.UiThread;
+import android.support.v4.content.ContextCompat;
+
+import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.geometry.LatLngQuad;
+
+import java.net.URL;
+
+
+/**
+ * Image source, allows a georeferenced raster image to be shown on the map.
+ * <p>
+ * The georeferenced image scales and rotates as the user zooms and rotates the map.
+ * The geographic location of the raster image content, supplied with `LatLngQuad`,
+ * can be non-axis aligned.
+ * </p>
+ * * @see <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-image">the style specification</a>
+ */
+@UiThread
+public class ImageSource extends Source {
+
+ /**
+ * Internal use
+ *
+ * @param nativePtr - pointer to native peer
+ */
+ public ImageSource(long nativePtr) {
+ super(nativePtr);
+ }
+
+ /**
+ * Create an ImageSource from coordinates and an image URL
+ *
+ * @param id The source id
+ * @param coordinates The Latitude and Longitude of the four corners of the image
+ * @param url remote json file
+ */
+ public ImageSource(String id, LatLngQuad coordinates, URL url) {
+ initialize(id, coordinates);
+ setUrl(url);
+ }
+
+ /**
+ * Create an ImageSource from coordinates and a bitmap image
+ *
+ * @param id The source id
+ * @param coordinates The Latitude and Longitude of the four corners of the image
+ * @param bitmap A Bitmap image
+ */
+ public ImageSource(String id, LatLngQuad coordinates, @NonNull android.graphics.Bitmap bitmap) {
+ initialize(id, coordinates);
+ setImage(bitmap);
+ }
+
+ /**
+ * Create an ImageSource from coordinates and a bitmap image resource
+ *
+ * @param id The source id
+ * @param coordinates The Latitude and Longitude of the four corners of the image
+ * @param resourceId The resource ID of a Bitmap image
+ */
+ public ImageSource(String id, LatLngQuad coordinates, @DrawableRes int resourceId) {
+ initialize(id, coordinates);
+ setImage(resourceId);
+ }
+
+ /**
+ * Updates the source image url
+ *
+ * @param url An Image url
+ */
+ public void setUrl(URL url) {
+ setUrl(url.toExternalForm());
+ }
+
+ /**
+ * Updates the source image url
+ *
+ * @param url An image url
+ */
+ public void setUrl(String url) {
+ nativeSetUrl(url);
+ }
+
+ /**
+ * Updates the source image to a bitmap
+ *
+ * @param bitmap A Bitmap image
+ */
+ public void setImage(@NonNull android.graphics.Bitmap bitmap) {
+ nativeSetImage(bitmap);
+ }
+
+ /**
+ * Updates the source image to a bitmap image resource
+ *
+ * @param resourceId The resource ID of a Bitmap image
+ */
+ public void setImage(@DrawableRes int resourceId) throws IllegalArgumentException {
+ Context context = Mapbox.getApplicationContext();
+ Drawable drawable = ContextCompat.getDrawable(context, resourceId);
+ if (drawable instanceof BitmapDrawable) {
+ BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+ nativeSetImage(bitmapDrawable.getBitmap());
+ } else {
+ throw new IllegalArgumentException("Failed to decode image. The resource provided must be a Bitmap.");
+ }
+ }
+
+ /**
+ * @return The url or null
+ */
+ @Nullable
+ public String getUrl() {
+ return nativeGetUrl();
+ }
+
+ protected native void initialize(String layerId, LatLngQuad payload);
+
+ protected native void nativeSetUrl(String url);
+
+ protected native String nativeGetUrl();
+
+ protected native void nativeSetImage(Bitmap bitmap);
+
+ @Override
+ protected native void finalize() throws Throwable;
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
index e05190cd57..e05190cd57 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/MapboxTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java
index 605e159b84..605e159b84 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/AnnotationTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
index 1c259af2d0..1c259af2d0 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/IconTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java
index 94b629860e..94b629860e 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/InfoWindowTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java
index fa571e06b1..fa571e06b1 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
index ebd30f5422..ebd30f5422 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/MarkerViewTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java
index 3933c68887..3933c68887 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolygonTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java
index 54bb0e8cf4..54bb0e8cf4 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/annotations/PolylineTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
index 0c5f3a4be2..0c5f3a4be2 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/camera/CameraPositionTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/constants/AppConstant.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/constants/AppConstant.java
index aaef7f8a51..cb654aa556 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/constants/AppConstant.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/constants/AppConstant.java
@@ -1,4 +1,4 @@
-package com.mapbox.mapboxsdk.testapp.model.constants;
+package com.mapbox.mapboxsdk.constants;
public class AppConstant {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
index 8d9a360714..8d9a360714 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngBoundsTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java
index 12297247cf..12297247cf 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngSpanTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
index 06e93b9d2f..06e93b9d2f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/LatLngTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java
index 00fd125a1a..00fd125a1a 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/ProjectedMetersTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java
index 12b779de5d..12b779de5d 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/geometry/VisibleRegionTest.java
diff --git a/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java
new file mode 100644
index 0000000000..0d592f9bb3
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/AnnotationManagerTest.java
@@ -0,0 +1,81 @@
+package com.mapbox.mapboxsdk.maps;
+
+import android.support.v4.util.LongSparseArray;
+
+import com.mapbox.mapboxsdk.annotations.Annotation;
+import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions;
+import com.mapbox.mapboxsdk.annotations.Marker;
+import com.mapbox.mapboxsdk.annotations.MarkerOptions;
+import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static junit.framework.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AnnotationManagerTest {
+
+ @Test
+ public void checksAddAMarker() throws Exception {
+ NativeMapView aNativeMapView = mock(NativeMapView.class);
+ MapView aMapView = mock(MapView.class);
+ LongSparseArray<Annotation> annotationsArray = new LongSparseArray<>();
+ MarkerViewManager aMarkerViewManager = mock(MarkerViewManager.class);
+ IconManager aIconManager = mock(IconManager.class);
+ Annotations annotations = new AnnotationContainer(aNativeMapView, annotationsArray);
+ Markers markers = new MarkerContainer(aNativeMapView, aMapView, annotationsArray, aIconManager, aMarkerViewManager);
+ Polygons polygons = new PolygonContainer(aNativeMapView, annotationsArray);
+ Polylines polylines = new PolylineContainer(aNativeMapView, annotationsArray);
+ AnnotationManager annotationManager = new AnnotationManager(aNativeMapView, aMapView, annotationsArray,
+ aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines);
+ Marker aMarker = mock(Marker.class);
+ long aId = 5L;
+ when(aNativeMapView.addMarker(aMarker)).thenReturn(aId);
+ BaseMarkerOptions aMarkerOptions = mock(BaseMarkerOptions.class);
+ MapboxMap aMapboxMap = mock(MapboxMap.class);
+ when(aMarkerOptions.getMarker()).thenReturn(aMarker);
+
+ annotationManager.addMarker(aMarkerOptions, aMapboxMap);
+
+ assertEquals(aMarker, annotationManager.getAnnotations().get(0));
+ assertEquals(aMarker, annotationManager.getAnnotation(aId));
+ }
+
+ @Test
+ public void checksAddMarkers() throws Exception {
+ NativeMapView aNativeMapView = mock(NativeMapView.class);
+ MapView aMapView = mock(MapView.class);
+ LongSparseArray<Annotation> annotationsArray = new LongSparseArray<>();
+ MarkerViewManager aMarkerViewManager = mock(MarkerViewManager.class);
+ IconManager aIconManager = mock(IconManager.class);
+ Annotations annotations = new AnnotationContainer(aNativeMapView, annotationsArray);
+ Markers markers = new MarkerContainer(aNativeMapView, aMapView, annotationsArray, aIconManager, aMarkerViewManager);
+ Polygons polygons = new PolygonContainer(aNativeMapView, annotationsArray);
+ Polylines polylines = new PolylineContainer(aNativeMapView, annotationsArray);
+ AnnotationManager annotationManager = new AnnotationManager(aNativeMapView, aMapView, annotationsArray,
+ aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines);
+ long firstId = 1L;
+ long secondId = 2L;
+ List<BaseMarkerOptions> markerList = new ArrayList<>();
+ MarkerOptions firstMarkerOption = new MarkerOptions().position(new LatLng()).title("first");
+ MarkerOptions secondMarkerOption = new MarkerOptions().position(new LatLng()).title("second");
+ markerList.add(firstMarkerOption);
+ markerList.add(secondMarkerOption);
+ MapboxMap aMapboxMap = mock(MapboxMap.class);
+ when(aNativeMapView.addMarker(any(Marker.class))).thenReturn(firstId, secondId);
+
+ annotationManager.addMarkers(markerList, aMapboxMap);
+
+ assertEquals(2, annotationManager.getAnnotations().size());
+ assertEquals("first", ((Marker) annotationManager.getAnnotations().get(0)).getTitle());
+ assertEquals("second", ((Marker) annotationManager.getAnnotations().get(1)).getTitle());
+ assertEquals("first", ((Marker) annotationManager.getAnnotation(firstId)).getTitle());
+ assertEquals("second", ((Marker) annotationManager.getAnnotation(secondId)).getTitle());
+ }
+} \ No newline at end of file
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java
index ce0cb00b0b..ce0cb00b0b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/MapboxMapOptionsTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java
index de5f364a5b..de5f364a5b 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/TrackingSettingsTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
index fbe00b4dce..fbe00b4dce 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/UiSettingsTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java
index c9ce19dc85..c9ce19dc85 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationViewSettingsTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java
index 933bf05b39..933bf05b39 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FilterTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java
index bac1154d62..bac1154d62 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/style/layers/FunctionTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java
index 94a6dc2194..94a6dc2194 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/telemetry/HttpTransportTest.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java
index dd4c7b25ee..dd4c7b25ee 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java
+++ b/platform/android/MapboxGLAndroidSDK/src/test/java/com/mapbox/mapboxsdk/utils/MockParcel.java
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/platform/android/MapboxGLAndroidSDK/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
index ca6ee9cea8..ca6ee9cea8 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
+++ b/platform/android/MapboxGLAndroidSDK/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
index 56b537e2a2..656789fcdb 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle
@@ -32,10 +32,6 @@ android {
disable 'InvalidPackage'
}
- testOptions {
- unitTests.returnDefaultValues = true
- }
-
buildTypes {
debug {
testCoverageEnabled = true
@@ -75,8 +71,6 @@ dependencies {
}
// Testing dependencies
- testCompile rootProject.ext.dep.junit
- testCompile rootProject.ext.dep.mockito
androidTestCompile rootProject.ext.dep.testSpoonRunner
androidTestCompile rootProject.ext.dep.supportAnnotations
androidTestCompile rootProject.ext.dep.testRunner
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle b/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle
index 1068e5e69e..8346806633 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle
+++ b/platform/android/MapboxGLAndroidSDKTestApp/gradle-config.gradle
@@ -5,14 +5,15 @@
task accessToken {
def tokenFile = new File("${projectDir}/src/main/res/values/developer-config.xml")
if (!tokenFile.exists()) {
+ String mapboxAccessToken = "$System.env.MAPBOX_ACCESS_TOKEN"
+ if (mapboxAccessToken == "null") {
+ System.out.println("You should set the MAPBOX_ACCESS_TOKEN environment variable.")
+ mapboxAccessToken = "YOUR_MAPBOX_ACCESS_TOKEN_GOES_HERE"
+ }
String tokenFileContents = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
"<resources>\n" +
- " <string name=\"mapbox_access_token\">" + "$System.env.MAPBOX_ACCESS_TOKEN" + "</string>\n" +
+ " <string name=\"mapbox_access_token\">" + mapboxAccessToken + "</string>\n" +
"</resources>"
-
- if (tokenFileContents == null) {
- throw new InvalidUserDataException("You must set the MAPBOX_ACCESS_TOKEN environment variable.")
- }
tokenFile.write(tokenFileContents)
}
}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
index 595a2e43dc..234bc583d7 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/style/LineLayerTest.java
@@ -861,6 +861,118 @@ public class LineLayerTest extends BaseActivityTest {
}
@Test
+ public void testLineWidthAsIdentitySourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineWidth(property("FeaturePropertyA", Stops.<Float>identity()))
+ );
+
+ // Verify
+ assertNotNull(layer.getLineWidth());
+ assertNotNull(layer.getLineWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineWidth().getFunction()).getProperty());
+ assertEquals(IdentityStops.class, layer.getLineWidth().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testLineWidthAsExponentialSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineWidth(
+ property(
+ "FeaturePropertyA",
+ exponential(
+ stop(0.3f, lineWidth(0.3f))
+ ).withBase(0.5f)
+ )
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineWidth());
+ assertNotNull(layer.getLineWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineWidth().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getLineWidth().getFunction().getStops().getClass());
+ }
+
+ @Test
+ public void testLineWidthAsCategoricalSourceFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineWidth(
+ property(
+ "FeaturePropertyA",
+ categorical(
+ stop(1.0f, lineWidth(0.3f))
+ )
+ ).withDefaultValue(lineWidth(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineWidth());
+ assertNotNull(layer.getLineWidth().getFunction());
+ assertEquals(SourceFunction.class, layer.getLineWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((SourceFunction) layer.getLineWidth().getFunction()).getProperty());
+ assertEquals(CategoricalStops.class, layer.getLineWidth().getFunction().getStops().getClass());
+ assertNotNull(((SourceFunction) layer.getLineWidth().getFunction()).getDefaultValue());
+ assertNotNull(((SourceFunction) layer.getLineWidth().getFunction()).getDefaultValue().getValue());
+ assertEquals(0.3f, ((SourceFunction) layer.getLineWidth().getFunction()).getDefaultValue().getValue());
+ }
+
+ @Test
+ public void testLineWidthAsCompositeFunction() {
+ validateTestSetup();
+ setupLayer();
+ Timber.i("line-width");
+ assertNotNull(layer);
+
+ // Set
+ layer.setProperties(
+ lineWidth(
+ composite(
+ "FeaturePropertyA",
+ exponential(
+ stop(0, 0.3f, lineWidth(0.9f))
+ ).withBase(0.5f)
+ ).withDefaultValue(lineWidth(0.3f))
+ )
+ );
+
+ // Verify
+ assertNotNull(layer.getLineWidth());
+ assertNotNull(layer.getLineWidth().getFunction());
+ assertEquals(CompositeFunction.class, layer.getLineWidth().getFunction().getClass());
+ assertEquals("FeaturePropertyA", ((CompositeFunction) layer.getLineWidth().getFunction()).getProperty());
+ assertEquals(ExponentialStops.class, layer.getLineWidth().getFunction().getStops().getClass());
+ assertEquals(1, ((ExponentialStops) layer.getLineWidth().getFunction().getStops()).size());
+
+ ExponentialStops<Stop.CompositeValue<Float, Float>, Float> stops =
+ (ExponentialStops<Stop.CompositeValue<Float, Float>, Float>) layer.getLineWidth().getFunction().getStops();
+ Stop<Stop.CompositeValue<Float, Float>, Float> stop = stops.iterator().next();
+ assertEquals(0f, stop.in.zoom, 0.001);
+ assertEquals(0.3f, stop.in.value, 0.001f);
+ assertEquals(0.9f, stop.out, 0.001f);
+ }
+
+ @Test
public void testLineGapWidthTransition() {
validateTestSetup();
setupLayer();
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
index 1a70e4548a..d57136755f 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml
@@ -535,6 +535,17 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".activity.FeatureOverviewActivity"/>
</activity>
+ <activity
+ android:name=".activity.style.AnimatedImageSourceActivity"
+ android:label="@string/activity_animated_image_source"
+ android:description="@string/description_animated_image_source">
+ <meta-data
+ android:name="@string/category"
+ android:value="@string/category_style"/>
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".activity.FeatureOverviewActivity"/>
+ </activity>
<!-- Features -->
<activity
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
index e344343627..deee312bb3 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/MapboxApplication.java
@@ -2,8 +2,11 @@ package com.mapbox.mapboxsdk.testapp;
import android.app.Application;
import android.os.StrictMode;
+import android.text.TextUtils;
+import android.util.Log;
import com.mapbox.mapboxsdk.Mapbox;
+import com.mapbox.mapboxsdk.testapp.utils.TokenUtils;
import com.squareup.leakcanary.LeakCanary;
import timber.log.Timber;
@@ -18,6 +21,13 @@ import static timber.log.Timber.DebugTree;
*/
public class MapboxApplication extends Application {
+ private static final String LOG_TAG = MapboxApplication.class.getSimpleName();
+ private static final String DEFAULT_MAPBOX_ACCESS_TOKEN = "YOUR_MAPBOX_ACCESS_TOKEN_GOES_HERE";
+ private static final String ACCESS_TOKEN_NOT_SET_MESSAGE = "In order to run the Test App you need to set a valid "
+ + "access token. During development, you can set the MAPBOX_ACCESS_TOKEN environment variable for the SDK to "
+ + "automatically include it in the Test App. Otherwise, you can manually include it in the "
+ + "res/values/developer-config.xml file in the MapboxGLAndroidSDKTestApp folder.";
+
@Override
public void onCreate() {
super.onCreate();
@@ -43,7 +53,12 @@ public class MapboxApplication extends Application {
.penaltyDeath()
.build());
- Mapbox.getInstance(getApplicationContext(), getString(R.string.mapbox_access_token));
+ String mapboxAccessToken = TokenUtils.getMapboxAccessToken(getApplicationContext());
+ if (TextUtils.isEmpty(mapboxAccessToken) || mapboxAccessToken.equals(DEFAULT_MAPBOX_ACCESS_TOKEN)) {
+ Log.w(LOG_TAG, ACCESS_TOKEN_NOT_SET_MESSAGE);
+ }
+
+ Mapbox.getInstance(getApplicationContext(), mapboxAccessToken);
}
private void initializeLogger() {
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/AnimatedImageSourceActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/AnimatedImageSourceActivity.java
new file mode 100644
index 0000000000..aeb6751b99
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/style/AnimatedImageSourceActivity.java
@@ -0,0 +1,132 @@
+package com.mapbox.mapboxsdk.testapp.activity.style;
+
+import android.os.Bundle;
+import android.os.Handler;
+import android.support.annotation.NonNull;
+import android.support.v7.app.AppCompatActivity;
+
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.geometry.LatLngQuad;
+import com.mapbox.mapboxsdk.maps.MapView;
+import com.mapbox.mapboxsdk.maps.MapboxMap;
+import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
+import com.mapbox.mapboxsdk.style.layers.RasterLayer;
+import com.mapbox.mapboxsdk.style.sources.ImageSource;
+
+import com.mapbox.mapboxsdk.testapp.R;
+
+/**
+ * Test activity showing how to use a series of images to create an animation
+ * with an ImageSource
+ * <p>
+ * GL-native equivalent of https://www.mapbox.com/mapbox-gl-js/example/animate-images/
+ * </p>
+ */
+public class AnimatedImageSourceActivity extends AppCompatActivity implements OnMapReadyCallback {
+
+ private static final String ID_IMAGE_SOURCE = "animated_image_source";
+ private static final String ID_IMAGE_LAYER = "animated_image_layer";
+
+ private MapView mapView;
+ private MapboxMap mapboxMap;
+
+ private Handler handler;
+ private Runnable runnable;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_animated_image_source);
+
+ mapView = (MapView) findViewById(R.id.mapView);
+ mapView.onCreate(savedInstanceState);
+ mapView.getMapAsync(this);
+ }
+
+ @Override
+ public void onMapReady(@NonNull final MapboxMap map) {
+ mapboxMap = map;
+
+ // add source
+ LatLngQuad quad = new LatLngQuad(
+ new LatLng(46.437, -80.425),
+ new LatLng(46.437, -71.516),
+ new LatLng(37.936, -71.516),
+ new LatLng(37.936, -80.425));
+ mapboxMap.addSource(new ImageSource(ID_IMAGE_SOURCE, quad, R.drawable.southeast_radar_0));
+
+ // add layer
+ RasterLayer layer = new RasterLayer(ID_IMAGE_LAYER, ID_IMAGE_SOURCE);
+ mapboxMap.addLayer(layer);
+
+ // loop refresh geojson
+ handler = new Handler();
+ runnable = new RefreshImageRunnable(mapboxMap, handler);
+ handler.postDelayed(runnable, 100);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ mapView.onStart();
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ mapView.onResume();
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ mapView.onPause();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mapView.onStop();
+ handler.removeCallbacks(runnable);
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mapView.onDestroy();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ mapView.onSaveInstanceState(outState);
+ }
+
+ private static class RefreshImageRunnable implements Runnable {
+
+ private MapboxMap mapboxMap;
+ private Handler handler;
+ private int[] drawables;
+ private int drawableIndex;
+
+ RefreshImageRunnable(MapboxMap mapboxMap, Handler handler) {
+ this.mapboxMap = mapboxMap;
+ this.handler = handler;
+ drawables = new int[4];
+ drawables[0] = R.drawable.southeast_radar_0;
+ drawables[1] = R.drawable.southeast_radar_1;
+ drawables[2] = R.drawable.southeast_radar_2;
+ drawables[3] = R.drawable.southeast_radar_3;
+ drawableIndex = 1;
+ }
+
+ @Override
+ public void run() {
+ ((ImageSource) mapboxMap.getSource(ID_IMAGE_SOURCE)).setImage(drawables[drawableIndex++]);
+ if (drawableIndex > 3) {
+ drawableIndex = 0;
+ }
+ handler.postDelayed(this, 1000);
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java
new file mode 100644
index 0000000000..e08fdb9154
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/utils/TokenUtils.java
@@ -0,0 +1,37 @@
+package com.mapbox.mapboxsdk.testapp.utils;
+
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+
+import com.mapbox.mapboxsdk.Mapbox;
+
+public class TokenUtils {
+
+ /**
+ * <p>
+ * Returns the Mapbox access token set in the app resources.
+ * </p>
+ * It will first search for a token in the Mapbox object. If not found it
+ * will then attempt to load the access token from the
+ * {@code res/values/dev.xml} development file.
+ *
+ * @param context The {@link Context} of the {@link android.app.Activity} or {@link android.app.Fragment}.
+ * @return The Mapbox access token or null if not found.
+ */
+ public static String getMapboxAccessToken(@NonNull Context context) {
+ try {
+ // Read out AndroidManifest
+ String token = Mapbox.getAccessToken();
+ if (token == null || token.isEmpty()) {
+ throw new IllegalArgumentException();
+ }
+ return token;
+ } catch (Exception exception) {
+ // Use fallback on string resource, used for development
+ int tokenResId = context.getResources()
+ .getIdentifier("mapbox_access_token", "string", context.getPackageName());
+ return tokenResId != 0 ? context.getString(tokenResId) : null;
+ }
+ }
+}
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_0.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_0.png
new file mode 100644
index 0000000000..c304b619c4
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_0.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_1.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_1.png
new file mode 100644
index 0000000000..ed09fffbe1
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_1.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_2.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_2.png
new file mode 100644
index 0000000000..fee630f863
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_2.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_3.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_3.png
new file mode 100644
index 0000000000..c4c7146afa
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-mdpi/southeast_radar_3.png
Binary files differ
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_image_source.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_image_source.xml
new file mode 100644
index 0000000000..ac1f08e821
--- /dev/null
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_image_source.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+<com.mapbox.mapboxsdk.maps.MapView
+ android:id="@id/mapView"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ app:mapbox_cameraTargetLat="46.437"
+ app:mapbox_cameraTargetLng="-80.425"
+ app:mapbox_cameraZoom="3"
+ app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
+
+<android.support.design.widget.FloatingActionButton
+ android:id="@+id/fabStartStop"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_alignParentBottom="true"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentRight="true"
+ android:layout_marginBottom="@dimen/fab_margin"
+ android:layout_marginRight="@dimen/fab_margin"
+ android:src="@android:drawable/ic_media_play"
+ app:backgroundTint="@color/primary"/>
+
+</RelativeLayout>
diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
index 74833105a4..7f9a08fd30 100644
--- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
+++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml
@@ -59,6 +59,7 @@
<string name="activity_restricted_bounds">Restrict camera to a bounds</string>
<string name="activity_fill_extrusion_layer">Fill extrusions</string>
<string name="activity_building_fill_extrusion_layer">Building layer</string>
+ <string name="activity_animated_image_source">Animated Image Source</string>
<!--Description-->
<string name="description_user_location_tracking">Tracks the location of the user</string>
@@ -117,6 +118,7 @@
<string name="description_restricted_bounds">Limit viewport to Iceland</string>
<string name="description_fill_extrusion_layer">Shows how to add 3D extruded shapes</string>
<string name="description_building_fill_extrusion_layer">Shows how to show 3D extruded buildings</string>
+ <string name="description_animated_image_source">Shows how to animate georeferenced images</string>
<!--Categories-->
<string name="category">category</string>
diff --git a/platform/android/bitrise.yml b/platform/android/bitrise.yml
deleted file mode 100644
index dcd4d4fb50..0000000000
--- a/platform/android/bitrise.yml
+++ /dev/null
@@ -1,235 +0,0 @@
----
-format_version: 1.0.0
-default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
-trigger_map:
-- pattern: devicefarmUpload
- workflow: devicefarmUpload
-- pattern: scheduled
- workflow: scheduled
-- pattern: nightly-release
- workflow: nightly-release
-- pattern: "*"
- workflow: primary
-workflows:
- primary:
- steps:
- - script:
- title: Build libmapbox-gl.so for armeabi-v7a
- inputs:
- - content: |-
- #!/bin/bash
- echo "Compile libmapbox-gl.so for armeabi-v7a abi:"
- ccache -z
- BUILDTYPE=Debug make android-lib-arm-v7
- ccache -s
- - script:
- title: Compile Core tests
- inputs:
- - content: |-
- #!/bin/bash
- echo "Compiling core tests:"
- ccache -z
- BUILDTYPE=Debug make android-test-lib-arm-v7
- ccache -s
- - script:
- title: Run local JVM Unit tests on phone module
- inputs:
- - content: |-
- #!/bin/bash
- echo "Running unit tests from MapboxGLAndroidSDKTestApp/src/test:"
- make run-android-unit-test
- - script:
- title: Run local JVM Unit tests on wear module
- inputs:
- - content: |-
- #!/bin/bash
- echo "Running unit tests from MapboxGLAndroidSDKWearTestApp/src/test:"
- make run-android-wear-unit-test
- - script:
- title: Generate Espresso sanity tests
- inputs:
- - content: |-
- #!/bin/bash
- echo "Generate these test locally by executing:"
- make test-code-android
- - script:
- title: Run Checkstyle
- inputs:
- - content: |-
- #!/bin/bash
- # Run checkstyle gradle task on all modules
- make android-checkstyle
- - script:
- title: Run Firebase instrumentation tests
- run_if: '{{getenv "BITRISEIO_GCLOUD_SERVICE_ACCOUNT_JSON_URL" | ne ""}}'
- inputs:
- - content: |-
- #!/bin/bash
- set -euo pipefail
- echo "Downloading Google Cloud authentication:"
- wget -O secret.json "$BITRISEIO_GCLOUD_SERVICE_ACCOUNT_JSON_URL"
-
- echo "Downloading Mapbox accesstoken for running tests:"
- wget -O platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/developer-config.xml "$BITRISEIO_TEST_ACCESS_TOKEN_UI_TEST_URL"
-
- echo "Build seperate test apk:"
- ccache -z
- make android-ui-test-arm-v7
- ccache -s
-
- echo "Run tests on firebase:"
- gcloud auth activate-service-account --key-file secret.json --project android-gl-native
- gcloud beta test android devices list
- gcloud beta test android run --type instrumentation --app platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug.apk --test platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-androidTest.apk --device-ids shamu --os-version-ids 22 --locales en --orientations portrait --timeout 15m --test-targets "class com.mapbox.mapboxsdk.testapp.maps.widgets.AttributionTest"
- - script:
- title: Download Firebase results
- is_always_run: true
- run_if: '{{getenv "BITRISEIO_GCLOUD_SERVICE_ACCOUNT_JSON_URL" | ne ""}}'
- inputs:
- - content: |-
- #!/bin/bash
- set -euo pipefail
- mkdir -p platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk
-
- echo "The details from Firebase will be downloaded, zipped and attached as a build artefact."
- testUri=$(gsutil ls "gs://test-lab-wrrntqk05p31w-h3y1qk44vuunw/" | tail -n1)
- echo "Downloading from : "$testUri
- gsutil -m cp -R -Z $testUri platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk
-
- echo "Try running ndk-stack on downloaded logcat to symbolicate the stacktraces:"
- find platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk -type f -name "logcat" -print0 | xargs -0 -Imylogcat mv -i mylogcat ./
- cat logcat | ndk-stack -sym build/android-arm-v7/Debug
- - deploy-to-bitrise-io:
- inputs:
- - deploy_path: platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk
- - is_compress: 'true'
- - notify_user_groups: none
- - slack:
- title: Post to Slack
- inputs:
- - webhook_url: "$SLACK_HOOK_URL"
- - channel: "#gl-bots"
- - from_username: 'Bitrise Android'
- - from_username_on_error: 'Bitrise Android'
- - message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
- for <https://github.com/mapbox/mapbox-gl-native/compare/${BITRISE_GIT_BRANCH}|mapbox/mapbox-gl-native@${BITRISE_GIT_BRANCH}>
- by ${GIT_CLONE_COMMIT_COMMITER_NAME}
- passed'
- - message_on_error: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
- for <https://github.com/mapbox/mapbox-gl-native/compare/${BITRISE_GIT_BRANCH}|mapbox/mapbox-gl-native@${BITRISE_GIT_BRANCH}>
- by ${GIT_CLONE_COMMIT_COMMITER_NAME}
- failed'
- - icon_url: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-icon-128.png
- - icon_url_on_error: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-error-icon-128.png
- scheduled:
- steps:
- - script:
- title: Download maven credentials
- inputs:
- - content: |-
- #!/bin/bash
- aws s3 cp s3://mapbox/android/signing-credentials/secring.gpg platform/android/MapboxGLAndroidSDK/secring.gpg
-
- # Add maven credentals for publishing
- echo "NEXUS_USERNAME=$PUBLISH_NEXUS_USERNAME
- NEXUS_PASSWORD=$PUBLISH_NEXUS_PASSWORD
- signing.keyId=$SIGNING_KEYID
- signing.password=$SIGNING_PASSWORD
- signing.secretKeyRingFile=secring.gpg" >> platform/android/MapboxGLAndroidSDK/gradle.properties
- - script:
- title: Build release
- inputs:
- - content: |-
- #!/bin/bash
- echo "Compile libmapbox-gl.so for all supportd abi's:"
- BUILDTYPE=Release make android-lib-arm-v5
- BUILDTYPE=Release make android-lib-arm-v7
- BUILDTYPE=Release make android-lib-arm-v8
- BUILDTYPE=Release make android-lib-x86
- BUILDTYPE=Release make android-lib-mips
- BUILDTYPE=Release make android-lib-mips-64
- cd platform/android && ./gradlew -Pmapbox.abis=armeabi-v7a MapboxGLAndroidSDK:assembleRelease
- - script:
- title: Publish to maven
- inputs:
- - content: |-
- #!/bin/bash
- echo "Upload aar file to maven:"
- make run-android-upload-archives
- - slack:
- title: Post to Slack
- inputs:
- - webhook_url: "$SLACK_HOOK_URL"
- - channel: "#gl-bots"
- - from_username: 'Bitrise Android'
- - from_username_on_error: 'Bitrise Android'
- - message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}> Publish of nightly Android SDK SNAPSHOT to maven succeeded.'
- - message_on_error: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}> Publish of nightly Android SDK SNAPSHOT to maven failed. @android_team.'
- - icon_url: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-icon-128.png
- - icon_url_on_error: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-error-icon-128.png
- devicefarmUpload:
- steps:
- - script:
- title: Build release
- inputs:
- - content: |-
- #!/bin/bash
- echo "Compile libmapbox-gl.so for all supportd abi's:"
- export BUILDTYPE=Release
- make apackage
- - script:
- title: Add AWS credentials
- inputs:
- - content: |-
- #!/bin/bash
- echo "AWS_ACCESS_KEY_ID_DEVICE_FARM=$AWS_ACCESS_KEY_ID_DEVICE_FARM" >> platform/android/MapboxGLAndroidSDKTestApp/gradle.properties
- echo "AWS_SECRET_ACCESS_KEY_DEVICE_FARM=$AWS_SECRET_ACCESS_KEY_DEVICE_FARM" >> platform/android/MapboxGLAndroidSDKTestApp/gradle.properties
- - script:
- title: Generate sanity tests
- inputs:
- - content: |-
- #!/bin/bash
- echo "Generate these test locally by executing:"
- make test-code-android
- - script:
- title: Run AWS Device Farm instrumentation tests
- inputs:
- - content: |-
- #!/bin/bash
- echo "Run tests on device farm:"
- make run-android-ui-test-aws
- - slack:
- title: Post to Slack
- inputs:
- - webhook_url: "$SLACK_HOOK_URL"
- - channel: "#gl-bots"
- - from_username: 'Bitrise Android'
- - from_username_on_error: 'Bitrise Android'
- - message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}> for devicefarmUpload passed'
- - message_on_error: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}> for devicefarmUpload failed'
- - icon_url: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-icon-128.png
- - icon_url_on_error: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-error-icon-128.png
- nightly-release:
- steps:
- - script:
- title: Configure AWS-CLI
- inputs:
- - content: |-
- #!/bin/bash
- apt-get install -y python-pip python-dev build-essential
- pip install awscli
- - script:
- title: Build release
- inputs:
- - content: |-
- #!/bin/bash
- echo "Compile libmapbox-gl.so for all supportd abi's:"
- export BUILDTYPE=Release
- make apackage
- - script:
- title: Log metrics
- inputs:
- - content: |-
- #!/bin/bash
- echo "Log binary size metrics to AWS CloudWatch:"
- CLOUDWATCH=true platform/android/scripts/metrics.sh
diff --git a/platform/android/config.cmake b/platform/android/config.cmake
index 84591d644b..a7370da5fd 100644
--- a/platform/android/config.cmake
+++ b/platform/android/config.cmake
@@ -158,6 +158,8 @@ add_library(mbgl-android STATIC
platform/android/src/style/sources/unknown_source.hpp
platform/android/src/style/sources/vector_source.cpp
platform/android/src/style/sources/vector_source.hpp
+ platform/android/src/style/sources/image_source.hpp
+ platform/android/src/style/sources/image_source.cpp
platform/android/src/style/functions/stop.cpp
platform/android/src/style/functions/stop.hpp
platform/android/src/style/functions/categorical_stops.cpp
@@ -222,6 +224,8 @@ add_library(mbgl-android STATIC
platform/android/src/geometry/lat_lng.hpp
platform/android/src/geometry/lat_lng_bounds.cpp
platform/android/src/geometry/lat_lng_bounds.hpp
+ platform/android/src/geometry/lat_lng_quad.cpp
+ platform/android/src/geometry/lat_lng_quad.hpp
platform/android/src/geometry/projected_meters.cpp
platform/android/src/geometry/projected_meters.hpp
diff --git a/platform/android/src/asset_manager_file_source.cpp b/platform/android/src/asset_manager_file_source.cpp
index 6a3113d696..aa65e3ff48 100644
--- a/platform/android/src/asset_manager_file_source.cpp
+++ b/platform/android/src/asset_manager_file_source.cpp
@@ -1,5 +1,6 @@
#include "asset_manager_file_source.hpp"
+#include <mbgl/storage/file_source_request.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/util.hpp>
#include <mbgl/util/thread.hpp>
@@ -12,10 +13,10 @@ namespace mbgl {
class AssetManagerFileSource::Impl {
public:
- Impl(AAssetManager* assetManager_) : assetManager(assetManager_) {
+ Impl(ActorRef<Impl>, AAssetManager* assetManager_) : assetManager(assetManager_) {
}
- void request(const std::string& url, FileSource::Callback callback) {
+ void request(const std::string& url, ActorRef<FileSourceRequest> req) {
// Note: AssetManager already prepends "assets" to the filename.
const std::string path = mbgl::util::percentDecode(url.substr(8));
@@ -30,7 +31,7 @@ public:
"Could not read asset");
}
- callback(response);
+ req.invoke(&FileSourceRequest::setResponse, response);
}
private:
@@ -39,15 +40,18 @@ private:
AssetManagerFileSource::AssetManagerFileSource(jni::JNIEnv& env, jni::Object<android::AssetManager> assetManager_)
: assetManager(assetManager_.NewGlobalRef(env)),
- thread(std::make_unique<util::Thread<Impl>>(
- util::ThreadContext{"AssetManagerFileSource", util::ThreadPriority::Low},
- AAssetManager_fromJava(&env, jni::Unwrap(**assetManager)))) {
+ impl(std::make_unique<util::Thread<Impl>>("AssetManagerFileSource",
+ AAssetManager_fromJava(&env, jni::Unwrap(**assetManager)))) {
}
AssetManagerFileSource::~AssetManagerFileSource() = default;
std::unique_ptr<AsyncRequest> AssetManagerFileSource::request(const Resource& resource, Callback callback) {
- return thread->invokeWithCallback(&Impl::request, resource.url, callback);
+ auto req = std::make_unique<FileSourceRequest>(std::move(callback));
+
+ impl->actor().invoke(&Impl::request, resource.url, req->actor());
+
+ return std::move(req);
}
} // namespace mbgl
diff --git a/platform/android/src/asset_manager_file_source.hpp b/platform/android/src/asset_manager_file_source.hpp
index 7a447a2c61..dcad95664a 100644
--- a/platform/android/src/asset_manager_file_source.hpp
+++ b/platform/android/src/asset_manager_file_source.hpp
@@ -20,9 +20,10 @@ public:
std::unique_ptr<AsyncRequest> request(const Resource&, Callback) override;
private:
- jni::UniqueObject<android::AssetManager> assetManager;
class Impl;
- std::unique_ptr<util::Thread<Impl>> thread;
+
+ jni::UniqueObject<android::AssetManager> assetManager;
+ std::unique_ptr<util::Thread<Impl>> impl;
};
} // namespace mbgl
diff --git a/platform/android/src/conversion/constant.hpp b/platform/android/src/conversion/constant.hpp
index 2a0b710f73..f1c72eb5dd 100644
--- a/platform/android/src/conversion/constant.hpp
+++ b/platform/android/src/conversion/constant.hpp
@@ -3,6 +3,7 @@
#include "conversion.hpp"
#include <mbgl/util/optional.hpp>
+#include <mbgl/util/color.hpp>
#include <jni/jni.hpp>
#include <string>
diff --git a/platform/android/src/file_source.cpp b/platform/android/src/file_source.cpp
index 16c09b7b52..5d19c506bc 100644
--- a/platform/android/src/file_source.cpp
+++ b/platform/android/src/file_source.cpp
@@ -1,6 +1,9 @@
#include "file_source.hpp"
+#include <mbgl/actor/actor.hpp>
+#include <mbgl/storage/resource_transform.hpp>
#include <mbgl/util/logging.hpp>
+#include <mbgl/util/run_loop.hpp>
#include "asset_manager_file_source.hpp"
#include "jni/generic_global_ref_deleter.hpp"
@@ -42,21 +45,22 @@ void FileSource::setAPIBaseUrl(jni::JNIEnv& env, jni::String url) {
void FileSource::setResourceTransform(jni::JNIEnv& env, jni::Object<FileSource::ResourceTransformCallback> transformCallback) {
if (transformCallback) {
- // Launch transformCallback
- fileSource->setResourceTransform([
+ resourceTransform = std::make_unique<Actor<ResourceTransform>>(*util::RunLoop::Get(),
// Capture the ResourceTransformCallback object as a managed global into
// the lambda. It is released automatically when we're setting a new ResourceTransform in
// a subsequent call.
// Note: we're converting it to shared_ptr because this lambda is converted to a std::function,
// which requires copyability of its captured variables.
- callback = std::shared_ptr<jni::jobject>(transformCallback.NewGlobalRef(env).release()->Get(), GenericGlobalRefDeleter())
- ](mbgl::Resource::Kind kind, std::string&& url_) {
- android::UniqueEnv _env = android::AttachEnv();
- return FileSource::ResourceTransformCallback::onURL(*_env, jni::Object<FileSource::ResourceTransformCallback>(*callback), int(kind), url_);
- });
+ [callback = std::shared_ptr<jni::jobject>(transformCallback.NewGlobalRef(env).release()->Get(), GenericGlobalRefDeleter())]
+ (mbgl::Resource::Kind kind, const std::string&& url_) {
+ android::UniqueEnv _env = android::AttachEnv();
+ return FileSource::ResourceTransformCallback::onURL(*_env, jni::Object<FileSource::ResourceTransformCallback>(*callback), int(kind), url_);
+ });
+ fileSource->setResourceTransform(resourceTransform->self());
} else {
// Reset the callback
- fileSource->setResourceTransform(nullptr);
+ resourceTransform.reset();
+ fileSource->setResourceTransform({});
}
}
@@ -106,4 +110,4 @@ std::string FileSource::ResourceTransformCallback::onURL(jni::JNIEnv& env, jni::
}
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/file_source.hpp b/platform/android/src/file_source.hpp
index 55e70f34d9..4abe352bff 100644
--- a/platform/android/src/file_source.hpp
+++ b/platform/android/src/file_source.hpp
@@ -7,6 +7,10 @@
#include <jni/jni.hpp>
namespace mbgl {
+
+template <typename T> class Actor;
+class ResourceTransform;
+
namespace android {
/**
@@ -46,10 +50,10 @@ public:
static void registerNative(jni::JNIEnv&);
private:
-
+ std::unique_ptr<Actor<ResourceTransform>> resourceTransform;
std::unique_ptr<mbgl::DefaultFileSource> fileSource;
};
} // namespace android
-} // namespace mbgl \ No newline at end of file
+} // namespace mbgl
diff --git a/platform/android/src/geometry/lat_lng_quad.cpp b/platform/android/src/geometry/lat_lng_quad.cpp
new file mode 100644
index 0000000000..2b36139e18
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng_quad.cpp
@@ -0,0 +1,39 @@
+#include "lat_lng_quad.hpp"
+#include "lat_lng.hpp"
+
+namespace mbgl {
+namespace android {
+
+jni::Object<LatLngQuad> LatLngQuad::New(jni::JNIEnv& env, std::array<mbgl::LatLng, 4> coordinates) {
+ static auto quadConstructor = LatLngQuad::javaClass.GetConstructor<jni::Object<LatLng>, jni::Object<LatLng>, jni::Object<LatLng>, jni::Object<LatLng>>(env);
+ return LatLngQuad::javaClass.New(env, quadConstructor,
+ LatLng::New(env, coordinates[0]),
+ LatLng::New(env, coordinates[1]),
+ LatLng::New(env, coordinates[2]),
+ LatLng::New(env, coordinates[3]));
+}
+
+std::array<mbgl::LatLng, 4> LatLngQuad::getLatLngArray(jni::JNIEnv& env, jni::Object<LatLngQuad> quad) {
+ static auto topLeftField = LatLngQuad::javaClass.GetField <jni::Object<LatLng>>(env, "topLeft");
+ static auto topRightField = LatLngQuad::javaClass.GetField <jni::Object<LatLng>>(env, "topRight");
+ static auto bottomRightField = LatLngQuad::javaClass.GetField <jni::Object<LatLng>>(env, "bottomRight");
+ static auto bottomLeftField = LatLngQuad::javaClass.GetField <jni::Object<LatLng>>(env, "bottomLeft");
+
+ return std::array < mbgl::LatLng, 4 > {{
+ LatLng::getLatLng(env, quad.Get(env, topLeftField)),
+ LatLng::getLatLng(env, quad.Get(env, topRightField)),
+ LatLng::getLatLng(env, quad.Get(env, bottomRightField)),
+ LatLng::getLatLng(env, quad.Get(env, bottomLeftField))
+ }};
+}
+
+void LatLngQuad::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ LatLngQuad::javaClass = *jni::Class<LatLngQuad>::Find(env).NewGlobalRef(env).release();
+}
+
+jni::Class<LatLngQuad> LatLngQuad::javaClass;
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/geometry/lat_lng_quad.hpp b/platform/android/src/geometry/lat_lng_quad.hpp
new file mode 100644
index 0000000000..8f8c9abeef
--- /dev/null
+++ b/platform/android/src/geometry/lat_lng_quad.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/geo.hpp>
+#include <mbgl/util/geometry.hpp>
+
+#include <jni/jni.hpp>
+#include <array>
+
+namespace mbgl {
+namespace android {
+
+class LatLngQuad : private mbgl::util::noncopyable {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/geometry/LatLngQuad"; };
+
+ static jni::Object<LatLngQuad> New(jni::JNIEnv&, std::array<mbgl::LatLng, 4>);
+
+ static std::array<mbgl::LatLng, 4> getLatLngArray(jni::JNIEnv&, jni::Object<LatLngQuad>);
+
+ static jni::Class<LatLngQuad> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+};
+
+
+} // namespace android
+} // namespace mbgl \ No newline at end of file
diff --git a/platform/android/src/jni.cpp b/platform/android/src/jni.cpp
index 6c490fad5c..db8dd1dbdf 100755
--- a/platform/android/src/jni.cpp
+++ b/platform/android/src/jni.cpp
@@ -23,6 +23,7 @@
#include "geojson/position.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"
@@ -127,6 +128,7 @@ void registerNatives(JavaVM *vm) {
// Geometry
LatLng::registerNative(env);
LatLngBounds::registerNative(env);
+ LatLngQuad::registerNative(env);
ProjectedMeters::registerNative(env);
// GSon
diff --git a/platform/android/src/native_map_view.cpp b/platform/android/src/native_map_view.cpp
index 0a57d3e6b4..79e7c3c82f 100755
--- a/platform/android/src/native_map_view.cpp
+++ b/platform/android/src/native_map_view.cpp
@@ -25,6 +25,7 @@
#include <mbgl/util/logging.hpp>
#include <mbgl/util/platform.hpp>
#include <mbgl/util/projection.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/style/filter.hpp>
@@ -55,13 +56,9 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env,
jni::Object<NativeMapView> _obj,
jni::Object<FileSource> jFileSource,
jni::jfloat _pixelRatio,
- jni::String _programCacheDir,
- jni::jint _availableProcessors,
- jni::jlong _totalMemory)
+ jni::String _programCacheDir)
: javaPeer(_obj.NewWeakGlobalRef(_env)),
pixelRatio(_pixelRatio),
- availableProcessors(_availableProcessors),
- totalMemory(_totalMemory),
threadPool(sharedThreadPool()) {
// Get a reference to the JavaVM for callbacks
@@ -76,19 +73,6 @@ NativeMapView::NativeMapView(jni::JNIEnv& _env,
pixelRatio, mbgl::android::FileSource::getDefaultFileSource(_env, jFileSource), *threadPool,
MapMode::Continuous, GLContextMode::Unique, ConstrainMode::HeightOnly,
ViewportMode::Default, jni::Make<std::string>(_env, _programCacheDir));
-
- recalculateSourceTileCacheSize();
-}
-
-void NativeMapView::recalculateSourceTileCacheSize() {
- //Calculate a fitting cache size based on device parameters
- float zoomFactor = map->getMaxZoom() - map->getMinZoom() + 1;
- float cpuFactor = availableProcessors;
- float memoryFactor = static_cast<float>(totalMemory) / 1000.0f / 1000.0f / 1000.0f;
- float sizeFactor = (static_cast<float>(map->getSize().width) / mbgl::util::tileSize) *
- (static_cast<float>(map->getSize().height) / mbgl::util::tileSize);
-
- map->setSourceTileCacheSize(zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f);
}
/**
@@ -109,7 +93,7 @@ NativeMapView::~NativeMapView() {
*/
void NativeMapView::bind() {
setFramebufferBinding(0);
- setViewportSize(getFramebufferSize());
+ setViewport(0, 0, getFramebufferSize());
}
/**
@@ -292,7 +276,7 @@ void NativeMapView::render(jni::JNIEnv& env) {
BackendScope guard(*this);
if (framebufferSizeChanged) {
- setViewportSize(getFramebufferSize());
+ setViewport(0, 0, getFramebufferSize());
framebufferSizeChanged = false;
}
@@ -332,7 +316,6 @@ void NativeMapView::resizeView(jni::JNIEnv&, int w, int h) {
width = util::max(64, w);
height = util::max(64, h);
map->setSize({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
- recalculateSourceTileCacheSize();
}
void NativeMapView::resizeFramebuffer(jni::JNIEnv&, int w, int h) {
@@ -343,19 +326,19 @@ void NativeMapView::resizeFramebuffer(jni::JNIEnv&, int w, int h) {
}
jni::String NativeMapView::getStyleUrl(jni::JNIEnv& env) {
- return jni::Make<jni::String>(env, map->getStyleURL());
+ return jni::Make<jni::String>(env, map->getStyle().getURL());
}
void NativeMapView::setStyleUrl(jni::JNIEnv& env, jni::String url) {
- map->setStyleURL(jni::Make<std::string>(env, url));
+ map->getStyle().loadURL(jni::Make<std::string>(env, url));
}
jni::String NativeMapView::getStyleJson(jni::JNIEnv& env) {
- return jni::Make<jni::String>(env, map->getStyleJSON());
+ return jni::Make<jni::String>(env, map->getStyle().getJSON());
}
void NativeMapView::setStyleJson(jni::JNIEnv& env, jni::String json) {
- map->setStyleJSON(jni::Make<std::string>(env, json));
+ map->getStyle().loadJSON(jni::Make<std::string>(env, json));
}
void NativeMapView::setLatLngBounds(jni::JNIEnv& env, jni::Object<mbgl::android::LatLngBounds> jBounds) {
@@ -487,7 +470,6 @@ void NativeMapView::resetZoom(jni::JNIEnv&) {
void NativeMapView::setMinZoom(jni::JNIEnv&, jni::jdouble zoom) {
map->setMinZoom(zoom);
- recalculateSourceTileCacheSize();
}
jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) {
@@ -496,7 +478,6 @@ jni::jdouble NativeMapView::getMinZoom(jni::JNIEnv&) {
void NativeMapView::setMaxZoom(jni::JNIEnv&, jni::jdouble zoom) {
map->setMaxZoom(zoom);
- recalculateSourceTileCacheSize();
}
jni::jdouble NativeMapView::getMaxZoom(jni::JNIEnv&) {
@@ -736,8 +717,8 @@ void NativeMapView::addAnnotationIcon(JNIEnv& env, jni::String symbol, jint w, j
}
jni::GetArrayRegion(env, *jpixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
- map->addAnnotationImage(symbolName,
- std::make_unique<mbgl::style::Image>(std::move(premultipliedImage), float(scale)));
+ map->addAnnotationImage(std::make_unique<mbgl::style::Image>(
+ symbolName, std::move(premultipliedImage), float(scale)));
}
jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, jni::String symbolName) {
@@ -745,25 +726,25 @@ jdouble NativeMapView::getTopOffsetPixelsForAnnotationSymbol(JNIEnv& env, jni::S
}
jlong NativeMapView::getTransitionDuration(JNIEnv&) {
- const auto transitionOptions = map->getTransitionOptions();
+ const auto transitionOptions = map->getStyle().getTransitionOptions();
return std::chrono::duration_cast<std::chrono::milliseconds>(transitionOptions.duration.value_or(mbgl::Duration::zero())).count();
}
void NativeMapView::setTransitionDuration(JNIEnv&, jlong duration) {
- auto transitionOptions = map->getTransitionOptions();
+ auto transitionOptions = map->getStyle().getTransitionOptions();
transitionOptions.duration.emplace(mbgl::Milliseconds(duration));
- map->setTransitionOptions(transitionOptions);
+ map->getStyle().setTransitionOptions(transitionOptions);
}
jlong NativeMapView::getTransitionDelay(JNIEnv&) {
- const auto transitionOptions = map->getTransitionOptions();
+ const auto transitionOptions = map->getStyle().getTransitionOptions();
return std::chrono::duration_cast<std::chrono::milliseconds>(transitionOptions.delay.value_or(mbgl::Duration::zero())).count();
}
void NativeMapView::setTransitionDelay(JNIEnv&, jlong delay) {
- auto transitionOptions = map->getTransitionOptions();
+ auto transitionOptions = map->getStyle().getTransitionOptions();
transitionOptions.delay.emplace(mbgl::Milliseconds(delay));
- map->setTransitionOptions(transitionOptions);
+ map->getStyle().setTransitionOptions(transitionOptions);
}
jni::Array<jlong> NativeMapView::queryPointAnnotations(JNIEnv& env, jni::Object<RectF> rect) {
@@ -821,7 +802,7 @@ jni::Array<jni::Object<geojson::Feature>> NativeMapView::queryRenderedFeaturesFo
}
jni::Object<Light> NativeMapView::getLight(JNIEnv& env) {
- mbgl::style::Light* light = map->getLight();
+ mbgl::style::Light* light = map->getStyle().getLight();
if (light) {
return jni::Object<Light>(Light::createJavaLightPeer(env, *map, *light));
} else {
@@ -832,7 +813,7 @@ jni::Object<Light> NativeMapView::getLight(JNIEnv& env) {
jni::Array<jni::Object<Layer>> NativeMapView::getLayers(JNIEnv& env) {
// Get the core layers
- std::vector<style::Layer*> layers = map->getLayers();
+ std::vector<style::Layer*> layers = map->getStyle().getLayers();
// Convert
jni::Array<jni::Object<Layer>> jLayers = jni::Array<jni::Object<Layer>>::New(env, layers.size(), Layer::javaClass);
@@ -850,7 +831,7 @@ jni::Array<jni::Object<Layer>> NativeMapView::getLayers(JNIEnv& env) {
jni::Object<Layer> NativeMapView::getLayer(JNIEnv& env, jni::String layerId) {
// Find the layer
- mbgl::style::Layer* coreLayer = map->getLayer(jni::Make<std::string>(env, layerId));
+ mbgl::style::Layer* coreLayer = map->getStyle().getLayer(jni::Make<std::string>(env, layerId));
if (!coreLayer) {
mbgl::Log::Debug(mbgl::Event::JNI, "No layer found");
return jni::Object<Layer>();
@@ -877,7 +858,7 @@ void NativeMapView::addLayerAbove(JNIEnv& env, jlong nativeLayerPtr, jni::String
Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
// Find the sibling
- auto layers = map->getLayers();
+ auto layers = map->getStyle().getLayers();
auto siblingId = jni::Make<std::string>(env, above);
size_t index = 0;
@@ -912,7 +893,7 @@ void NativeMapView::addLayerAt(JNIEnv& env, jlong nativeLayerPtr, jni::jint inde
assert(nativeLayerPtr != 0);
Layer *layer = reinterpret_cast<Layer *>(nativeLayerPtr);
- auto layers = map->getLayers();
+ auto layers = map->getStyle().getLayers();
// Check index
int numLayers = layers.size() - 1;
@@ -935,7 +916,7 @@ void NativeMapView::addLayerAt(JNIEnv& env, jlong nativeLayerPtr, jni::jint inde
* Remove by layer id.
*/
jni::Object<Layer> NativeMapView::removeLayerById(JNIEnv& env, jni::String id) {
- std::unique_ptr<mbgl::style::Layer> coreLayer = map->removeLayer(jni::Make<std::string>(env, id));
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->getStyle().removeLayer(jni::Make<std::string>(env, id));
if (coreLayer) {
return jni::Object<Layer>(createJavaLayerPeer(env, *map, std::move(coreLayer)));
} else {
@@ -947,7 +928,7 @@ jni::Object<Layer> NativeMapView::removeLayerById(JNIEnv& env, jni::String id) {
* Remove layer at index.
*/
jni::Object<Layer> NativeMapView::removeLayerAt(JNIEnv& env, jni::jint index) {
- auto layers = map->getLayers();
+ auto layers = map->getStyle().getLayers();
// Check index
int numLayers = layers.size() - 1;
@@ -956,7 +937,7 @@ jni::Object<Layer> NativeMapView::removeLayerAt(JNIEnv& env, jni::jint index) {
return jni::Object<Layer>();
}
- std::unique_ptr<mbgl::style::Layer> coreLayer = map->removeLayer(layers.at(index)->getID());
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->getStyle().removeLayer(layers.at(index)->getID());
if (coreLayer) {
return jni::Object<Layer>(createJavaLayerPeer(env, *map, std::move(coreLayer)));
} else {
@@ -971,7 +952,7 @@ void NativeMapView::removeLayer(JNIEnv&, jlong layerPtr) {
assert(layerPtr != 0);
mbgl::android::Layer *layer = reinterpret_cast<mbgl::android::Layer *>(layerPtr);
- std::unique_ptr<mbgl::style::Layer> coreLayer = map->removeLayer(layer->get().getID());
+ std::unique_ptr<mbgl::style::Layer> coreLayer = map->getStyle().removeLayer(layer->get().getID());
if (coreLayer) {
layer->setLayer(std::move(coreLayer));
}
@@ -979,7 +960,7 @@ void NativeMapView::removeLayer(JNIEnv&, jlong layerPtr) {
jni::Array<jni::Object<Source>> NativeMapView::getSources(JNIEnv& env) {
// Get the core sources
- std::vector<style::Source*> sources = map->getSources();
+ std::vector<style::Source*> sources = map->getStyle().getSources();
// Convert
jni::Array<jni::Object<Source>> jSources = jni::Array<jni::Object<Source>>::New(env, sources.size(), Source::javaClass);
@@ -996,7 +977,7 @@ jni::Array<jni::Object<Source>> NativeMapView::getSources(JNIEnv& env) {
jni::Object<Source> NativeMapView::getSource(JNIEnv& env, jni::String sourceId) {
// Find the source
- mbgl::style::Source* coreSource = map->getSource(jni::Make<std::string>(env, sourceId));
+ mbgl::style::Source* coreSource = map->getStyle().getSource(jni::Make<std::string>(env, sourceId));
if (!coreSource) {
mbgl::Log::Debug(mbgl::Event::JNI, "No source found");
return jni::Object<Source>();
@@ -1018,7 +999,7 @@ void NativeMapView::addSource(JNIEnv& env, jni::jlong sourcePtr) {
}
jni::Object<Source> NativeMapView::removeSourceById(JNIEnv& env, jni::String id) {
- std::unique_ptr<mbgl::style::Source> coreSource = map->removeSource(jni::Make<std::string>(env, id));
+ std::unique_ptr<mbgl::style::Source> coreSource = map->getStyle().removeSource(jni::Make<std::string>(env, id));
if (coreSource) {
return jni::Object<Source>(createJavaSourcePeer(env, *map, *coreSource));
} else {
@@ -1030,7 +1011,7 @@ void NativeMapView::removeSource(JNIEnv&, jlong sourcePtr) {
assert(sourcePtr != 0);
mbgl::android::Source *source = reinterpret_cast<mbgl::android::Source *>(sourcePtr);
- std::unique_ptr<mbgl::style::Source> coreSource = map->removeSource(source->get().getID());
+ std::unique_ptr<mbgl::style::Source> coreSource = map->getStyle().removeSource(source->get().getID());
if (coreSource) {
source->setSource(std::move(coreSource));
}
@@ -1047,12 +1028,14 @@ void NativeMapView::addImage(JNIEnv& env, jni::String name, jni::jint w, jni::ji
jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
- map->addImage(jni::Make<std::string>(env, name),
- std::make_unique<mbgl::style::Image>(std::move(premultipliedImage), float(scale)));
+ map->getStyle().addImage(std::make_unique<mbgl::style::Image>(
+ jni::Make<std::string>(env, name),
+ std::move(premultipliedImage),
+ float(scale)));
}
void NativeMapView::removeImage(JNIEnv& env, jni::String name) {
- map->removeImage(jni::Make<std::string>(env, name));
+ map->getStyle().removeImage(jni::Make<std::string>(env, name));
}
// Private methods //
@@ -1428,7 +1411,7 @@ mbgl::Size NativeMapView::getFramebufferSize() const {
void NativeMapView::updateAssumedState() {
assumeFramebufferBinding(0);
- assumeViewportSize(getFramebufferSize());
+ assumeViewport(0, 0, getFramebufferSize());
}
void NativeMapView::updateFps() {
@@ -1470,7 +1453,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
// Register the peer
jni::RegisterNativePeer<NativeMapView>(env, NativeMapView::javaClass, "nativePtr",
- std::make_unique<NativeMapView, JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::jfloat, jni::String, jni::jint, jni::jlong>,
+ std::make_unique<NativeMapView, JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::jfloat, jni::String>,
"nativeInitialize",
"nativeDestroy",
METHOD(&NativeMapView::render, "nativeRender"),
diff --git a/platform/android/src/native_map_view.hpp b/platform/android/src/native_map_view.hpp
index df43ad08b7..393a2c913f 100755
--- a/platform/android/src/native_map_view.hpp
+++ b/platform/android/src/native_map_view.hpp
@@ -49,9 +49,7 @@ public:
jni::Object<NativeMapView>,
jni::Object<FileSource>,
jni::jfloat pixelRatio,
- jni::String programCacheDir,
- jni::jint availableProcessors,
- jni::jlong totalMemory);
+ jni::String programCacheDir);
virtual ~NativeMapView();
@@ -290,8 +288,6 @@ private:
void updateFps();
private:
- void recalculateSourceTileCacheSize();
-
JavaVM *vm = nullptr;
jni::UniqueWeakObject<NativeMapView> javaPeer;
@@ -327,9 +323,6 @@ private:
bool framebufferSizeChanged = true;
- int availableProcessors = 0;
- size_t totalMemory = 0;
-
// Ensure these are initialised last
std::shared_ptr<mbgl::ThreadPool> threadPool;
std::unique_ptr<mbgl::Map> map;
diff --git a/platform/android/src/run_loop.cpp b/platform/android/src/run_loop.cpp
index 49d28f2ebb..3c605b70e8 100644
--- a/platform/android/src/run_loop.cpp
+++ b/platform/android/src/run_loop.cpp
@@ -1,9 +1,8 @@
#include "run_loop_impl.hpp"
#include <mbgl/util/platform.hpp>
-#include <mbgl/util/thread.hpp>
-#include <mbgl/util/thread_context.hpp>
#include <mbgl/util/thread_local.hpp>
+#include <mbgl/util/thread.hpp>
#include <mbgl/util/timer.hpp>
#include <android/looper.h>
@@ -62,9 +61,13 @@ namespace util {
// timeout, but on the main thread `ALooper_pollAll` is called by the activity
// automatically, thus we cannot set the timeout. Instead we wake the loop
// with an external file descriptor event coming from this thread.
+//
+// Usually an actor should not carry pointers to other threads, but in
+// this case the RunLoop itself owns the Alarm and calling wake() is the most
+// efficient way of waking up the RunLoop and it is also thread-safe.
class Alarm {
public:
- Alarm(RunLoop::Impl* loop_) : loop(loop_) {}
+ Alarm(ActorRef<Alarm>, RunLoop::Impl* loop_) : loop(loop_) {}
void set(const Milliseconds& timeout) {
alarm.start(timeout, mbgl::Duration::zero(), [this]() { loop->wake(); });
@@ -102,7 +105,7 @@ RunLoop::Impl::Impl(RunLoop* runLoop_, RunLoop::Type type) : runLoop(runLoop_) {
case Type::Default:
ret = ALooper_addFd(loop, fds[PIPE_OUT], ALOOPER_POLL_CALLBACK,
ALOOPER_EVENT_INPUT, looperCallbackDefault, this);
- alarm = std::make_unique<Thread<Alarm>>(ThreadContext{"Alarm"}, this);
+ alarm = std::make_unique<Thread<Alarm>>("Alarm", this);
running = true;
break;
}
@@ -190,7 +193,7 @@ Milliseconds RunLoop::Impl::processRunnables() {
auto timeout = std::chrono::duration_cast<Milliseconds>(nextDue - now);
if (alarm) {
- alarm->invoke(&Alarm::set, timeout);
+ alarm->actor().invoke(&Alarm::set, timeout);
}
return timeout;
diff --git a/platform/android/src/style/android_conversion.hpp b/platform/android/src/style/android_conversion.hpp
index e2b2685928..082fe411e2 100644
--- a/platform/android/src/style/android_conversion.hpp
+++ b/platform/android/src/style/android_conversion.hpp
@@ -2,6 +2,7 @@
#include "value.hpp"
+#include <mbgl/util/feature.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/util/optional.hpp>
@@ -66,6 +67,14 @@ inline optional<float> toNumber(const mbgl::android::Value& value) {
}
}
+inline optional<double> toDouble(const mbgl::android::Value& value) {
+ if (value.isNumber()) {
+ return value.toDouble();
+ } else {
+ return {};
+ }
+}
+
inline optional<std::string> toString(const mbgl::android::Value& value) {
if (value.isString()) {
return value.toString();
diff --git a/platform/android/src/style/conversion/latlngquad.hpp b/platform/android/src/style/conversion/latlngquad.hpp
new file mode 100644
index 0000000000..9d1a83e164
--- /dev/null
+++ b/platform/android/src/style/conversion/latlngquad.hpp
@@ -0,0 +1,24 @@
+#pragma once
+
+#include <mapbox/geojson.hpp>
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/style/conversion/geojson.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace style {
+namespace conversion {
+
+template <>
+optional<std::array<LatLng, 4>> Converter<std::array<LatLng, 4>>::operator()(const mbgl::android::Value& value, Error& error) const {
+ if (value.isNull() || !value.isArray()) {
+ error = { "value cannot be converted to LatLng array" };
+ return {};
+ }
+
+ return convert<GeoJSON>(value.toString(), error);
+}
+
+} // namespace conversion
+} // namespace style
+} // namespace mbgl
diff --git a/platform/android/src/style/conversion/transition_options.hpp b/platform/android/src/style/conversion/transition_options.hpp
index 3614878f43..ae65a32194 100644
--- a/platform/android/src/style/conversion/transition_options.hpp
+++ b/platform/android/src/style/conversion/transition_options.hpp
@@ -3,6 +3,7 @@
#include "../../conversion/conversion.hpp"
#include <jni/jni.hpp>
+#include <mbgl/style/transition_options.hpp>
#include "../../jni/local_object.hpp"
#include "../transition_options.hpp"
diff --git a/platform/android/src/style/layers/custom_layer.cpp b/platform/android/src/style/layers/custom_layer.cpp
index 9bdc308d85..e6321a8efa 100644
--- a/platform/android/src/style/layers/custom_layer.cpp
+++ b/platform/android/src/style/layers/custom_layer.cpp
@@ -21,6 +21,10 @@ namespace android {
: Layer(map, coreLayer) {
}
+ CustomLayer::CustomLayer(mbgl::Map& map, std::unique_ptr<mbgl::style::CustomLayer> coreLayer)
+ : Layer(map, std::move(coreLayer)) {
+ }
+
CustomLayer::~CustomLayer() = default;
void CustomLayer::update(jni::JNIEnv&) {
diff --git a/platform/android/src/style/layers/custom_layer.hpp b/platform/android/src/style/layers/custom_layer.hpp
index 1173d21bfd..3e3f3bf77f 100644
--- a/platform/android/src/style/layers/custom_layer.hpp
+++ b/platform/android/src/style/layers/custom_layer.hpp
@@ -20,6 +20,8 @@ public:
CustomLayer(mbgl::Map&, mbgl::style::CustomLayer&);
+ CustomLayer(mbgl::Map&, std::unique_ptr<mbgl::style::CustomLayer>);
+
~CustomLayer();
void update(jni::JNIEnv&);
diff --git a/platform/android/src/style/layers/layer.cpp b/platform/android/src/style/layers/layer.cpp
index d571c3fd2e..02a1f0be82 100644
--- a/platform/android/src/style/layers/layer.cpp
+++ b/platform/android/src/style/layers/layer.cpp
@@ -3,6 +3,7 @@
#include <jni/jni.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/transition_options.hpp>
#include <mbgl/util/logging.hpp>
@@ -53,7 +54,7 @@ namespace android {
}
// Add layer to map
- _map.addLayer(releaseCoreLayer(), before);
+ _map.getStyle().addLayer(releaseCoreLayer(), before);
// Save pointer to the map
this->map = &_map;
@@ -91,19 +92,31 @@ namespace android {
Value value(env, jvalue);
// Convert and set property
- optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setPaintProperty(layer, jni::Make<std::string>(env, jname), value, mbgl::optional<std::string>());
+ optional<mbgl::style::conversion::Error> error = mbgl::style::conversion::setPaintProperty(layer, jni::Make<std::string>(env, jname), value);
if (error) {
mbgl::Log::Error(mbgl::Event::JNI, "Error setting property: " + jni::Make<std::string>(env, jname) + " " + error->message);
return;
}
}
+ struct SetFilterEvaluator {
+ style::Filter filter;
+
+ void operator()(style::BackgroundLayer&) { Log::Warning(mbgl::Event::JNI, "BackgroundLayer doesn't support filters"); }
+ void operator()(style::CustomLayer&) { Log::Warning(mbgl::Event::JNI, "CustomLayer doesn't support filters"); }
+ void operator()(style::RasterLayer&) { Log::Warning(mbgl::Event::JNI, "RasterLayer doesn't support filters"); }
+
+ template <class LayerType>
+ void operator()(LayerType& layer) {
+ layer.setFilter(filter);
+ }
+ };
+
void Layer::setFilter(jni::JNIEnv& env, jni::Array<jni::Object<>> jfilter) {
using namespace mbgl::style;
using namespace mbgl::style::conversion;
Value wrapped(env, jfilter);
- Filter filter;
Error error;
optional<Filter> converted = convert<Filter>(wrapped, error);
@@ -111,62 +124,45 @@ namespace android {
mbgl::Log::Error(mbgl::Event::JNI, "Error setting filter: " + error.message);
return;
}
- filter = std::move(*converted);
-
- if (layer.is<FillLayer>()) {
- layer.as<FillLayer>()->setFilter(filter);
- } else if (layer.is<LineLayer>()) {
- layer.as<LineLayer>()->setFilter(filter);
- } else if (layer.is<SymbolLayer>()) {
- layer.as<SymbolLayer>()->setFilter(filter);
- } else if (layer.is<CircleLayer>()) {
- layer.as<CircleLayer>()->setFilter(filter);
- } else if (layer.is<FillExtrusionLayer>()){
- layer.as<FillExtrusionLayer>()->setFilter(filter);
- } else {
- mbgl::Log::Warning(mbgl::Event::JNI, "Layer doesn't support filters");
- }
+
+ layer.accept(SetFilterEvaluator {std::move(*converted)});
}
- void Layer::setSourceLayer(jni::JNIEnv& env, jni::String sourceLayer) {
- using namespace mbgl::style;
+ struct SetSourceLayerEvaluator {
+ std::string sourceLayer;
- std::string layerId = jni::Make<std::string>(env, sourceLayer);
-
- if (layer.is<FillLayer>()) {
- layer.as<FillLayer>()->setSourceLayer(layerId);
- } else if (layer.is<LineLayer>()) {
- layer.as<LineLayer>()->setSourceLayer(layerId);
- } else if (layer.is<SymbolLayer>()) {
- layer.as<SymbolLayer>()->setSourceLayer(layerId);
- } else if (layer.is<CircleLayer>()) {
- layer.as<CircleLayer>()->setSourceLayer(layerId);
- } else if(layer.is<FillExtrusionLayer>()) {
- layer.as<FillExtrusionLayer>()->setSourceLayer(layerId);
- } else {
- mbgl::Log::Warning(mbgl::Event::JNI, "Layer doesn't support source layer");
+ void operator()(style::BackgroundLayer&) { Log::Warning(mbgl::Event::JNI, "BackgroundLayer doesn't support source layer"); }
+ void operator()(style::CustomLayer&) { Log::Warning(mbgl::Event::JNI, "CustomLayer doesn't support source layer"); }
+ void operator()(style::RasterLayer&) { Log::Warning(mbgl::Event::JNI, "RasterLayer doesn't support source layer"); }
+
+ template <class LayerType>
+ void operator()(LayerType& layer) {
+ layer.setSourceLayer(sourceLayer);
}
+ };
+
+ void Layer::setSourceLayer(jni::JNIEnv& env, jni::String sourceLayer) {
+ layer.accept(SetSourceLayerEvaluator {jni::Make<std::string>(env, sourceLayer)});
}
- jni::String Layer::getSourceLayer(jni::JNIEnv& env) {
- using namespace mbgl::style;
+ struct GetSourceLayerEvaluator {
+ std::string noop(std::string layerType) {
+ Log::Warning(mbgl::Event::JNI, "%s doesn't support source layer", layerType.c_str());
+ return {};
+ }
- std::string sourceLayerId;
- if (layer.is<FillLayer>()) {
- sourceLayerId = layer.as<FillLayer>()->getSourceLayer();
- } else if (layer.is<LineLayer>()) {
- sourceLayerId = layer.as<LineLayer>()->getSourceLayer();
- } else if (layer.is<SymbolLayer>()) {
- sourceLayerId = layer.as<SymbolLayer>()->getSourceLayer();
- } else if (layer.is<CircleLayer>()) {
- sourceLayerId = layer.as<CircleLayer>()->getSourceLayer();
- } else if (layer.is<FillExtrusionLayer>()) {
- sourceLayerId = layer.as<FillExtrusionLayer>()->getSourceLayer();
- } else {
- mbgl::Log::Warning(mbgl::Event::JNI, "Layer doesn't support source layer");
+ std::string operator()(style::BackgroundLayer&) { return noop("BackgroundLayer"); }
+ std::string operator()(style::CustomLayer&) { return noop("CustomLayer"); }
+ std::string operator()(style::RasterLayer&) { return noop("RasterLayer"); }
+
+ template <class LayerType>
+ std::string operator()(LayerType& layer) {
+ return layer.getSourceLayer();
}
+ };
- return jni::Make<jni::String>(env, sourceLayerId);
+ jni::String Layer::getSourceLayer(jni::JNIEnv& env) {
+ return jni::Make<jni::String>(env, layer.accept(GetSourceLayerEvaluator()));
}
jni::jfloat Layer::getMinZoom(jni::JNIEnv&){
diff --git a/platform/android/src/style/layers/layers.cpp b/platform/android/src/style/layers/layers.cpp
index 5c49f875ee..9803b6f841 100644
--- a/platform/android/src/style/layers/layers.cpp
+++ b/platform/android/src/style/layers/layers.cpp
@@ -24,53 +24,51 @@
namespace mbgl {
namespace android {
-static Layer* initializeLayerPeer(mbgl::Map& map, mbgl::style::Layer& coreLayer) {
- if (coreLayer.is<mbgl::style::BackgroundLayer>()) {
- return new BackgroundLayer(map, *coreLayer.as<mbgl::style::BackgroundLayer>());
- } else if (coreLayer.is<mbgl::style::CircleLayer>()) {
- return new CircleLayer(map, *coreLayer.as<mbgl::style::CircleLayer>());
- } else if (coreLayer.is<mbgl::style::FillExtrusionLayer>()) {
- return new FillExtrusionLayer(map, *coreLayer.as<mbgl::style::FillExtrusionLayer>());
- } else if (coreLayer.is<mbgl::style::FillLayer>()) {
- return new FillLayer(map, *coreLayer.as<mbgl::style::FillLayer>());
- } else if (coreLayer.is<mbgl::style::LineLayer>()) {
- return new LineLayer(map, *coreLayer.as<mbgl::style::LineLayer>());
- } else if (coreLayer.is<mbgl::style::RasterLayer>()) {
- return new RasterLayer(map, *coreLayer.as<mbgl::style::RasterLayer>());
- } else if (coreLayer.is<mbgl::style::SymbolLayer>()) {
- return new SymbolLayer(map, *coreLayer.as<mbgl::style::SymbolLayer>());
- } else if (coreLayer.is<mbgl::style::CustomLayer>()) {
- return new CustomLayer(map, *coreLayer.as<mbgl::style::CustomLayer>());
- } else {
- return new UnknownLayer(map, coreLayer);
+// Mapping from style layers to peer classes
+template <class> struct PeerType {};
+template <> struct PeerType<style::BackgroundLayer> { using Type = android::BackgroundLayer; };
+template <> struct PeerType<style::CircleLayer> { using Type = android::CircleLayer; };
+template <> struct PeerType<style::FillExtrusionLayer> { using Type = android::FillExtrusionLayer; };
+template <> struct PeerType<style::FillLayer> { using Type = android::FillLayer; };
+template <> struct PeerType<style::LineLayer> { using Type = android::LineLayer; };
+template <> struct PeerType<style::RasterLayer> { using Type = android::RasterLayer; };
+template <> struct PeerType<style::SymbolLayer> { using Type = android::SymbolLayer; };
+template <> struct PeerType<style::CustomLayer> { using Type = android::CustomLayer; };
+
+// Inititalizes a non-owning peer
+struct LayerPeerIntitializer {
+ mbgl::Map& map;
+
+ template <class LayerType>
+ Layer* operator()(LayerType& layer) {
+ return new typename PeerType<LayerType>::Type(map, layer);
}
-}
+};
-template <class LayerType, class PeerType>
-static PeerType* createPeer(Map& map, std::unique_ptr<mbgl::style::Layer> layer) {
- return new PeerType(map, std::move(std::unique_ptr<LayerType>(layer.release()->as<LayerType>())));
+static Layer* initializeLayerPeer(mbgl::Map& map, mbgl::style::Layer& coreLayer) {
+ Layer* layer = coreLayer.accept(LayerPeerIntitializer {map});
+ return layer ? layer : new UnknownLayer(map, coreLayer);
}
-static Layer* initializeLayerPeer(Map& map, std::unique_ptr<mbgl::style::Layer> coreLayer) {
- if (coreLayer->is<style::BackgroundLayer>()) {
- return createPeer<style::BackgroundLayer, BackgroundLayer>(map, std::move(coreLayer));
- } else if (coreLayer->is<style::CircleLayer>()) {
- return createPeer<style::CircleLayer, CircleLayer>(map, std::move(coreLayer));
- } else if (coreLayer->is<style::FillExtrusionLayer>()) {
- return createPeer<style::FillExtrusionLayer, FillExtrusionLayer>(map, std::move(coreLayer));
- } else if (coreLayer->is<style::FillLayer>()) {
- return createPeer<style::FillLayer, FillLayer>(map, std::move(coreLayer));
- } else if (coreLayer->is<style::LineLayer>()) {
- return createPeer<style::LineLayer, LineLayer>(map, std::move(coreLayer));
- } else if (coreLayer->is<style::RasterLayer>()) {
- return createPeer<style::RasterLayer, RasterLayer>(map, std::move(coreLayer));
- } else if (coreLayer->is<style::SymbolLayer>()) {
- return createPeer<style::SymbolLayer, SymbolLayer>(map, std::move(coreLayer));
- } else if (coreLayer->is<mbgl::style::CustomLayer>()) {
- return createPeer<style::SymbolLayer, SymbolLayer>(map, std::move(coreLayer));
- } else {
- return new UnknownLayer(map, std::move(coreLayer));
+// Initializes an owning peer
+// Only usable once since it needs to pass on ownership
+// of the given layer and thus enforced to be an rvalue
+struct UniqueLayerPeerIntitializer {
+ mbgl::Map& map;
+ std::unique_ptr<style::Layer> layer;
+
+ template <class LayerType>
+ Layer* operator()(LayerType&) && {
+ return new typename PeerType<LayerType>::Type(
+ map,
+ std::unique_ptr<LayerType>(layer.release()->as<LayerType>())
+ );
}
+};
+
+static Layer* initializeLayerPeer(Map& map, std::unique_ptr<mbgl::style::Layer> coreLayer) {
+ Layer* layer = coreLayer->accept(UniqueLayerPeerIntitializer {map, std::move(coreLayer)});
+ return layer ? layer : new UnknownLayer(map, std::move(coreLayer));
}
jni::jobject* createJavaLayerPeer(jni::JNIEnv& env, Map& map, style::Layer& coreLayer) {
diff --git a/platform/android/src/style/sources/image_source.cpp b/platform/android/src/style/sources/image_source.cpp
new file mode 100644
index 0000000000..cc7e1e7404
--- /dev/null
+++ b/platform/android/src/style/sources/image_source.cpp
@@ -0,0 +1,73 @@
+#include "image_source.hpp"
+
+// Java -> C++ conversion
+#include "../android_conversion.hpp"
+
+// C++ -> Java conversion
+#include "../../conversion/conversion.hpp"
+#include <mbgl/style/conversion.hpp>
+#include <mbgl/util/premultiply.hpp>
+
+#include "../../bitmap.hpp"
+#include <string>
+#include <array>
+
+namespace mbgl {
+namespace android {
+
+ ImageSource::ImageSource(jni::JNIEnv& env, jni::String sourceId, jni::Object<LatLngQuad> coordinatesObject)
+ : Source(env, std::make_unique<mbgl::style::ImageSource>(
+ jni::Make<std::string>(env, sourceId),
+ LatLngQuad::getLatLngArray(env, coordinatesObject)
+ )
+ ) {
+ }
+
+ ImageSource::ImageSource(mbgl::Map& map, mbgl::style::ImageSource& coreSource)
+ : Source(map, coreSource) {
+ }
+
+ ImageSource::~ImageSource() = default;
+
+ void ImageSource::setURL(jni::JNIEnv& env, jni::String url) {
+ // Update the core source
+ source.as<mbgl::style::ImageSource>()->ImageSource::setURL(jni::Make<std::string>(env, url));
+ }
+
+ jni::String ImageSource::getURL(jni::JNIEnv& env) {
+ optional<std::string> url = source.as<mbgl::style::ImageSource>()->ImageSource::getURL();
+ return url ? jni::Make<jni::String>(env, *url) : jni::String();
+ }
+
+ void ImageSource::setImage(jni::JNIEnv& env, jni::Object<Bitmap> bitmap) {
+ UnassociatedImage image = util::unpremultiply(Bitmap::GetImage(env, bitmap));
+ source.as<mbgl::style::ImageSource>()->setImage(std:: move(image));
+ }
+
+ jni::Class<ImageSource> ImageSource::javaClass;
+
+ jni::jobject* ImageSource::createJavaPeer(jni::JNIEnv& env) {
+ static auto constructor = ImageSource::javaClass.template GetConstructor<jni::jlong>(env);
+ return ImageSource::javaClass.New(env, constructor, reinterpret_cast<jni::jlong>(this));
+ }
+
+ void ImageSource::registerNative(jni::JNIEnv& env) {
+ // Lookup the class
+ ImageSource::javaClass = *jni::Class<ImageSource>::Find(env).NewGlobalRef(env).release();
+
+ #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name)
+
+ // Register the peer
+ jni::RegisterNativePeer<ImageSource>(
+ env, ImageSource::javaClass, "nativePtr",
+ std::make_unique<ImageSource, JNIEnv&, jni::String, jni::Object<LatLngQuad>>,
+ "initialize",
+ "finalize",
+ METHOD(&ImageSource::setURL, "nativeSetUrl"),
+ METHOD(&ImageSource::getURL, "nativeGetUrl"),
+ METHOD(&ImageSource::setImage, "nativeSetImage")
+ );
+ }
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/image_source.hpp b/platform/android/src/style/sources/image_source.hpp
new file mode 100644
index 0000000000..309d17a299
--- /dev/null
+++ b/platform/android/src/style/sources/image_source.hpp
@@ -0,0 +1,38 @@
+#pragma once
+
+#include "source.hpp"
+#include "../../geometry/lat_lng_quad.hpp"
+#include <mbgl/style/sources/image_source.hpp>
+#include <jni/jni.hpp>
+
+namespace mbgl {
+namespace android {
+
+class Bitmap;
+
+class ImageSource : public Source {
+public:
+
+ static constexpr auto Name() { return "com/mapbox/mapboxsdk/style/sources/ImageSource"; };
+
+ static jni::Class<ImageSource> javaClass;
+
+ static void registerNative(jni::JNIEnv&);
+
+ ImageSource(jni::JNIEnv&, jni::String, jni::Object<LatLngQuad>);
+
+ ImageSource(mbgl::Map&, mbgl::style::ImageSource&);
+
+ ~ImageSource();
+
+ void setURL(jni::JNIEnv&, jni::String);
+ jni::String getURL(jni::JNIEnv&);
+
+ void setImage(jni::JNIEnv&, jni::Object<Bitmap>);
+
+ jni::jobject* createJavaPeer(jni::JNIEnv&);
+
+}; // class ImageSource
+
+} // namespace android
+} // namespace mbgl
diff --git a/platform/android/src/style/sources/source.cpp b/platform/android/src/style/sources/source.cpp
index e0e9bb9870..05f981953a 100644
--- a/platform/android/src/style/sources/source.cpp
+++ b/platform/android/src/style/sources/source.cpp
@@ -3,6 +3,7 @@
#include <jni/jni.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/util/logging.hpp>
// Java -> C++ conversion
@@ -55,7 +56,7 @@ namespace android {
}
// Add source to map
- _map.addSource(releaseCoreSource());
+ _map.getStyle().addSource(releaseCoreSource());
// Save pointer to the map
this->map = &_map;
diff --git a/platform/android/src/style/sources/sources.cpp b/platform/android/src/style/sources/sources.cpp
index b4e70202b4..7ca6328e71 100644
--- a/platform/android/src/style/sources/sources.cpp
+++ b/platform/android/src/style/sources/sources.cpp
@@ -2,11 +2,13 @@
#include <mbgl/style/source.hpp>
#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/sources/image_source.hpp>
#include <mbgl/style/sources/raster_source.hpp>
#include <mbgl/style/sources/vector_source.hpp>
#include "source.hpp"
#include "geojson_source.hpp"
+#include "image_source.hpp"
#include "raster_source.hpp"
#include "unknown_source.hpp"
#include "vector_source.hpp"
@@ -22,6 +24,8 @@ Source* initializeSourcePeer(mbgl::Map& map, mbgl::style::Source& coreSource) {
source = new RasterSource(map, *coreSource.as<mbgl::style::RasterSource>());
} else if (coreSource.is<mbgl::style::GeoJSONSource>()) {
source = new GeoJSONSource(map, *coreSource.as<mbgl::style::GeoJSONSource>());
+ } else if (coreSource.is<mbgl::style::ImageSource>()) {
+ source = new ImageSource(map, *coreSource.as<mbgl::style::ImageSource>());
} else {
source = new UnknownSource(map, coreSource);
}
@@ -39,6 +43,7 @@ jni::jobject* createJavaSourcePeer(jni::JNIEnv& env, mbgl::Map& map, mbgl::style
void registerNativeSources(jni::JNIEnv& env) {
Source::registerNative(env);
GeoJSONSource::registerNative(env);
+ ImageSource::registerNative(env);
RasterSource::registerNative(env);
UnknownSource::registerNative(env);
VectorSource::registerNative(env);
diff --git a/platform/darwin/docs/guides/For Style Authors.md.ejs b/platform/darwin/docs/guides/For Style Authors.md.ejs
index 26c533632f..06a8907704 100644
--- a/platform/darwin/docs/guides/For Style Authors.md.ejs
+++ b/platform/darwin/docs/guides/For Style Authors.md.ejs
@@ -160,7 +160,6 @@ the following terms for concepts defined in the style specification:
In the style specification | In the SDK
---------------------------|---------
-class | style class
filter | predicate
function type | interpolation mode
id | identifier
@@ -181,8 +180,9 @@ In style JSON | In the SDK
`geojson` | `MGLShapeSource`
`raster` | `MGLRasterSource`
`vector` | `MGLVectorSource`
+`image` | `MGLImageSource`
-`canvas`, `image`, and `video` sources are not supported.
+`canvas` and `video` sources are not supported.
### Tile sources
@@ -223,6 +223,12 @@ To create a shape source from local GeoJSON data, first
[convert the GeoJSON data into a shape](working-with-geojson-data.html#converting-geojson-data-into-shape-objects),
then use the `-[MGLShapeSource initWithIdentifier:shape:options:]` method.
+### Image sources
+
+Image sources accept a non-axis aligned quadrilateral as their geographic coordinates.
+These coordinates, in `MGLCoordinateQuad`, are described in counterclockwise order,
+in contrast to the clockwise order defined in the style specification.
+
## Configuring the map content’s appearance
Each layer defined by the style JSON file is represented at runtime by a style
diff --git a/platform/darwin/src/MGLCircleStyleLayer.h b/platform/darwin/src/MGLCircleStyleLayer.h
index 789ff7a258..823824b50f 100644
--- a/platform/darwin/src/MGLCircleStyleLayer.h
+++ b/platform/darwin/src/MGLCircleStyleLayer.h
@@ -64,16 +64,6 @@ typedef NS_ENUM(NSUInteger, MGLCircleTranslationAnchor) {
### Example
```swift
- let layer = MGLCircleStyleLayer(identifier: "circles", source: population)
- layer.sourceLayerIdentifier = "population"
- layer.circleColor = MGLStyleValue(rawValue: .green)
- layer.circleRadius = MGLStyleValue(interpolationMode: .exponential,
- cameraStops: [12: MGLStyleValue(rawValue: 2),
- 22: MGLStyleValue(rawValue: 180)],
- options: [.interpolationBase: 1.75])
- layer.circleOpacity = MGLStyleValue(rawValue: 0.7)
- layer.predicate = NSPredicate(format: "%K == %@", "marital-status", "married")
- mapView.style?.addLayer(layer)
```
*/
MGL_EXPORT
diff --git a/platform/darwin/src/MGLConversion.h b/platform/darwin/src/MGLConversion.h
index d51ebd775c..d6363b28eb 100644
--- a/platform/darwin/src/MGLConversion.h
+++ b/platform/darwin/src/MGLConversion.h
@@ -104,6 +104,14 @@ inline optional<float> toNumber(const id value) {
}
}
+inline optional<double> toDouble(const id value) {
+ if (_isNumber(value)) {
+ return ((NSNumber *)value).doubleValue;
+ } else {
+ return {};
+ }
+}
+
inline optional<std::string> toString(const id value) {
if (_isString(value)) {
return std::string(static_cast<const char *>([value UTF8String]));
diff --git a/platform/darwin/src/MGLFillExtrusionStyleLayer.h b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
index c4fb9aa77e..443391756d 100644
--- a/platform/darwin/src/MGLFillExtrusionStyleLayer.h
+++ b/platform/darwin/src/MGLFillExtrusionStyleLayer.h
@@ -42,12 +42,6 @@ typedef NS_ENUM(NSUInteger, MGLFillExtrusionTranslationAnchor) {
### Example
```swift
- let layer = MGLFillExtrusionStyleLayer(identifier: "buildings", source: buildings)
- layer.sourceLayerIdentifier = "building"
- layer.fillExtrusionHeight = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "height", options: nil)
- layer.fillExtrusionBase = MGLStyleValue(interpolationMode: .identity, sourceStops: nil, attributeName: "min_height", options: nil)
- layer.predicate = NSPredicate(format: "extrude == 'true'")
- mapView.style?.addLayer(layer)
```
*/
MGL_EXPORT
diff --git a/platform/darwin/src/MGLFillStyleLayer.h b/platform/darwin/src/MGLFillStyleLayer.h
index 6e3297bdec..8776f17bcb 100644
--- a/platform/darwin/src/MGLFillStyleLayer.h
+++ b/platform/darwin/src/MGLFillStyleLayer.h
@@ -42,11 +42,6 @@ typedef NS_ENUM(NSUInteger, MGLFillTranslationAnchor) {
### Example
```swift
- let layer = MGLFillStyleLayer(identifier: "parks", source: parks)
- layer.sourceLayerIdentifier = "parks"
- layer.fillColor = MGLStyleValue(rawValue: .green)
- layer.predicate = NSPredicate(format: "type == %@", "national-park")
- mapView.style?.addLayer(layer)
```
*/
MGL_EXPORT
diff --git a/platform/darwin/src/MGLGeometry.h b/platform/darwin/src/MGLGeometry.h
index d37741cde5..7c68033abf 100644
--- a/platform/darwin/src/MGLGeometry.h
+++ b/platform/darwin/src/MGLGeometry.h
@@ -45,6 +45,24 @@ typedef struct __attribute__((objc_boxable)) MGLCoordinateBounds {
CLLocationCoordinate2D ne;
} MGLCoordinateBounds;
+/**
+ A quadrilateral area as measured on a two-dimensional map projection.
+ `MGLCoordinateQuad` differs from `MGLCoordinateBounds` in that it allows
+ representation of non-axis aligned bounds and non-rectangular quadrilaterals.
+ The coordinates are described in counter clockwise order from top left.
+ */
+typedef struct MGLCoordinateQuad {
+ /** Coordinate at the top left corner. */
+ CLLocationCoordinate2D topLeft;
+ /** Coordinate at the bottom left corner. */
+ CLLocationCoordinate2D bottomLeft;
+ /** Coordinate at the bottom right corner. */
+ CLLocationCoordinate2D bottomRight;
+ /** Coordinate at the top right corner. */
+ CLLocationCoordinate2D topRight;
+} MGLCoordinateQuad;
+
+
/**
Creates a new `MGLCoordinateBounds` structure from the given southwest and
northeast coordinates.
@@ -56,6 +74,33 @@ NS_INLINE MGLCoordinateBounds MGLCoordinateBoundsMake(CLLocationCoordinate2D sw,
return bounds;
}
+/**
+ Creates a new `MGLCoordinateQuad` structure from the given top left,
+ bottom left, bottom right, and top right coordinates.
+ */
+NS_INLINE MGLCoordinateQuad MGLCoordinateQuadMake(CLLocationCoordinate2D topLeft, CLLocationCoordinate2D bottomLeft, CLLocationCoordinate2D bottomRight, CLLocationCoordinate2D topRight) {
+ MGLCoordinateQuad quad;
+ quad.topLeft = topLeft;
+ quad.bottomLeft = bottomLeft;
+ quad.bottomRight = bottomRight;
+ quad.topRight = topRight;
+ return quad;
+}
+
+/**
+ Creates a new `MGLCoordinateQuad` structure from the given `MGLCoordinateBounds`.
+ The returned quad uses the bounds' northeast coordinate as the top right, and the
+ southwest coordinate at the bottom left.
+ */
+NS_INLINE MGLCoordinateQuad MGLCoordinateQuadFromCoordinateBounds(MGLCoordinateBounds bounds) {
+ MGLCoordinateQuad quad;
+ quad.topLeft = CLLocationCoordinate2DMake(bounds.ne.latitude, bounds.sw.longitude);
+ quad.bottomLeft = bounds.sw;
+ quad.bottomRight = CLLocationCoordinate2DMake(bounds.sw.latitude, bounds.ne.longitude);
+ quad.topRight = bounds.ne;
+ return quad;
+}
+
/** Returns `YES` if the two coordinate bounds are equal to each other. */
NS_INLINE BOOL MGLCoordinateBoundsEqualToCoordinateBounds(MGLCoordinateBounds bounds1, MGLCoordinateBounds bounds2) {
return (bounds1.sw.latitude == bounds2.sw.latitude &&
@@ -117,6 +162,15 @@ NS_INLINE NSString *MGLStringFromCoordinateBounds(MGLCoordinateBounds bounds) {
bounds.ne.latitude, bounds.ne.longitude];
}
+/** Returns a formatted string for the given coordinate quad. */
+NS_INLINE NSString *MGLStringFromCoordinateQuad(MGLCoordinateQuad quad) {
+ return [NSString stringWithFormat:@"{ topleft = {%.1f, %.1f}, bottomleft = {%.1f, %.1f}}, bottomright = {%.1f, %.1f}, topright = {%.1f, %.1f}",
+ quad.topLeft.latitude, quad.topLeft.longitude,
+ quad.bottomLeft.latitude, quad.bottomLeft.longitude,
+ quad.bottomRight.latitude, quad.bottomRight.longitude,
+ quad.topRight.latitude, quad.topRight.longitude];
+}
+
/** Returns radians, converted from degrees. */
NS_INLINE CGFloat MGLRadiansFromDegrees(CLLocationDegrees degrees) {
return (CGFloat)(degrees * M_PI) / 180;
diff --git a/platform/darwin/src/MGLGeometry_Private.h b/platform/darwin/src/MGLGeometry_Private.h
index 7ad8314a79..88fcf5b576 100644
--- a/platform/darwin/src/MGLGeometry_Private.h
+++ b/platform/darwin/src/MGLGeometry_Private.h
@@ -8,6 +8,7 @@
#import <mbgl/util/geo.hpp>
#import <mbgl/util/geometry.hpp>
+#import <array>
typedef double MGLLocationRadians;
typedef double MGLRadianDistance;
typedef double MGLRadianDirection;
@@ -56,6 +57,20 @@ NS_INLINE mbgl::LatLngBounds MGLLatLngBoundsFromCoordinateBounds(MGLCoordinateBo
MGLLatLngFromLocationCoordinate2D(coordinateBounds.ne));
}
+NS_INLINE std::array<mbgl::LatLng, 4> MGLLatLngArrayFromCoordinateQuad(MGLCoordinateQuad quad) {
+ return { MGLLatLngFromLocationCoordinate2D(quad.topLeft),
+ MGLLatLngFromLocationCoordinate2D(quad.topRight),
+ MGLLatLngFromLocationCoordinate2D(quad.bottomRight),
+ MGLLatLngFromLocationCoordinate2D(quad.bottomLeft) };
+}
+
+NS_INLINE MGLCoordinateQuad MGLCoordinateQuadFromLatLngArray(std::array<mbgl::LatLng, 4> quad) {
+ return { MGLLocationCoordinate2DFromLatLng(quad[0]),
+ MGLLocationCoordinate2DFromLatLng(quad[3]),
+ MGLLocationCoordinate2DFromLatLng(quad[2]),
+ MGLLocationCoordinate2DFromLatLng(quad[1]) };
+}
+
#if TARGET_OS_IPHONE
NS_INLINE mbgl::EdgeInsets MGLEdgeInsetsFromNSEdgeInsets(UIEdgeInsets insets) {
return { insets.top, insets.left, insets.bottom, insets.right };
diff --git a/platform/darwin/src/MGLImageSource.h b/platform/darwin/src/MGLImageSource.h
new file mode 100644
index 0000000000..21487d9739
--- /dev/null
+++ b/platform/darwin/src/MGLImageSource.h
@@ -0,0 +1,94 @@
+#import "MGLSource.h"
+
+#import "MGLFoundation.h"
+#import "MGLTypes.h"
+#import "MGLGeometry.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+MGL_EXPORT
+/**
+ `MGLImageSource` is a content source that is used for a georeferenced raster
+ image to be shown on the map. The georeferenced image scales and rotates as the
+ user zooms and rotates the map. Images may also be used as icons or patterns
+ in a style layer. To register an image for use as an icon or pattern,
+ use the `-[MGLStyle setImage:forName:]` method. To configure a point
+ annotation’s image, use the `MGLAnnotationImage` class.
+
+ The geographic location of the raster image content, supplied with
+ `MGLCoordinateQuad`, can be non-axis aligned.
+ `MGLImageSource` supports raster content from `NSURL`, `NSImage` (macOS), or
+ `UIImage` (iOS).
+ An image source is added to an `MGLStyle` object along with one or more
+ `MGLRasterStyleLayer` objects. Use a raster style layer to control the
+ appearance of content supplied by the image source.
+
+ Each
+ <a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-image"><code>image</code></a>
+ source defined by the style JSON file is represented at runtime by an
+ `MGLImageSource` object that you can use to initialize new style layers. You
+ can also add and remove sources dynamically using methods such as
+ `-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
+
+ ### Example
+
+ ```swift
+ let coordinates = MGLCoordinateQuad(
+ topLeft: CLLocationCoordinate2D(latitude: 46.437, longitude: -80.425),
+ bottomLeft: CLLocationCoordinate2D(latitude: 37.936, longitude: -80.425),
+ bottomRight: CLLocationCoordinate2D(latitude: 37.936, longitude: -71.516),
+ topRight: CLLocationCoordinate2D(latitude: 46.437, longitude: -71.516))
+ let source = MGLImageSource(identifier: "radar", coordinateQuad: coordinates, url: URL(string: "https://www.mapbox.com/mapbox-gl-js/assets/radar.gif")!)
+ mapView.style?.addSource(source)
+ ```
+ */
+MGL_EXPORT
+@interface MGLImageSource : MGLSource
+
+#pragma mark Initializing a Source
+
+/**
+ Returns a georeferenced image source with an identifier, coordinates and a URL.
+
+ @param identifier A string that uniquely identifies the source.
+ @param coordinateQuad the top left, top right, bottom right, and bottom left coordinates for the image.
+ @param url An HTTP(S) URL, absolute file URL, or local file URL relative to the
+ current application’s resource bundle.
+ @return An initialized shape source.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad URL:(NSURL *)url;
+
+/**
+ Returns a georeferenced image source with an identifier, coordinates and an image.
+
+ @param identifier A string that uniquely identifies the source.
+ @param coordinateQuad The top left, top right, bottom right, and bottom left coordinates for the image.
+ @param image The image to display for the source.
+ @return An initialized shape source.
+ */
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad image:(MGLImage *)image;
+
+#pragma mark Accessing a Source’s Content
+
+/**
+ The URL to the source image.
+
+ If the receiver was initialized using `-initWithIdentifier:coordinateQuad:image:` or
+ the `image` property is set, this property is set to `nil`.
+ */
+@property (nonatomic, copy, nullable)NSURL *URL;
+
+/**
+ The source image.
+
+ If the receiver was initialized using `-initWithIdentifier:coordinateQuad:URL:` or if the `URL` property is set, this property is set to `nil`.
+ */
+@property (nonatomic, retain, nullable)MGLImage *image;
+
+/**
+ The coordinates at which the corners of the source image will be placed.
+ */
+@property (nonatomic) MGLCoordinateQuad coordinates;
+@end
+
+NS_ASSUME_NONNULL_END
diff --git a/platform/darwin/src/MGLImageSource.mm b/platform/darwin/src/MGLImageSource.mm
new file mode 100644
index 0000000000..0a2dc2713f
--- /dev/null
+++ b/platform/darwin/src/MGLImageSource.mm
@@ -0,0 +1,93 @@
+#import "MGLImageSource.h"
+
+#import "MGLGeometry_Private.h"
+#import "MGLSource_Private.h"
+#import "MGLTileSource_Private.h"
+#import "NSURL+MGLAdditions.h"
+#if TARGET_OS_IPHONE
+ #import "UIImage+MGLAdditions.h"
+#else
+ #import "NSImage+MGLAdditions.h"
+#endif
+
+#include <mbgl/style/sources/image_source.hpp>
+#include <mbgl/util/premultiply.hpp>
+
+@interface MGLImageSource ()
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad NS_DESIGNATED_INITIALIZER;
+
+@property (nonatomic, readonly) mbgl::style::ImageSource *rawSource;
+
+@end
+
+@implementation MGLImageSource
+
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad {
+
+ const auto coordsArray = MGLLatLngArrayFromCoordinateQuad(coordinateQuad);
+ auto source = std::make_unique<mbgl::style::ImageSource>(identifier.UTF8String, coordsArray);
+ return self = [super initWithPendingSource:std::move(source)];
+}
+
+
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad URL:(NSURL *)url {
+ self = [self initWithIdentifier:identifier coordinateQuad: coordinateQuad];
+ self.URL = url;
+ return self;
+}
+
+
+- (instancetype)initWithIdentifier:(NSString *)identifier coordinateQuad:(MGLCoordinateQuad)coordinateQuad image:(MGLImage *)image {
+ self = [self initWithIdentifier:identifier coordinateQuad: coordinateQuad];
+ self.image = image;
+
+ return self;
+}
+
+- (NSURL *)URL {
+ auto url = self.rawSource->getURL();
+ return url ? [NSURL URLWithString:@(url->c_str())] : nil;
+}
+
+- (void)setURL:(NSURL *)url {
+ if (url) {
+ self.rawSource->setURL(url.mgl_URLByStandardizingScheme.absoluteString.UTF8String);
+ _image = nil;
+ } else {
+ self.image = nullptr;
+ }
+}
+
+- (void)setImage:(MGLImage *)image {
+ if (image != nullptr) {
+ mbgl::UnassociatedImage unassociatedImage = mbgl::util::unpremultiply(image.mgl_premultipliedImage);
+ self.rawSource->setImage(std::move(unassociatedImage));
+ } else {
+ self.rawSource->setImage(mbgl::UnassociatedImage({0,0}));
+ }
+ _image = image;
+}
+
+- (MGLCoordinateQuad)coordinates {
+ return MGLCoordinateQuadFromLatLngArray(self.rawSource->getCoordinates());
+}
+
+- (void)setCoordinates: (MGLCoordinateQuad)coordinateQuad {
+ self.rawSource->setCoordinates(MGLLatLngArrayFromCoordinateQuad(coordinateQuad));
+}
+
+- (NSString *)description {
+ return [NSString stringWithFormat:@"<%@: %p; identifier = %@; coordinates = %@; URL = %@; image = %@>",
+ NSStringFromClass([self class]), (void *)self, self.identifier, MGLStringFromCoordinateQuad(self.coordinates), self.URL, self.image];
+}
+
+- (mbgl::style::ImageSource *)rawSource {
+ return (mbgl::style::ImageSource *)super.rawSource;
+}
+
+- (NSString *)attributionHTMLString {
+ auto attribution = self.rawSource->getAttribution();
+ return attribution ? @(attribution->c_str()) : nil;
+}
+
+@end
diff --git a/platform/darwin/src/MGLLight.h b/platform/darwin/src/MGLLight.h
index 50db3f45fd..55b789f043 100644
--- a/platform/darwin/src/MGLLight.h
+++ b/platform/darwin/src/MGLLight.h
@@ -27,7 +27,7 @@ typedef NS_ENUM(NSUInteger, MGLLightAnchor) {
A structure containing information about the position of the light source
relative to lit geometries.
*/
-typedef struct __attribute__((objc_boxable)) MGLSphericalPosition {
+typedef struct MGLSphericalPosition {
/** Distance from the center of the base of an object to its light. */
CGFloat radial;
/** Position of the light relative to 0° (0° when `MGLLight.anchor` is set to viewport corresponds
diff --git a/platform/darwin/src/MGLLineStyleLayer.h b/platform/darwin/src/MGLLineStyleLayer.h
index 38513652c5..7c5b66a2c2 100644
--- a/platform/darwin/src/MGLLineStyleLayer.h
+++ b/platform/darwin/src/MGLLineStyleLayer.h
@@ -92,16 +92,6 @@ typedef NS_ENUM(NSUInteger, MGLLineTranslationAnchor) {
### Example
```swift
- let layer = MGLLineStyleLayer(identifier: "trails-path", source: trails)
- layer.sourceLayerIdentifier = "trails"
- layer.lineWidth = MGLStyleValue(interpolationMode: .exponential,
- cameraStops: [14: MGLStyleValue(rawValue: 2),
- 18: MGLStyleValue(rawValue: 20)],
- options: [.interpolationBase: 1.5])
- layer.lineColor = MGLStyleValue(rawValue: .brown)
- layer.lineCap = MGLStyleValue(rawValue: NSValue(mglLineCap: .round))
- layer.predicate = NSPredicate(format: "%K == %@", "trail-type", "mountain-biking")
- mapView.style?.addLayer(layer)
```
*/
MGL_EXPORT
@@ -543,6 +533,15 @@ MGL_EXPORT
* `MGLCameraStyleFunction` with an interpolation mode of:
* `MGLInterpolationModeExponential`
* `MGLInterpolationModeInterval`
+ * `MGLSourceStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
+ * `MGLInterpolationModeIdentity`
+ * `MGLCompositeStyleFunction` with an interpolation mode of:
+ * `MGLInterpolationModeExponential`
+ * `MGLInterpolationModeInterval`
+ * `MGLInterpolationModeCategorical`
*/
@property (nonatomic, null_resettable) MGLStyleValue<NSNumber *> *lineWidth;
diff --git a/platform/darwin/src/MGLLineStyleLayer.mm b/platform/darwin/src/MGLLineStyleLayer.mm
index 8b90efd0c4..9be1667722 100644
--- a/platform/darwin/src/MGLLineStyleLayer.mm
+++ b/platform/darwin/src/MGLLineStyleLayer.mm
@@ -480,7 +480,7 @@ namespace mbgl {
- (void)setLineWidth:(MGLStyleValue<NSNumber *> *)lineWidth {
MGLAssertStyleLayerIsValid();
- auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toInterpolatablePropertyValue(lineWidth);
+ auto mbglValue = MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenPropertyValue(lineWidth);
self.rawLayer->setLineWidth(mbglValue);
}
@@ -489,9 +489,9 @@ namespace mbgl {
auto propertyValue = self.rawLayer->getLineWidth();
if (propertyValue.isUndefined()) {
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(self.rawLayer->getDefaultLineWidth());
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(self.rawLayer->getDefaultLineWidth());
}
- return MGLStyleValueTransformer<float, NSNumber *>().toStyleValue(propertyValue);
+ return MGLStyleValueTransformer<float, NSNumber *>().toDataDrivenStyleValue(propertyValue);
}
- (void)setLineWidthTransition:(MGLTransition )transition {
diff --git a/platform/darwin/src/MGLOfflineStorage.h b/platform/darwin/src/MGLOfflineStorage.h
index 16f134adb1..b009f893b3 100644
--- a/platform/darwin/src/MGLOfflineStorage.h
+++ b/platform/darwin/src/MGLOfflineStorage.h
@@ -154,6 +154,8 @@ typedef NS_ENUM(NSUInteger, MGLResourceKind) {
/** JSON part of a sprite sheet. It is constructed of the prefix in
https://www.mapbox.com/mapbox-gl-js/style-spec/#root-sprite and a JSON file extension. */
MGLResourceKindSpriteJSON,
+ /** Image data for a georeferenced image source. **/
+ MGLResourceKindImage,
};
/**
diff --git a/platform/darwin/src/MGLOfflineStorage.mm b/platform/darwin/src/MGLOfflineStorage.mm
index 81774ad3cb..2ddfa649e9 100644
--- a/platform/darwin/src/MGLOfflineStorage.mm
+++ b/platform/darwin/src/MGLOfflineStorage.mm
@@ -10,8 +10,13 @@
#import "NSBundle+MGLAdditions.h"
#import "NSValue+MGLAdditions.h"
+#include <mbgl/actor/actor.hpp>
+#include <mbgl/storage/resource_transform.hpp>
+#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/string.hpp>
+#include <memory>
+
static NSString * const MGLOfflineStorageFileName = @"cache.db";
static NSString * const MGLOfflineStorageFileName3_2_0_beta_1 = @"offline.db";
@@ -36,7 +41,9 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
@end
-@implementation MGLOfflineStorage
+@implementation MGLOfflineStorage {
+ std::unique_ptr<mbgl::Actor<mbgl::ResourceTransform>> _mbglResourceTransform;
+}
+ (instancetype)sharedOfflineStorage {
static dispatch_once_t onceToken;
@@ -74,7 +81,7 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
- (void)setDelegate:(id<MGLOfflineStorageDelegate>)newValue {
_delegate = newValue;
if ([self.delegate respondsToSelector:@selector(offlineStorage:URLForResourceOfKind:withURL:)]) {
- _mbglFileSource->setResourceTransform([offlineStorage = self](auto kind_, std::string&& url_) -> std::string {
+ _mbglResourceTransform = std::make_unique<mbgl::Actor<mbgl::ResourceTransform>>(*mbgl::util::RunLoop::Get(), [offlineStorage = self](auto kind_, const std::string&& url_) -> std::string {
NSURL* url =
[NSURL URLWithString:[[NSString alloc] initWithBytes:url_.data()
length:url_.length()
@@ -99,6 +106,9 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
case mbgl::Resource::Kind::SpriteJSON:
kind = MGLResourceKindSpriteJSON;
break;
+ case mbgl::Resource::Kind::Image:
+ kind = MGLResourceKindImage;
+ break;
case mbgl::Resource::Kind::Unknown:
kind = MGLResourceKindUnknown;
break;
@@ -109,8 +119,11 @@ NSString * const MGLOfflinePackMaximumCountUserInfoKey = MGLOfflinePackUserInfoK
withURL:url];
return url.absoluteString.UTF8String;
});
+
+ _mbglFileSource->setResourceTransform(_mbglResourceTransform->self());
} else {
- _mbglFileSource->setResourceTransform(nullptr);
+ _mbglResourceTransform.reset();
+ _mbglFileSource->setResourceTransform({});
}
}
diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.h b/platform/darwin/src/MGLOpenGLStyleLayer.h
index bdad5f9d07..0b494e8062 100644
--- a/platform/darwin/src/MGLOpenGLStyleLayer.h
+++ b/platform/darwin/src/MGLOpenGLStyleLayer.h
@@ -8,6 +8,7 @@
NS_ASSUME_NONNULL_BEGIN
@class MGLMapView;
+@class MGLStyle;
typedef struct MGLStyleLayerDrawingContext {
CGSize size;
@@ -21,7 +22,7 @@ typedef struct MGLStyleLayerDrawingContext {
MGL_EXPORT
@interface MGLOpenGLStyleLayer : MGLStyleLayer
-@property (nonatomic, weak, readonly) MGLMapView *mapView;
+@property (nonatomic, weak, readonly) MGLStyle *style;
- (instancetype)initWithIdentifier:(NSString *)identifier;
diff --git a/platform/darwin/src/MGLOpenGLStyleLayer.mm b/platform/darwin/src/MGLOpenGLStyleLayer.mm
index 39eda758eb..36a3c20c97 100644
--- a/platform/darwin/src/MGLOpenGLStyleLayer.mm
+++ b/platform/darwin/src/MGLOpenGLStyleLayer.mm
@@ -4,7 +4,6 @@
#import "MGLStyle_Private.h"
#import "MGLStyleLayer_Private.h"
-#include <mbgl/map/map.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
#include <mbgl/math/wrap.hpp>
@@ -17,7 +16,7 @@
*/
void MGLPrepareCustomStyleLayer(void *context) {
MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context;
- [layer didMoveToMapView:layer.mapView];
+ [layer didMoveToMapView:layer.style.mapView];
}
/**
@@ -37,7 +36,7 @@ void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRender
.pitch = static_cast<CGFloat>(params.pitch),
.fieldOfView = static_cast<CGFloat>(params.fieldOfView),
};
- [layer drawInMapView:layer.mapView withContext:drawingContext];
+ [layer drawInMapView:layer.style.mapView withContext:drawingContext];
}
/**
@@ -49,7 +48,7 @@ void MGLDrawCustomStyleLayer(void *context, const mbgl::style::CustomLayerRender
*/
void MGLFinishCustomStyleLayer(void *context) {
MGLOpenGLStyleLayer *layer = (__bridge MGLOpenGLStyleLayer *)context;
- [layer willMoveFromMapView:layer.mapView];
+ [layer willMoveFromMapView:layer.style.mapView];
}
/**
@@ -75,12 +74,12 @@ void MGLFinishCustomStyleLayer(void *context) {
@property (nonatomic, readonly) mbgl::style::CustomLayer *rawLayer;
/**
- The map view whose style currently contains the layer.
+ The style currently containing the layer.
- If the layer is not currently part of any map view’s style, this property is
+ If the layer is not currently part of any style, this property is
set to `nil`.
*/
-@property (nonatomic, weak, readwrite) MGLMapView *mapView;
+@property (nonatomic, weak, readwrite) MGLStyle *style;
@end
@@ -112,24 +111,24 @@ void MGLFinishCustomStyleLayer(void *context) {
#pragma mark - Adding to and removing from a map view
-- (void)setMapView:(MGLMapView *)mapView {
- if (_mapView && mapView) {
+- (void)setStyle:(MGLStyle *)style {
+ if (_style && style) {
[NSException raise:@"MGLLayerReuseException"
format:@"%@ cannot be added to more than one MGLStyle at a time.", self];
}
- _mapView.style.openGLLayers[self.identifier] = nil;
- _mapView = mapView;
- _mapView.style.openGLLayers[self.identifier] = self;
+ _style.openGLLayers[self.identifier] = nil;
+ _style = style;
+ _style.openGLLayers[self.identifier] = self;
}
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer {
- self.mapView = mapView;
- [super addToMapView:mapView belowLayer:otherLayer];
+- (void)addToStyle:(MGLStyle *)style belowLayer:(MGLStyleLayer *)otherLayer {
+ self.style = style;
+ [super addToStyle:style belowLayer:otherLayer];
}
-- (void)removeFromMapView:(MGLMapView *)mapView {
- [super removeFromMapView:mapView];
- self.mapView = nil;
+- (void)removeFromStyle:(MGLStyle *)style {
+ [super removeFromStyle:style];
+ self.style = nil;
}
/**
@@ -193,7 +192,7 @@ void MGLFinishCustomStyleLayer(void *context) {
causing the `-drawInMapView:withContext:` method to be called.
*/
- (void)setNeedsDisplay {
- [self.mapView setNeedsGLDisplay];
+ [self.style.mapView setNeedsGLDisplay];
}
@end
diff --git a/platform/darwin/src/MGLRasterStyleLayer.h b/platform/darwin/src/MGLRasterStyleLayer.h
index 53a6a98b8a..09fafd114d 100644
--- a/platform/darwin/src/MGLRasterStyleLayer.h
+++ b/platform/darwin/src/MGLRasterStyleLayer.h
@@ -28,9 +28,6 @@ NS_ASSUME_NONNULL_BEGIN
### Example
```swift
- let layer = MGLRasterStyleLayer(identifier: "clouds", source: source)
- layer.rasterOpacity = MGLStyleValue(rawValue: 0.5)
- mapView.style?.addLayer(layer)
```
*/
MGL_EXPORT
diff --git a/platform/darwin/src/MGLShapeSource.mm b/platform/darwin/src/MGLShapeSource.mm
index 023a81bba8..11b1d8eca8 100644
--- a/platform/darwin/src/MGLShapeSource.mm
+++ b/platform/darwin/src/MGLShapeSource.mm
@@ -1,5 +1,6 @@
#import "MGLShapeSource_Private.h"
+#import "MGLStyle_Private.h"
#import "MGLMapView_Private.h"
#import "MGLSource_Private.h"
#import "MGLFeature_Private.h"
@@ -96,8 +97,8 @@ const MGLShapeSourceOption MGLShapeSourceOptionSimplificationTolerance = @"MGLSh
}
std::vector<mbgl::Feature> features;
- if (self.mapView) {
- features = self.mapView.mbglMap->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter });
+ if (self.style) {
+ features = self.style.mapView.mbglMap->querySourceFeatures(self.rawSource->getID(), { {}, optionalFilter });
}
return MGLFeaturesFromMBGLFeatures(features);
}
diff --git a/platform/darwin/src/MGLSource.h b/platform/darwin/src/MGLSource.h
index a504a01791..8d8c936833 100644
--- a/platform/darwin/src/MGLSource.h
+++ b/platform/darwin/src/MGLSource.h
@@ -16,7 +16,7 @@ NS_ASSUME_NONNULL_BEGIN
add and remove sources dynamically using methods such as
`-[MGLStyle addSource:]` and `-[MGLStyle sourceWithIdentifier:]`.
- Create instances of `MGLShapeSource` and the concrete subclasses of
+ Create instances of `MGLShapeSource`, `MGLImageSource` and the concrete subclasses of
`MGLTileSource` (`MGLVectorSource` and `MGLRasterSource`) in order to use
`MGLSource`'s properties and methods. Do not create instances of `MGLSource`
directly, and do not create your own subclasses of this class.
diff --git a/platform/darwin/src/MGLSource.mm b/platform/darwin/src/MGLSource.mm
index eb859ba2c0..ee012f4d66 100644
--- a/platform/darwin/src/MGLSource.mm
+++ b/platform/darwin/src/MGLSource.mm
@@ -1,7 +1,7 @@
#import "MGLSource_Private.h"
-#import "MGLMapView_Private.h"
+#import "MGLStyle_Private.h"
-#include <mbgl/map/map.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/source.hpp>
@interface MGLSource ()
@@ -10,7 +10,7 @@
// special internal source types like mbgl::AnnotationSource.
@property (nonatomic, readonly) mbgl::style::Source *rawSource;
-@property (nonatomic, readonly, weak) MGLMapView *mapView;
+@property (nonatomic, readonly, weak) MGLStyle *style;
@end
@@ -43,21 +43,21 @@
return self;
}
-- (void)addToMapView:(MGLMapView *)mapView {
+- (void)addToStyle:(MGLStyle *)style {
if (_pendingSource == nullptr) {
[NSException raise:@"MGLRedundantSourceException"
format:@"This instance %@ was already added to %@. Adding the same source instance " \
- "to the style more than once is invalid.", self, mapView.style];
+ "to the style more than once is invalid.", self, style];
}
- _mapView = mapView;
- mapView.mbglMap->addSource(std::move(_pendingSource));
+ _style = style;
+ style.rawStyle->addSource(std::move(_pendingSource));
}
-- (void)removeFromMapView:(MGLMapView *)mapView {
- if (self.rawSource == mapView.mbglMap->getSource(self.identifier.UTF8String)) {
- _pendingSource = mapView.mbglMap->removeSource(self.identifier.UTF8String);
- _mapView = nil;
+- (void)removeFromStyle:(MGLStyle *)style {
+ if (self.rawSource == style.rawStyle->getSource(self.identifier.UTF8String)) {
+ _pendingSource = style.rawStyle->removeSource(self.identifier.UTF8String);
+ _style = nil;
}
}
diff --git a/platform/darwin/src/MGLSource_Private.h b/platform/darwin/src/MGLSource_Private.h
index 91bfac6390..ba78973279 100644
--- a/platform/darwin/src/MGLSource_Private.h
+++ b/platform/darwin/src/MGLSource_Private.h
@@ -18,7 +18,7 @@ struct SourceWrapper {
__weak MGLSource *source;
};
-@class MGLMapView;
+@class MGLStyle;
@interface MGLSource (Private)
@@ -44,33 +44,33 @@ struct SourceWrapper {
@property (nonatomic, readonly) mbgl::style::Source *rawSource;
/**
- The map view whose style currently contains the source.
+ The style which currently contains the source.
- If the source is not currently part of any map view’s style, this property is
+ If the source is not currently part of a style, this property is
set to `nil`.
*/
-@property (nonatomic, readonly, weak) MGLMapView *mapView;
+@property (nonatomic, readonly, weak) MGLStyle *style;
/**
- Adds the mbgl source that this object represents to the mbgl map.
+ Adds the mbgl source that this object represents to the style.
Once a mbgl source is added, ownership of the object is transferred to the
- `mbgl::Map` and this object no longer has an active unique_ptr reference to the
+ `mbgl::Style` and this object no longer has an active unique_ptr reference to the
`mbgl::Source`. If this object's mbgl source is in that state, the mbgl source
can still be changed but the changes will not be visible until the `MGLSource`
- is added back to the map via `-[MGLStyle addSource:]` and styled with a
+ is added back to the style via `-[MGLStyle addSource:]` and styled with a
`MGLLayer`.
*/
-- (void)addToMapView:(MGLMapView *)mapView;
+- (void)addToStyle:(MGLStyle *)style;
/**
- Removes the mbgl source that this object represents from the mbgl map.
+ Removes the mbgl source that this object represents from the style.
When a mbgl source is removed, ownership of the object is transferred back
to the `MGLSource` instance and the unique_ptr reference is valid again. It is
safe to add the source back to the style after it is removed.
*/
-- (void)removeFromMapView:(MGLMapView *)mapView;
+- (void)removeFromStyle:(MGLStyle *)style;
@end
diff --git a/platform/darwin/src/MGLStyle.h b/platform/darwin/src/MGLStyle.h
index 8ffd7db2b2..6fb4a6cc6b 100644
--- a/platform/darwin/src/MGLStyle.h
+++ b/platform/darwin/src/MGLStyle.h
@@ -32,51 +32,14 @@ NS_ASSUME_NONNULL_BEGIN
static MGL_EXPORT const NSInteger MGLStyleDefaultVersion = 10;
/**
- An `MGLStyle` object represents the active map style of an `MGLMapView`. A
- style defines both the map’s content and every aspect of its appearance. Styles
- can be designed in
- <a href="https://www.mapbox.com/studio/">Mapbox Studio</a> and hosted on
- mapbox.com. `MGLStyle` provides methods for inspecting and manipulating a style
- dynamically, with classes and properties that parallel the style JSON format
- defined by the
- <a href="https://www.mapbox.com/mapbox-gl-js/style-spec/">Mapbox Style Specification</a>.
-
- You set a map view’s active style using the `MGLMapView.styleURL` property.
- `MGLStyle` provides a set of convenience methods that return the URLs of
- <a href="https://www.mapbox.com/maps/">popular Mapbox-designed styles</a>.
- Once the `-[MGLMapViewDelegate mapView:didFinishLoadingStyle:]` or
- `-[MGLMapViewDelegate mapViewDidFinishLoadingMap:]` method is called, signaling
- that the style has finished loading, you can use the `MGLMapView.style`
- property to obtain the map view’s `MGLStyle`.
-
- A style primarily consists of the following components:
-
- * _Content sources_ supply content to be shown on the map. Use methods such as
- `-sourceWithIdentifier:` and `-addSource:` to configure the style’s content
- sources, which are represented by `MGLSource` objects.
- * _Style layers_ manage the layout and appearance of content at specific
- z-indices in the style. Most kinds of style layers display content provided
- by a content source. Use methods such as `-layerWithIdentifier:` and
- `-addLayer:` to configure the style’s layers, which are represented by
- `MGLStyleLayer` objects.
- * _Style images_ are used as icons and patterns in style layers. Use the
- `-setImage:forName:` method to register an image as a style image.
- (Annotations are represented by annotation images rather than style images.
- To configure an annotation’s appearance, use the
- `-[MGLMapViewDelegate mapView:imageForAnnotation:]` method.)
- * The style’s _light_ is the light source affecting any 3D extruded fills.
- Use the `light` property to configure the style’s light, which is represented
- by an `MGLLight` object.
-
- The `MGLStyle`, `MGLSource`, `MGLStyleLayer`, and `MGLLight` classes are
- collectively known as the _runtime styling API_. The active style influences a
- related API, visible feature querying, which is available through methods such
- as `-[MGLMapView visibleFeaturesInRect:]`.
-
- Some terminology differs between the Mapbox Style Specification and the various
- classes associated with `MGLStyle`. Consult the
- “[Information for Style Authors](../for-style-authors.html)” guide for an
- overview of these differences.
+ The proxy object for the current map style.
+
+ MGLStyle provides a set of convenience methods for changing Mapbox
+ default styles using `-[MGLMapView styleURL]`.
+ <a href="https://www.mapbox.com/maps/">Learn more about Mapbox default styles</a>.
+
+ It is also possible to directly manipulate the current map style
+ via `-[MGLMapView style]` by updating the style's data sources or layers.
@note Wait until the map style has finished loading before modifying a map's
style via any of the `MGLStyle` instance methods below. You can use the
@@ -521,40 +484,24 @@ MGL_EXPORT
#pragma mark Managing Style Classes
/**
- Currently active style classes, represented as an array of string identifiers.
+ Support for style classes has been removed. This property always returns an empty array.
*/
-@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((deprecated("This property will be removed in a future release.")));
+@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((deprecated("This property is non-functional.")));
/**
- Returns a Boolean value indicating whether the style class with the given
- identifier is currently active.
-
- @param styleClass The style class to query for.
- @return Whether the style class is currently active.
+ Support for style classes has been removed. This method always returns NO.
*/
-- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
+- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
/**
- Activates the style class with the given identifier.
-
- @param styleClass The style class to activate.
+ Support for style classes has been removed. This method is a no-op.
*/
-- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
+- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
/**
- Deactivates the style class with the given identifier.
-
- @note Style class names are not guaranteed to exist across styles or different
- versions of the same style. Applications that use this API must first set the
- style URL to an explicitly versioned style using a convenience method like
- `+[MGLStyle outdoorsStyleURLWithVersion:]`, `MGLMapView`’s “Style URL”
- inspectable in Interface Builder, or a manually constructed `NSURL`. This
- approach also avoids style class name changes that will occur in the default
- style over time.
-
- @param styleClass The style class to deactivate.
+ Support for style classes has been removed. This method is a no-op.
*/
-- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("This method will be removed in a future release.")));
+- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
#pragma mark Managing a Style’s Images
diff --git a/platform/darwin/src/MGLStyle.mm b/platform/darwin/src/MGLStyle.mm
index eb838085d7..2365641f02 100644
--- a/platform/darwin/src/MGLStyle.mm
+++ b/platform/darwin/src/MGLStyle.mm
@@ -2,6 +2,7 @@
#import "MGLMapView_Private.h"
#import "MGLStyleLayer.h"
+#import "MGLStyleLayer_Private.h"
#import "MGLFillStyleLayer.h"
#import "MGLFillExtrusionStyleLayer.h"
#import "MGLLineStyleLayer.h"
@@ -11,23 +12,20 @@
#import "MGLBackgroundStyleLayer.h"
#import "MGLOpenGLStyleLayer.h"
-#import "MGLStyle_Private.h"
-#import "MGLStyleLayer_Private.h"
+#import "MGLSource.h"
#import "MGLSource_Private.h"
#import "MGLLight_Private.h"
-
-#import "NSDate+MGLAdditions.h"
-
-#import "MGLSource.h"
#import "MGLTileSource_Private.h"
#import "MGLVectorSource.h"
#import "MGLRasterSource.h"
#import "MGLShapeSource.h"
+#import "MGLImageSource.h"
#import "MGLAttributionInfo_Private.h"
#include <mbgl/map/map.hpp>
#include <mbgl/util/default_styles.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/style/light.hpp>
#include <mbgl/style/layers/fill_layer.hpp>
@@ -41,6 +39,9 @@
#include <mbgl/style/sources/geojson_source.hpp>
#include <mbgl/style/sources/vector_source.hpp>
#include <mbgl/style/sources/raster_source.hpp>
+#include <mbgl/style/sources/image_source.hpp>
+
+#import "NSDate+MGLAdditions.h"
#if TARGET_OS_IPHONE
#import "UIImage+MGLAdditions.h"
@@ -50,7 +51,8 @@
@interface MGLStyle()
-@property (nonatomic, readwrite, weak) MGLMapView *mapView;
+@property (nonatomic, readonly, weak) MGLMapView *mapView;
+@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
@property (readonly, copy, nullable) NSURL *URL;
@property (nonatomic, readwrite, strong) NS_MUTABLE_DICTIONARY_OF(NSString *, MGLOpenGLStyleLayer *) *openGLLayers;
@@ -112,27 +114,28 @@ static NSURL *MGLStyleURL_emerald;
#pragma mark -
-- (instancetype)initWithMapView:(MGLMapView *)mapView {
+- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle mapView:(MGLMapView *)mapView {
if (self = [super init]) {
_mapView = mapView;
+ _rawStyle = rawStyle;
_openGLLayers = [NSMutableDictionary dictionary];
}
return self;
}
- (NSURL *)URL {
- return [NSURL URLWithString:@(self.mapView.mbglMap->getStyleURL().c_str())];
+ return [NSURL URLWithString:@(self.rawStyle->getURL().c_str())];
}
- (NSString *)name {
- std::string name = self.mapView.mbglMap->getStyleName();
+ std::string name = self.rawStyle->getName();
return name.empty() ? nil : @(name.c_str());
}
#pragma mark Sources
- (NS_SET_OF(__kindof MGLSource *) *)sources {
- auto rawSources = self.mapView.mbglMap->getSources();
+ auto rawSources = self.rawStyle->getSources();
NS_MUTABLE_SET_OF(__kindof MGLSource *) *sources = [NSMutableSet setWithCapacity:rawSources.size()];
for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) {
MGLSource *source = [self sourceFromMBGLSource:*rawSource];
@@ -151,8 +154,7 @@ static NSURL *MGLStyleURL_emerald;
}
- (NSUInteger)countOfSources {
- auto rawSources = self.mapView.mbglMap->getSources();
- return rawSources.size();
+ return self.rawStyle->getSources().size();
}
- (MGLSource *)memberOfSources:(MGLSource *)object {
@@ -161,7 +163,7 @@ static NSURL *MGLStyleURL_emerald;
- (MGLSource *)sourceWithIdentifier:(NSString *)identifier
{
- auto rawSource = self.mapView.mbglMap->getSource(identifier.UTF8String);
+ auto rawSource = self.rawStyle->getSource(identifier.UTF8String);
return rawSource ? [self sourceFromMBGLSource:rawSource] : nil;
}
@@ -178,6 +180,8 @@ static NSURL *MGLStyleURL_emerald;
return [[MGLShapeSource alloc] initWithRawSource:geoJSONSource];
} else if (auto rasterSource = rawSource->as<mbgl::style::RasterSource>()) {
return [[MGLRasterSource alloc] initWithRawSource:rasterSource];
+ } else if (auto imageSource = rawSource->as<mbgl::style::ImageSource>()) {
+ return [[MGLImageSource alloc] initWithRawSource:imageSource];
} else {
return [[MGLSource alloc] initWithRawSource:rawSource];
}
@@ -193,7 +197,7 @@ static NSURL *MGLStyleURL_emerald;
}
try {
- [source addToMapView:self.mapView];
+ [source addToStyle:self];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantSourceIdentifierException" format:@"%s", err.what()];
}
@@ -207,14 +211,14 @@ static NSURL *MGLStyleURL_emerald;
@"Make sure the source was created as a member of a concrete subclass of MGLSource.",
source];
}
- [source removeFromMapView:self.mapView];
+ [source removeFromStyle:self];
}
- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor {
// It’d be incredibly convenient to use -sources here, but this operation
// depends on the sources being sorted in ascending order by creation, as
// with the std::vector used in mbgl.
- auto rawSources = self.mapView.mbglMap->getSources();
+ auto rawSources = self.rawStyle->getSources();
NSMutableArray *infos = [NSMutableArray arrayWithCapacity:rawSources.size()];
for (auto rawSource = rawSources.begin(); rawSource != rawSources.end(); ++rawSource) {
MGLTileSource *source = (MGLTileSource *)[self sourceFromMBGLSource:*rawSource];
@@ -232,7 +236,7 @@ static NSURL *MGLStyleURL_emerald;
- (NS_ARRAY_OF(__kindof MGLStyleLayer *) *)layers
{
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
NS_MUTABLE_ARRAY_OF(__kindof MGLStyleLayer *) *styleLayers = [NSMutableArray arrayWithCapacity:layers.size()];
for (auto layer : layers) {
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
@@ -252,12 +256,12 @@ static NSURL *MGLStyleURL_emerald;
- (NSUInteger)countOfLayers
{
- return self.mapView.mbglMap->getLayers().size();
+ return self.rawStyle->getLayers().size();
}
- (MGLStyleLayer *)objectInLayersAtIndex:(NSUInteger)index
{
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
if (index >= layers.size()) {
[NSException raise:NSRangeException
format:@"No style layer at index %lu.", (unsigned long)index];
@@ -269,7 +273,7 @@ static NSURL *MGLStyleURL_emerald;
- (void)getLayers:(MGLStyleLayer **)buffer range:(NSRange)inRange
{
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
if (NSMaxRange(inRange) > layers.size()) {
[NSException raise:NSRangeException
format:@"Style layer range %@ is out of bounds.", NSStringFromRange(inRange)];
@@ -289,21 +293,21 @@ static NSURL *MGLStyleURL_emerald;
@"Make sure the style layer was created as a member of a concrete subclass of MGLStyleLayer.",
styleLayer];
}
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
if (index > layers.size()) {
[NSException raise:NSRangeException
format:@"Cannot insert style layer at out-of-bounds index %lu.", (unsigned long)index];
} else if (index == 0) {
try {
MGLStyleLayer *sibling = layers.size() ? [self layerFromMBGLLayer:layers.at(0)] : nil;
- [styleLayer addToMapView:self.mapView belowLayer:sibling];
+ [styleLayer addToStyle:self belowLayer:sibling];
} catch (const std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
} else {
try {
MGLStyleLayer *sibling = [self layerFromMBGLLayer:layers.at(index)];
- [styleLayer addToMapView:self.mapView belowLayer:sibling];
+ [styleLayer addToStyle:self belowLayer:sibling];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
@@ -312,14 +316,14 @@ static NSURL *MGLStyleURL_emerald;
- (void)removeObjectFromLayersAtIndex:(NSUInteger)index
{
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
if (index >= layers.size()) {
[NSException raise:NSRangeException
format:@"Cannot remove style layer at out-of-bounds index %lu.", (unsigned long)index];
}
auto layer = layers.at(index);
MGLStyleLayer *styleLayer = [self layerFromMBGLLayer:layer];
- [styleLayer removeFromMapView:self.mapView];
+ [styleLayer removeFromStyle:self];
}
- (MGLStyleLayer *)layerFromMBGLLayer:(mbgl::style::Layer *)rawLayer
@@ -354,7 +358,7 @@ static NSURL *MGLStyleURL_emerald;
- (MGLStyleLayer *)layerWithIdentifier:(NSString *)identifier
{
- auto mbglLayer = self.mapView.mbglMap->getLayer(identifier.UTF8String);
+ auto mbglLayer = self.rawStyle->getLayer(identifier.UTF8String);
return mbglLayer ? [self layerFromMBGLLayer:mbglLayer] : nil;
}
@@ -367,7 +371,7 @@ static NSURL *MGLStyleURL_emerald;
layer];
}
[self willChangeValueForKey:@"layers"];
- [layer removeFromMapView:self.mapView];
+ [layer removeFromStyle:self];
[self didChangeValueForKey:@"layers"];
}
@@ -381,7 +385,7 @@ static NSURL *MGLStyleURL_emerald;
}
[self willChangeValueForKey:@"layers"];
try {
- [layer addToMapView:self.mapView belowLayer:nil];
+ [layer addToStyle:self belowLayer:nil];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
@@ -410,7 +414,7 @@ static NSURL *MGLStyleURL_emerald;
}
[self willChangeValueForKey:@"layers"];
try {
- [layer addToMapView:self.mapView belowLayer:sibling];
+ [layer addToStyle:self belowLayer:sibling];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
@@ -433,7 +437,7 @@ static NSURL *MGLStyleURL_emerald;
sibling];
}
- auto layers = self.mapView.mbglMap->getLayers();
+ auto layers = self.rawStyle->getLayers();
std::string siblingIdentifier = sibling.identifier.UTF8String;
NSUInteger index = 0;
for (auto layer : layers) {
@@ -452,14 +456,14 @@ static NSURL *MGLStyleURL_emerald;
sibling];
} else if (index + 1 == layers.size()) {
try {
- [layer addToMapView:self.mapView belowLayer:nil];
+ [layer addToStyle:self belowLayer:nil];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
} else {
MGLStyleLayer *sibling = [self layerFromMBGLLayer:layers.at(index + 1)];
try {
- [layer addToMapView:self.mapView belowLayer:sibling];
+ [layer addToStyle:self belowLayer:sibling];
} catch (std::runtime_error & err) {
[NSException raise:@"MGLRedundantLayerIdentifierException" format:@"%s", err.what()];
}
@@ -471,60 +475,32 @@ static NSURL *MGLStyleURL_emerald;
- (NS_ARRAY_OF(NSString *) *)styleClasses
{
- const std::vector<std::string> &appliedClasses = self.mapView.mbglMap->getClasses();
-
- NSMutableArray *returnArray = [NSMutableArray arrayWithCapacity:appliedClasses.size()];
-
- for (auto appliedClass : appliedClasses) {
- [returnArray addObject:@(appliedClass.c_str())];
- }
-
- return returnArray;
+ return @[];
}
- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses
{
- [self setStyleClasses:appliedClasses transitionDuration:0];
}
- (void)setStyleClasses:(NS_ARRAY_OF(NSString *) *)appliedClasses transitionDuration:(NSTimeInterval)transitionDuration
{
- std::vector<std::string> newAppliedClasses;
-
- for (NSString *appliedClass in appliedClasses)
- {
- newAppliedClasses.push_back([appliedClass UTF8String]);
- }
-
- mbgl::style::TransitionOptions transition { { MGLDurationFromTimeInterval(transitionDuration) } };
- self.mapView.mbglMap->setTransitionOptions(transition);
- self.mapView.mbglMap->setClasses(newAppliedClasses);
}
- (NSUInteger)countOfStyleClasses {
- const auto &classes = self.mapView.mbglMap->getClasses();
- return classes.size();
+ return 0;
}
- (BOOL)hasStyleClass:(NSString *)styleClass
{
- return styleClass && self.mapView.mbglMap->hasClass([styleClass UTF8String]);
+ return NO;
}
- (void)addStyleClass:(NSString *)styleClass
{
- if (styleClass)
- {
- self.mapView.mbglMap->addClass([styleClass UTF8String]);
- }
}
- (void)removeStyleClass:(NSString *)styleClass
{
- if (styleClass)
- {
- self.mapView.mbglMap->removeClass([styleClass UTF8String]);
- }
}
#pragma mark Style images
@@ -540,7 +516,7 @@ static NSURL *MGLStyleURL_emerald;
format:@"Cannot assign image %@ to a nil name.", image];
}
- self.mapView.mbglMap->addImage([name UTF8String], image.mgl_styleImage);
+ self.rawStyle->addImage([image mgl_styleImageWithIdentifier:name]);
}
- (void)removeImageForName:(NSString *)name
@@ -550,7 +526,7 @@ static NSURL *MGLStyleURL_emerald;
format:@"Cannot remove image with nil name."];
}
- self.mapView.mbglMap->removeImage([name UTF8String]);
+ self.rawStyle->removeImage([name UTF8String]);
}
- (MGLImage *)imageForName:(NSString *)name
@@ -560,7 +536,7 @@ static NSURL *MGLStyleURL_emerald;
format:@"Cannot get image with nil name."];
}
- auto styleImage = self.mapView.mbglMap->getImage([name UTF8String]);
+ auto styleImage = self.rawStyle->getImage([name UTF8String]);
return styleImage ? [[MGLImage alloc] initWithMGLStyleImage:styleImage] : nil;
}
@@ -568,17 +544,17 @@ static NSURL *MGLStyleURL_emerald;
- (void)setTransition:(MGLTransition)transition
{
- auto transitionOptions = self.mapView.mbglMap->getTransitionOptions();
+ auto transitionOptions = self.rawStyle->getTransitionOptions();
transitionOptions.duration = MGLDurationFromTimeInterval(transition.duration);
transitionOptions.delay = MGLDurationFromTimeInterval(transition.delay);
- self.mapView.mbglMap->setTransitionOptions(transitionOptions);
+ self.rawStyle->setTransitionOptions(transitionOptions);
}
- (MGLTransition)transition
{
MGLTransition transition;
- const mbgl::style::TransitionOptions transitionOptions = self.mapView.mbglMap->getTransitionOptions();
+ const mbgl::style::TransitionOptions transitionOptions = self.rawStyle->getTransitionOptions();
transition.delay = MGLTimeIntervalFromDuration(transitionOptions.delay.value_or(mbgl::Duration::zero()));
transition.duration = MGLTimeIntervalFromDuration(transitionOptions.duration.value_or(mbgl::Duration::zero()));
@@ -591,12 +567,12 @@ static NSURL *MGLStyleURL_emerald;
- (void)setLight:(MGLLight *)light
{
std::unique_ptr<mbgl::style::Light> mbglLight = std::make_unique<mbgl::style::Light>([light mbglLight]);
- self.mapView.mbglMap->setLight(std::move(mbglLight));
+ self.rawStyle->setLight(std::move(mbglLight));
}
- (MGLLight *)light
{
- auto mbglLight = self.mapView.mbglMap->getLight();
+ auto mbglLight = self.rawStyle->getLight();
MGLLight *light = [[MGLLight alloc] initWithMBGLLight:mbglLight];
return light;
}
diff --git a/platform/darwin/src/MGLStyleLayer.mm b/platform/darwin/src/MGLStyleLayer.mm
index 4bfaea934b..6400b8fcbf 100644
--- a/platform/darwin/src/MGLStyleLayer.mm
+++ b/platform/darwin/src/MGLStyleLayer.mm
@@ -1,7 +1,7 @@
#import "MGLStyleLayer_Private.h"
-#import "MGLMapView_Private.h"
+#import "MGLStyle_Private.h"
-#include <mbgl/map/map.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/layer.hpp>
@interface MGLStyleLayer ()
@@ -30,26 +30,26 @@
return self;
}
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(MGLStyleLayer *)otherLayer
+- (void)addToStyle:(MGLStyle *)style belowLayer:(MGLStyleLayer *)otherLayer
{
if (_pendingLayer == nullptr) {
[NSException raise:@"MGLRedundantLayerException"
format:@"This instance %@ was already added to %@. Adding the same layer instance " \
- "to the style more than once is invalid.", self, mapView.style];
+ "to the style more than once is invalid.", self, style];
}
if (otherLayer) {
const mbgl::optional<std::string> belowLayerId{otherLayer.identifier.UTF8String};
- mapView.mbglMap->addLayer(std::move(_pendingLayer), belowLayerId);
+ style.rawStyle->addLayer(std::move(_pendingLayer), belowLayerId);
} else {
- mapView.mbglMap->addLayer(std::move(_pendingLayer));
+ style.rawStyle->addLayer(std::move(_pendingLayer));
}
}
-- (void)removeFromMapView:(MGLMapView *)mapView
+- (void)removeFromStyle:(MGLStyle *)style
{
- if (self.rawLayer == mapView.mbglMap->getLayer(self.identifier.UTF8String)) {
- _pendingLayer = mapView.mbglMap->removeLayer(self.identifier.UTF8String);
+ if (self.rawLayer == style.rawStyle->getLayer(self.identifier.UTF8String)) {
+ _pendingLayer = style.rawStyle->removeLayer(self.identifier.UTF8String);
}
}
diff --git a/platform/darwin/src/MGLStyleLayer_Private.h b/platform/darwin/src/MGLStyleLayer_Private.h
index ed8ec31755..9bee013c3d 100644
--- a/platform/darwin/src/MGLStyleLayer_Private.h
+++ b/platform/darwin/src/MGLStyleLayer_Private.h
@@ -34,7 +34,7 @@ struct LayerWrapper {
} \
} while (NO);
-@class MGLMapView;
+@class MGLStyle;
@interface MGLStyleLayer (Private)
@@ -69,7 +69,7 @@ struct LayerWrapper {
`mbgl::Map` and this object no longer has an active unique_ptr reference to the
`mbgl::style::Layer`.
*/
-- (void)addToMapView:(MGLMapView *)mapView belowLayer:(nullable MGLStyleLayer *)otherLayer;
+- (void)addToStyle:(MGLStyle *)style belowLayer:(nullable MGLStyleLayer *)otherLayer;
/**
Removes the mbgl style layer that this object represents from the mbgl map.
@@ -78,7 +78,7 @@ struct LayerWrapper {
to the `MGLStyleLayer` instance and the unique_ptr reference is valid again. It
is safe to add the layer back to the style after it is removed.
*/
-- (void)removeFromMapView:(MGLMapView *)mapView;
+- (void)removeFromStyle:(MGLStyle *)style;
@end
diff --git a/platform/darwin/src/MGLStyle_Private.h b/platform/darwin/src/MGLStyle_Private.h
index 23ce8fbee0..92b08e844b 100644
--- a/platform/darwin/src/MGLStyle_Private.h
+++ b/platform/darwin/src/MGLStyle_Private.h
@@ -5,15 +5,22 @@
NS_ASSUME_NONNULL_BEGIN
+namespace mbgl {
+ namespace style {
+ class Style;
+ }
+}
+
@class MGLAttributionInfo;
@class MGLMapView;
@class MGLOpenGLStyleLayer;
@interface MGLStyle (Private)
-- (instancetype)initWithMapView:(MGLMapView *)mapView;
+- (instancetype)initWithRawStyle:(mbgl::style::Style *)rawStyle mapView:(MGLMapView *)mapView;
@property (nonatomic, readonly, weak) MGLMapView *mapView;
+@property (nonatomic, readonly) mbgl::style::Style *rawStyle;
- (nullable NS_ARRAY_OF(MGLAttributionInfo *) *)attributionInfosWithFontSize:(CGFloat)fontSize linkColor:(nullable MGLColor *)linkColor;
diff --git a/platform/darwin/src/MGLSymbolStyleLayer.h b/platform/darwin/src/MGLSymbolStyleLayer.h
index b6c6372324..8512870e1b 100644
--- a/platform/darwin/src/MGLSymbolStyleLayer.h
+++ b/platform/darwin/src/MGLSymbolStyleLayer.h
@@ -265,16 +265,6 @@ typedef NS_ENUM(NSUInteger, MGLTextTranslationAnchor) {
### Example
```swift
- let layer = MGLSymbolStyleLayer(identifier: "coffeeshops", source: pois)
- layer.sourceLayerIdentifier = "pois"
- layer.iconImageName = MGLStyleValue(rawValue: "coffee")
- layer.iconScale = MGLStyleValue(rawValue: 0.5)
- layer.text = MGLStyleValue(rawValue: "{name}")
- layer.textTranslation = MGLStyleValue(rawValue: NSValue(cgVector: CGVector(dx: 10, dy: 0)))
- layer.textJustification = MGLStyleValue(rawValue: NSValue(mglTextJustification: .left))
- layer.textAnchor = MGLStyleValue(rawValue: NSValue(mglTextAnchor: .left))
- layer.predicate = NSPredicate(format: "%K == %@", "venue-type", "coffee")
- mapView.style?.addLayer(layer)
```
*/
MGL_EXPORT
@@ -533,7 +523,11 @@ MGL_EXPORT
@property (nonatomic, null_resettable) MGLStyleValue<NSValue *> *iconRotationAlignment;
/**
- Scale factor for icon. 1 is original size, 3 triples the size.
+ Scales the original size of the icon by the provided factor. The new point size
+ of the image will be the original point size multiplied by `iconSize`. 1 is the
+ original size; 3 triples the size of the image.
+
+ This property is measured in factor of the original icon sizes.
The default value of this property is an `MGLStyleValue` object containing an
`NSNumber` object containing the float `1`. Set this property to `nil` to reset
diff --git a/platform/darwin/src/MGLVectorSource.mm b/platform/darwin/src/MGLVectorSource.mm
index 5e9f4f4a6e..7265690f4d 100644
--- a/platform/darwin/src/MGLVectorSource.mm
+++ b/platform/darwin/src/MGLVectorSource.mm
@@ -3,6 +3,7 @@
#import "MGLFeature_Private.h"
#import "MGLSource_Private.h"
#import "MGLTileSource_Private.h"
+#import "MGLStyle_Private.h"
#import "MGLMapView_Private.h"
#import "NSPredicate+MGLAdditions.h"
#import "NSURL+MGLAdditions.h"
@@ -62,8 +63,8 @@
}
std::vector<mbgl::Feature> features;
- if (self.mapView) {
- features = self.mapView.mbglMap->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
+ if (self.style) {
+ features = self.style.mapView.mbglMap->querySourceFeatures(self.rawSource->getID(), { optionalSourceLayerIDs, optionalFilter });
}
return MGLFeaturesFromMBGLFeatures(features);
}
diff --git a/platform/darwin/src/NSValue+MGLAdditions.h b/platform/darwin/src/NSValue+MGLAdditions.h
index 0aaa2a337a..f3026a389f 100644
--- a/platform/darwin/src/NSValue+MGLAdditions.h
+++ b/platform/darwin/src/NSValue+MGLAdditions.h
@@ -56,6 +56,20 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (readonly) MGLCoordinateBounds MGLCoordinateBoundsValue;
+/**
+ Creates a new value object containing the specified Mapbox coordinate
+ quad structure.
+
+ @param quad The value for the new object.
+ @return A new value object that contains the coordinate quad information.
+ */
++ (instancetype)valueWithMGLCoordinateQuad:(MGLCoordinateQuad)quad;
+
+/**
+ The Mapbox coordinate quad structure representation of the value.
+ */
+- (MGLCoordinateQuad)MGLCoordinateQuadValue;
+
#pragma mark Working with Offline Map Values
/**
diff --git a/platform/darwin/src/NSValue+MGLAdditions.m b/platform/darwin/src/NSValue+MGLAdditions.m
index ef894f0eb4..1383056944 100644
--- a/platform/darwin/src/NSValue+MGLAdditions.m
+++ b/platform/darwin/src/NSValue+MGLAdditions.m
@@ -34,6 +34,16 @@
return bounds;
}
++ (instancetype)valueWithMGLCoordinateQuad:(MGLCoordinateQuad)quad {
+ return [self valueWithBytes:&quad objCType:@encode(MGLCoordinateQuad)];
+}
+
+- (MGLCoordinateQuad)MGLCoordinateQuadValue {
+ MGLCoordinateQuad quad;
+ [self getValue:&quad];
+ return quad;
+}
+
#pragma mark Offline maps
+ (NSValue *)valueWithMGLOfflinePackProgress:(MGLOfflinePackProgress)progress {
diff --git a/platform/darwin/src/nsthread.mm b/platform/darwin/src/nsthread.mm
index 6caa1be43e..458db968d8 100644
--- a/platform/darwin/src/nsthread.mm
+++ b/platform/darwin/src/nsthread.mm
@@ -15,7 +15,8 @@ std::string getCurrentThreadName() {
}
void setCurrentThreadName(const std::string& name) {
- pthread_setname_np(name.c_str());
+ std::string qualifiedName = "com.mapbox.mbgl." + name;
+ pthread_setname_np(qualifiedName.c_str());
}
void makeThreadLowPriority() {
diff --git a/platform/darwin/test/MGLDocumentationExampleTests.swift b/platform/darwin/test/MGLDocumentationExampleTests.swift
index 48e6b17f44..ae72b35d82 100644
--- a/platform/darwin/test/MGLDocumentationExampleTests.swift
+++ b/platform/darwin/test/MGLDocumentationExampleTests.swift
@@ -104,6 +104,20 @@ class MGLDocumentationExampleTests: XCTestCase, MGLMapViewDelegate {
XCTAssertNotNil(mapView.style?.source(withIdentifier: "pois"))
}
+ func testMGLImageSource() {
+ //#-example-code
+ let coordinates = MGLCoordinateQuad(
+ topLeft: CLLocationCoordinate2D(latitude: 46.437, longitude: -80.425),
+ bottomLeft: CLLocationCoordinate2D(latitude: 37.936, longitude: -80.425),
+ bottomRight: CLLocationCoordinate2D(latitude: 37.936, longitude: -71.516),
+ topRight: CLLocationCoordinate2D(latitude: 46.437, longitude: -71.516))
+ let source = MGLImageSource(identifier: "radar", coordinateQuad: coordinates, url: URL(string: "https://www.mapbox.com/mapbox-gl-js/assets/radar.gif")!)
+ mapView.style?.addSource(source)
+ //#-end-example-code
+
+ XCTAssertNotNil(mapView.style?.source(withIdentifier: "radar"))
+ }
+
func testMGLCircleStyleLayer() {
let population = MGLVectorSource(identifier: "population", configurationURL: URL(string: "https://example.com/style.json")!)
mapView.style?.addSource(population)
diff --git a/platform/darwin/test/MGLGeometryTests.mm b/platform/darwin/test/MGLGeometryTests.mm
index 220a837643..1c85470188 100644
--- a/platform/darwin/test/MGLGeometryTests.mm
+++ b/platform/darwin/test/MGLGeometryTests.mm
@@ -144,4 +144,23 @@
XCTAssertEqualObjects(serializedGeoJSON, geoJSON, @"MGLPointFeature should serialize as a GeoJSON point feature.");
}
+- (void)testMGLCoordinateBoundsToMGLCoordinateQuad {
+ MGLCoordinateBounds bounds = MGLCoordinateBoundsMake(CLLocationCoordinate2DMake(37.936, -80.425),
+ CLLocationCoordinate2DMake(46.437, -71.516));
+
+ MGLCoordinateQuad quad = MGLCoordinateQuadFromCoordinateBounds(bounds);
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:bounds.sw],
+ [NSValue valueWithMGLCoordinate:quad.bottomLeft],
+ @"Bounds southwest should be bottom left of quad.");
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:bounds.ne],
+ [NSValue valueWithMGLCoordinate:quad.topRight],
+ @"Bounds northeast should be top right of quad.");
+
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(46.437, -80.425)],
+ [NSValue valueWithMGLCoordinate:quad.topLeft],
+ @"Quad top left should be computed correctly.");
+ XCTAssertEqualObjects([NSValue valueWithMGLCoordinate:CLLocationCoordinate2DMake(37.936, -71.516)],
+ [NSValue valueWithMGLCoordinate:quad.bottomRight],
+ @"Quad bottom right should be computed correctly.");
+}
@end
diff --git a/platform/darwin/test/MGLImageSourceTests.m b/platform/darwin/test/MGLImageSourceTests.m
new file mode 100644
index 0000000000..38fcd38709
--- /dev/null
+++ b/platform/darwin/test/MGLImageSourceTests.m
@@ -0,0 +1,42 @@
+#import <XCTest/XCTest.h>
+
+#import <Mapbox/Mapbox.h>
+
+@interface MGLImageSourceTests : XCTestCase
+
+@end
+
+@implementation MGLImageSourceTests
+
+
+- (void)testMGLImageSourceWithImageURL {
+
+ MGLCoordinateQuad quad = { { 80, 37}, { 81, 37}, { 81, 39}, { 80, 39}};
+ MGLImageSource *source = [[MGLImageSource alloc] initWithIdentifier:@"source-id" coordinateQuad:quad URL:[NSURL URLWithString:@"http://host/image.png"]];
+
+ XCTAssertNotNil(source.URL);
+ XCTAssertEqualObjects(source.URL.absoluteString, @"http://host/image.png");
+ XCTAssertNil(source.image);
+}
+
+- (void)testMGLImageSourceWithImage {
+
+ NSString *imageName = @"RadarImage";
+#if TARGET_OS_IPHONE
+ MGLImage *image = [MGLImage imageNamed:imageName
+ inBundle:[NSBundle bundleForClass:[self class]]
+ compatibleWithTraitCollection:nil];
+#else
+ MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:imageName];
+#endif
+ XCTAssertNotNil(image);
+
+ MGLCoordinateQuad quad = { { 80, 37}, { 81, 37}, { 81, 39}, { 80, 39}};
+ MGLImageSource *source = [[MGLImageSource alloc] initWithIdentifier:@"source-id" coordinateQuad:quad image:image];
+
+ XCTAssertNotNil(source.image);
+ XCTAssertEqualObjects(source.image, image);
+ XCTAssertNil(source.URL);
+}
+
+@end
diff --git a/platform/darwin/test/MGLLightTest.mm b/platform/darwin/test/MGLLightTest.mm
index 8f901cbb72..de64d57851 100644
--- a/platform/darwin/test/MGLLightTest.mm
+++ b/platform/darwin/test/MGLLightTest.mm
@@ -18,7 +18,7 @@
@implementation MGLLightTest
- (void)testProperties {
-
+
MGLTransition defaultTransition = MGLTransitionMake(0, 0);
MGLTransition transition = MGLTransitionMake(6, 3);
mbgl::style::TransitionOptions transitionOptions { { MGLDurationFromTimeInterval(6) }, { MGLDurationFromTimeInterval(3) } };
@@ -35,9 +35,7 @@
XCTAssertEqual(anchorValue.MGLLightAnchorValue, MGLLightAnchorViewport);
mbgl::style::PropertyValue<mbgl::style::LightAnchorType> propertyValue = { mbgl::style::LightAnchorType::Viewport };
-
light.setAnchor(propertyValue);
-
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
lightFromMGLlight = [mglLight mbglLight];
@@ -55,14 +53,12 @@
XCTAssert(positionTransition.delay && MGLTimeIntervalFromDuration(*positionTransition.delay) == defaultTransition.delay);
XCTAssert(positionTransition.duration && MGLTimeIntervalFromDuration(*positionTransition.duration) == defaultTransition.duration);
- const std::array<float, 3> positionArray = { { 6, 180, 90 } };
+ std::array<float, 3> positionArray = { { 6, 180, 90 } };
mbgl::style::Position position = { positionArray };
mbgl::style::PropertyValue<mbgl::style::Position> propertyValue = { position };
-
light.setPosition(propertyValue);
light.setPositionTransition(transitionOptions);
-
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
lightFromMGLlight = [mglLight mbglLight];
@@ -85,11 +81,9 @@
XCTAssert(colorTransition.duration && MGLTimeIntervalFromDuration(*colorTransition.duration) == defaultTransition.duration);
mbgl::style::PropertyValue<mbgl::Color> propertyValue = { { 1, 0, 0, 1 } };
-
light.setColor(propertyValue);
light.setColorTransition(transitionOptions);
-
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
lightFromMGLlight = [mglLight mbglLight];
@@ -112,11 +106,9 @@
XCTAssert(intensityTransition.duration && MGLTimeIntervalFromDuration(*intensityTransition.duration) == defaultTransition.duration);
mbgl::style::PropertyValue<float> propertyValue = { 0xff };
-
light.setIntensity(propertyValue);
light.setIntensityTransition(transitionOptions);
-
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
lightFromMGLlight = [mglLight mbglLight];
@@ -131,10 +123,10 @@
- (void)testValueAdditions {
MGLSphericalPosition position = MGLSphericalPositionMake(1.15, 210, 30);
-
- XCTAssertEqual(@(position).MGLSphericalPositionValue.radial, position.radial);
- XCTAssertEqual(@(position).MGLSphericalPositionValue.azimuthal, position.azimuthal);
- XCTAssertEqual(@(position).MGLSphericalPositionValue.polar, position.polar);
+
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.radial, position.radial);
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.azimuthal, position.azimuthal);
+ XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.polar, position.polar);
XCTAssertEqual([NSValue valueWithMGLLightAnchor:MGLLightAnchorMap].MGLLightAnchorValue, MGLLightAnchorMap);
XCTAssertEqual([NSValue valueWithMGLLightAnchor:MGLLightAnchorViewport].MGLLightAnchorValue, MGLLightAnchorViewport);
}
diff --git a/platform/darwin/test/MGLLightTest.mm.ejs b/platform/darwin/test/MGLLightTest.mm.ejs
index c1904d5ab8..5b1f27d8d1 100644
--- a/platform/darwin/test/MGLLightTest.mm.ejs
+++ b/platform/darwin/test/MGLLightTest.mm.ejs
@@ -22,7 +22,7 @@
@implementation MGLLightTest
- (void)testProperties {
-
+
MGLTransition defaultTransition = MGLTransitionMake(0, 0);
MGLTransition transition = MGLTransitionMake(6, 3);
mbgl::style::TransitionOptions transitionOptions { { MGLDurationFromTimeInterval(6) }, { MGLDurationFromTimeInterval(3) } };
@@ -48,17 +48,17 @@
<% } -%>
<% if (property.type == "array") { -%>
- const std::array<float, 3> positionArray = { { 6, 180, 90 } };
+ std::array<float, 3> positionArray = { { 6, 180, 90 } };
mbgl::style::Position position = { positionArray };
mbgl::style::PropertyValue<mbgl::style::Position> propertyValue = { position };
<% } else { -%>
mbgl::style::PropertyValue<<%- mbglType(property) %>> propertyValue = { <%- mbglTestValue(property, type) %> };
-<% } -%>
+<% } -%>
light.set<%- camelize(property.name) -%>(propertyValue);
<% if (property.transition) { -%>
light.set<%- camelize(property.name) -%>Transition(transitionOptions);
-<% } -%>
+<% } -%>
mglLight = [[MGLLight alloc] initWithMBGLLight:&light];
lightFromMGLlight = [mglLight mbglLight];
@@ -76,7 +76,7 @@
- (void)testValueAdditions {
MGLSphericalPosition position = MGLSphericalPositionMake(1.15, 210, 30);
-
+
XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.radial, position.radial);
XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.azimuthal, position.azimuthal);
XCTAssertEqual([NSValue valueWithMGLSphericalPosition:position].MGLSphericalPositionValue.polar, position.polar);
diff --git a/platform/darwin/test/MGLLineStyleLayerTests.mm b/platform/darwin/test/MGLLineStyleLayerTests.mm
index 1e92959520..be7d9a6754 100644
--- a/platform/darwin/test/MGLLineStyleLayerTests.mm
+++ b/platform/darwin/test/MGLLineStyleLayerTests.mm
@@ -713,7 +713,7 @@
MGLStyleValue<NSNumber *> *constantStyleValue = [MGLStyleValue<NSNumber *> valueWithRawValue:@0xff];
layer.lineWidth = constantStyleValue;
- mbgl::style::PropertyValue<float> propertyValue = { 0xff };
+ mbgl::style::DataDrivenPropertyValue<float> propertyValue = { 0xff };
XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
@"Setting lineWidth to a constant value should update line-width.");
XCTAssertEqualObjects(layer.lineWidth, constantStyleValue,
@@ -730,6 +730,29 @@
XCTAssertEqualObjects(layer.lineWidth, functionStyleValue,
@"lineWidth should round-trip camera functions.");
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential sourceStops:@{@18: constantStyleValue} attributeName:@"keyName" options:nil];
+ layer.lineWidth = functionStyleValue;
+
+ mbgl::style::ExponentialStops<float> exponentialStops = { {{18, 0xff}}, 1.0 };
+ propertyValue = mbgl::style::SourceFunction<float> { "keyName", exponentialStops };
+
+ XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
+ @"Setting lineWidth to a source function should update line-width.");
+ XCTAssertEqualObjects(layer.lineWidth, functionStyleValue,
+ @"lineWidth should round-trip source functions.");
+
+ functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeExponential compositeStops:@{@10: @{@18: constantStyleValue}} attributeName:@"keyName" options:nil];
+ layer.lineWidth = functionStyleValue;
+
+ std::map<float, float> innerStops { {18, 0xff} };
+ mbgl::style::CompositeExponentialStops<float> compositeStops { { {10.0, innerStops} }, 1.0 };
+
+ propertyValue = mbgl::style::CompositeFunction<float> { "keyName", compositeStops };
+
+ XCTAssertEqual(rawLayer->getLineWidth(), propertyValue,
+ @"Setting lineWidth to a composite function should update line-width.");
+ XCTAssertEqualObjects(layer.lineWidth, functionStyleValue,
+ @"lineWidth should round-trip composite functions.");
layer.lineWidth = nil;
@@ -737,11 +760,6 @@
@"Unsetting lineWidth should return line-width to the default value.");
XCTAssertEqualObjects(layer.lineWidth, defaultStyleValue,
@"lineWidth should return the default value after being unset.");
-
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
- functionStyleValue = [MGLStyleValue<NSNumber *> valueWithInterpolationMode:MGLInterpolationModeInterval compositeStops:@{@18: constantStyleValue} attributeName:@"" options:nil];
- XCTAssertThrowsSpecificNamed(layer.lineWidth = functionStyleValue, NSException, NSInvalidArgumentException, @"MGLStyleValue should raise an exception if it is applied to a property that cannot support it");
// Transition property test
layer.lineWidthTransition = transitionTest;
auto toptions = rawLayer->getLineWidthTransition();
diff --git a/platform/darwin/test/MGLStyleTests.mm b/platform/darwin/test/MGLStyleTests.mm
index d93483ea6e..608cfdfd2d 100644
--- a/platform/darwin/test/MGLStyleTests.mm
+++ b/platform/darwin/test/MGLStyleTests.mm
@@ -210,9 +210,9 @@
MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
[self.style addSource:rasterSource];
- // Attempt to remove a shape source with the same identifier as the raster source
- MGLShapeSource *shapeSource = [[MGLShapeSource alloc] initWithIdentifier:@"some-identifier" shape:nil options:nil];
- [self.style removeSource:shapeSource];
+ // Attempt to remove an image source with the same identifier as the raster source
+ MGLImageSource *imageSource = [[MGLImageSource alloc] initWithIdentifier:@"some-identifier" coordinateQuad: { } URL:[NSURL URLWithString:@"http://host/image.png"]];
+ [self.style removeSource:imageSource];
// The raster source should still be added
XCTAssertTrue([[self.style sourceWithIdentifier:rasterSource.identifier] isMemberOfClass:[MGLRasterSource class]]);
@@ -220,16 +220,16 @@
[self.style removeSource:rasterSource];
// Add the shape source
- [self.style addSource:shapeSource];
+ [self.style addSource:imageSource];
// Attempt to remove a vector source with the same identifer as the shape source
MGLVectorSource *vectorSource = [[MGLVectorSource alloc] initWithIdentifier:@"some-identifier" tileURLTemplates:@[] options:nil];
[self.style removeSource:vectorSource];
- // The shape source should still be added
- XCTAssertTrue([[self.style sourceWithIdentifier:shapeSource.identifier] isMemberOfClass:[MGLShapeSource class]]);
+ // The image source should still be added
+ XCTAssertTrue([[self.style sourceWithIdentifier:imageSource.identifier] isMemberOfClass:[MGLImageSource class]]);
- // Remove the shape source
- [self.style removeSource:shapeSource];
+ // Remove the image source
+ [self.style removeSource:imageSource];
// Add the vector source
[self.style addSource:vectorSource];
@@ -237,7 +237,7 @@
// Attempt to remove the previously created raster source that has the same identifer as the shape source
[self.style removeSource:rasterSource];
// The vector source should still be added
- XCTAssertTrue([[self.style sourceWithIdentifier:shapeSource.identifier] isMemberOfClass:[MGLVectorSource class]]);
+ XCTAssertTrue([[self.style sourceWithIdentifier:imageSource.identifier] isMemberOfClass:[MGLVectorSource class]]);
}
- (void)testRemovingSourceInUse {
diff --git a/platform/darwin/test/Media.xcassets/RadarImage.imageset/Contents.json b/platform/darwin/test/Media.xcassets/RadarImage.imageset/Contents.json
new file mode 100644
index 0000000000..79be9ed970
--- /dev/null
+++ b/platform/darwin/test/Media.xcassets/RadarImage.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "radar.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/platform/darwin/test/Media.xcassets/RadarImage.imageset/radar.png b/platform/darwin/test/Media.xcassets/RadarImage.imageset/radar.png
new file mode 100644
index 0000000000..e23697f42a
--- /dev/null
+++ b/platform/darwin/test/Media.xcassets/RadarImage.imageset/radar.png
Binary files differ
diff --git a/platform/default/asset_file_source.cpp b/platform/default/asset_file_source.cpp
index 1832818378..343f3b70ce 100644
--- a/platform/default/asset_file_source.cpp
+++ b/platform/default/asset_file_source.cpp
@@ -1,4 +1,5 @@
#include <mbgl/storage/asset_file_source.hpp>
+#include <mbgl/storage/file_source_request.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/thread.hpp>
@@ -14,11 +15,11 @@ namespace mbgl {
class AssetFileSource::Impl {
public:
- Impl(std::string root_)
+ Impl(ActorRef<Impl>, std::string root_)
: root(std::move(root_)) {
}
- void request(const std::string& url, FileSource::Callback callback) {
+ void request(const std::string& url, ActorRef<FileSourceRequest> req) {
std::string path;
if (url.size() <= 8 || url[8] == '/') {
@@ -48,7 +49,7 @@ public:
}
}
- callback(response);
+ req.invoke(&FileSourceRequest::setResponse, response);
}
private:
@@ -56,15 +57,17 @@ private:
};
AssetFileSource::AssetFileSource(const std::string& root)
- : thread(std::make_unique<util::Thread<Impl>>(
- util::ThreadContext{"AssetFileSource", util::ThreadPriority::Low},
- root)) {
+ : impl(std::make_unique<util::Thread<Impl>>("AssetFileSource", root)) {
}
AssetFileSource::~AssetFileSource() = default;
std::unique_ptr<AsyncRequest> AssetFileSource::request(const Resource& resource, Callback callback) {
- return thread->invokeWithCallback(&Impl::request, resource.url, callback);
+ auto req = std::make_unique<FileSourceRequest>(std::move(callback));
+
+ impl->actor().invoke(&Impl::request, resource.url, req->actor());
+
+ return std::move(req);
}
} // namespace mbgl
diff --git a/platform/default/async_task.cpp b/platform/default/async_task.cpp
index 5fa9db8d33..50891056d8 100644
--- a/platform/default/async_task.cpp
+++ b/platform/default/async_task.cpp
@@ -16,7 +16,7 @@ public:
: async(new uv_async_t),
task(std::move(fn)) {
- uv_loop_t* loop = reinterpret_cast<uv_loop_t*>(RunLoop::getLoopHandle());
+ auto* loop = reinterpret_cast<uv_loop_t*>(RunLoop::getLoopHandle());
if (uv_async_init(loop, async, asyncCallback) != 0) {
throw std::runtime_error("Failed to initialize async.");
}
diff --git a/platform/default/bidi.cpp b/platform/default/bidi.cpp
index a76c4bcaac..d475c387b3 100644
--- a/platform/default/bidi.cpp
+++ b/platform/default/bidi.cpp
@@ -30,7 +30,7 @@ std::u16string applyArabicShaping(const std::u16string& input) {
UErrorCode errorCode = U_ZERO_ERROR;
const int32_t outputLength =
- u_shapeArabic(mbgl::utf16char_cast<const UChar*>(input.c_str()), static_cast<int32_t>(input.size()), NULL, 0,
+ u_shapeArabic(mbgl::utf16char_cast<const UChar*>(input.c_str()), static_cast<int32_t>(input.size()), nullptr, 0,
(U_SHAPE_LETTERS_SHAPE & U_SHAPE_LETTERS_MASK) |
(U_SHAPE_TEXT_DIRECTION_LOGICAL & U_SHAPE_TEXT_DIRECTION_MASK),
&errorCode);
@@ -57,7 +57,7 @@ void BiDi::mergeParagraphLineBreaks(std::set<size_t>& lineBreakPoints) {
for (int32_t i = 0; i < paragraphCount; i++) {
UErrorCode errorCode = U_ZERO_ERROR;
int32_t paragraphEndIndex;
- ubidi_getParagraphByIndex(impl->bidiText, i, NULL, &paragraphEndIndex, NULL, &errorCode);
+ ubidi_getParagraphByIndex(impl->bidiText, i, nullptr, &paragraphEndIndex, nullptr, &errorCode);
if (U_FAILURE(errorCode)) {
throw std::runtime_error(std::string("ProcessedBiDiText::mergeParagraphLineBreaks: ") +
@@ -92,7 +92,7 @@ std::vector<std::u16string> BiDi::processText(const std::u16string& input,
UErrorCode errorCode = U_ZERO_ERROR;
ubidi_setPara(impl->bidiText, mbgl::utf16char_cast<const UChar*>(input.c_str()), static_cast<int32_t>(input.size()),
- UBIDI_DEFAULT_LTR, NULL, &errorCode);
+ UBIDI_DEFAULT_LTR, nullptr, &errorCode);
if (U_FAILURE(errorCode)) {
throw std::runtime_error(std::string("BiDi::processText: ") + u_errorName(errorCode));
diff --git a/platform/default/default_file_source.cpp b/platform/default/default_file_source.cpp
index 7db0b85461..bf8d7b6348 100644
--- a/platform/default/default_file_source.cpp
+++ b/platform/default/default_file_source.cpp
@@ -1,9 +1,11 @@
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/asset_file_source.hpp>
+#include <mbgl/storage/file_source_request.hpp>
#include <mbgl/storage/local_file_source.hpp>
#include <mbgl/storage/online_file_source.hpp>
#include <mbgl/storage/offline_database.hpp>
#include <mbgl/storage/offline_download.hpp>
+#include <mbgl/storage/resource_transform.hpp>
#include <mbgl/util/platform.hpp>
#include <mbgl/util/url.hpp>
@@ -26,8 +28,10 @@ namespace mbgl {
class DefaultFileSource::Impl {
public:
- Impl(const std::string& cachePath, uint64_t maximumCacheSize)
- : offlineDatabase(cachePath, maximumCacheSize) {
+ Impl(ActorRef<Impl>, std::shared_ptr<FileSource> assetFileSource_, const std::string& cachePath, uint64_t maximumCacheSize)
+ : assetFileSource(assetFileSource_)
+ , localFileSource(std::make_unique<LocalFileSource>())
+ , offlineDatabase(cachePath, maximumCacheSize) {
}
void setAPIBaseURL(const std::string& url) {
@@ -46,7 +50,7 @@ public:
return onlineFileSource.getAccessToken();
}
- void setResourceTransform(OnlineFileSource::ResourceTransform&& transform) {
+ void setResourceTransform(optional<ActorRef<ResourceTransform>>&& transform) {
onlineFileSource.setResourceTransform(std::move(transform));
}
@@ -104,36 +108,50 @@ public:
getDownload(regionID).setState(state);
}
- void request(AsyncRequest* req, Resource resource, Callback callback) {
- Resource revalidation = resource;
-
- const bool hasPrior = resource.priorEtag || resource.priorModified || resource.priorExpires;
- if (!hasPrior || resource.necessity == Resource::Optional) {
- auto offlineResponse = offlineDatabase.get(resource);
-
- if (resource.necessity == Resource::Optional && !offlineResponse) {
- // Ensure there's always a response that we can send, so the caller knows that
- // there's no optional data available in the cache.
- offlineResponse.emplace();
- offlineResponse->noContent = true;
- offlineResponse->error = std::make_unique<Response::Error>(
- Response::Error::Reason::NotFound, "Not found in offline database");
+ void request(AsyncRequest* req, Resource resource, ActorRef<FileSourceRequest> ref) {
+ auto callback = [ref] (const Response& res) mutable {
+ ref.invoke(&FileSourceRequest::setResponse, res);
+ };
+
+ if (isAssetURL(resource.url)) {
+ //Asset request
+ tasks[req] = assetFileSource->request(resource, callback);
+ } else if (LocalFileSource::acceptsURL(resource.url)) {
+ //Local file request
+ tasks[req] = localFileSource->request(resource, callback);
+ } else {
+ // Try the offline database
+ Resource revalidation = resource;
+
+ const bool hasPrior = resource.priorEtag || resource.priorModified || resource.priorExpires;
+ if (!hasPrior || resource.necessity == Resource::Optional) {
+ auto offlineResponse = offlineDatabase.get(resource);
+
+ if (resource.necessity == Resource::Optional && !offlineResponse) {
+ // Ensure there's always a response that we can send, so the caller knows that
+ // there's no optional data available in the cache.
+ offlineResponse.emplace();
+ offlineResponse->noContent = true;
+ offlineResponse->error = std::make_unique<Response::Error>(
+ Response::Error::Reason::NotFound, "Not found in offline database");
+ }
+
+ if (offlineResponse) {
+ revalidation.priorModified = offlineResponse->modified;
+ revalidation.priorExpires = offlineResponse->expires;
+ revalidation.priorEtag = offlineResponse->etag;
+ callback(*offlineResponse);
+ }
}
- if (offlineResponse) {
- revalidation.priorModified = offlineResponse->modified;
- revalidation.priorExpires = offlineResponse->expires;
- revalidation.priorEtag = offlineResponse->etag;
- callback(*offlineResponse);
+ // Get from the online file source
+ if (resource.necessity == Resource::Required) {
+ tasks[req] = onlineFileSource.request(revalidation, [=] (Response onlineResponse) mutable {
+ this->offlineDatabase.put(revalidation, onlineResponse);
+ callback(onlineResponse);
+ });
}
}
-
- if (resource.necessity == Resource::Required) {
- tasks[req] = onlineFileSource.request(revalidation, [=] (Response onlineResponse) {
- this->offlineDatabase.put(revalidation, onlineResponse);
- callback(onlineResponse);
- });
- }
}
void cancel(AsyncRequest* req) {
@@ -158,6 +176,9 @@ private:
std::make_unique<OfflineDownload>(regionID, offlineDatabase.getRegionDefinition(regionID), offlineDatabase, onlineFileSource)).first->second;
}
+ // shared so that destruction is done on the creating thread
+ const std::shared_ptr<FileSource> assetFileSource;
+ const std::unique_ptr<FileSource> localFileSource;
OfflineDatabase offlineDatabase;
OnlineFileSource onlineFileSource;
std::unordered_map<AsyncRequest*, std::unique_ptr<AsyncRequest>> tasks;
@@ -173,118 +194,102 @@ DefaultFileSource::DefaultFileSource(const std::string& cachePath,
DefaultFileSource::DefaultFileSource(const std::string& cachePath,
std::unique_ptr<FileSource>&& assetFileSource_,
uint64_t maximumCacheSize)
- : thread(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"DefaultFileSource", util::ThreadPriority::Low},
- cachePath, maximumCacheSize)),
- assetFileSource(std::move(assetFileSource_)),
- localFileSource(std::make_unique<LocalFileSource>()) {
+ : assetFileSource(std::move(assetFileSource_))
+ , impl(std::make_unique<util::Thread<Impl>>("DefaultFileSource", assetFileSource, cachePath, maximumCacheSize)) {
}
DefaultFileSource::~DefaultFileSource() = default;
void DefaultFileSource::setAPIBaseURL(const std::string& baseURL) {
- thread->invoke(&Impl::setAPIBaseURL, baseURL);
- cachedBaseURL = baseURL;
+ impl->actor().invoke(&Impl::setAPIBaseURL, baseURL);
+
+ {
+ std::lock_guard<std::mutex> lock(cachedBaseURLMutex);
+ cachedBaseURL = baseURL;
+ }
}
-std::string DefaultFileSource::getAPIBaseURL() const {
+std::string DefaultFileSource::getAPIBaseURL() {
+ std::lock_guard<std::mutex> lock(cachedBaseURLMutex);
return cachedBaseURL;
}
void DefaultFileSource::setAccessToken(const std::string& accessToken) {
- thread->invoke(&Impl::setAccessToken, accessToken);
- cachedAccessToken = accessToken;
+ impl->actor().invoke(&Impl::setAccessToken, accessToken);
+
+ {
+ std::lock_guard<std::mutex> lock(cachedAccessTokenMutex);
+ cachedAccessToken = accessToken;
+ }
}
-std::string DefaultFileSource::getAccessToken() const {
+std::string DefaultFileSource::getAccessToken() {
+ std::lock_guard<std::mutex> lock(cachedAccessTokenMutex);
return cachedAccessToken;
}
-void DefaultFileSource::setResourceTransform(std::function<std::string(Resource::Kind, std::string&&)> transform) {
- if (transform) {
- auto loop = util::RunLoop::Get();
- thread->invoke(&Impl::setResourceTransform, [loop, transform](Resource::Kind kind_, std::string&& url_, auto callback_) {
- return loop->invokeWithCallback([transform](Resource::Kind kind, std::string&& url, auto callback) {
- callback(transform(kind, std::move(url)));
- }, kind_, std::move(url_), callback_);
- });
- } else {
- thread->invoke(&Impl::setResourceTransform, nullptr);
- }
+void DefaultFileSource::setResourceTransform(optional<ActorRef<ResourceTransform>>&& transform) {
+ impl->actor().invoke(&Impl::setResourceTransform, std::move(transform));
}
std::unique_ptr<AsyncRequest> DefaultFileSource::request(const Resource& resource, Callback callback) {
- class DefaultFileRequest : public AsyncRequest {
- public:
- DefaultFileRequest(Resource resource_, FileSource::Callback callback_, util::Thread<DefaultFileSource::Impl>& thread_)
- : thread(thread_),
- workRequest(thread.invokeWithCallback(&DefaultFileSource::Impl::request, this, resource_, callback_)) {
- }
+ auto req = std::make_unique<FileSourceRequest>(std::move(callback));
- ~DefaultFileRequest() override {
- thread.invoke(&DefaultFileSource::Impl::cancel, this);
- }
+ req->onCancel([fs = impl->actor(), req = req.get()] () mutable { fs.invoke(&Impl::cancel, req); });
- util::Thread<DefaultFileSource::Impl>& thread;
- std::unique_ptr<AsyncRequest> workRequest;
- };
+ impl->actor().invoke(&Impl::request, req.get(), resource, req->actor());
- if (isAssetURL(resource.url)) {
- return assetFileSource->request(resource, callback);
- } else if (LocalFileSource::acceptsURL(resource.url)) {
- return localFileSource->request(resource, callback);
- } else {
- return std::make_unique<DefaultFileRequest>(resource, callback, *thread);
- }
+ return std::move(req);
}
void DefaultFileSource::listOfflineRegions(std::function<void (std::exception_ptr, optional<std::vector<OfflineRegion>>)> callback) {
- thread->invoke(&Impl::listRegions, callback);
+ impl->actor().invoke(&Impl::listRegions, callback);
}
void DefaultFileSource::createOfflineRegion(const OfflineRegionDefinition& definition,
const OfflineRegionMetadata& metadata,
std::function<void (std::exception_ptr, optional<OfflineRegion>)> callback) {
- thread->invoke(&Impl::createRegion, definition, metadata, callback);
+ impl->actor().invoke(&Impl::createRegion, definition, metadata, callback);
}
void DefaultFileSource::updateOfflineMetadata(const int64_t regionID,
const OfflineRegionMetadata& metadata,
std::function<void (std::exception_ptr, optional<OfflineRegionMetadata>)> callback) {
- thread->invoke(&Impl::updateMetadata, regionID, metadata, callback);
+ impl->actor().invoke(&Impl::updateMetadata, regionID, metadata, callback);
}
void DefaultFileSource::deleteOfflineRegion(OfflineRegion&& region, std::function<void (std::exception_ptr)> callback) {
- thread->invoke(&Impl::deleteRegion, std::move(region), callback);
+ impl->actor().invoke(&Impl::deleteRegion, std::move(region), callback);
}
void DefaultFileSource::setOfflineRegionObserver(OfflineRegion& region, std::unique_ptr<OfflineRegionObserver> observer) {
- thread->invoke(&Impl::setRegionObserver, region.getID(), std::move(observer));
+ impl->actor().invoke(&Impl::setRegionObserver, region.getID(), std::move(observer));
}
void DefaultFileSource::setOfflineRegionDownloadState(OfflineRegion& region, OfflineRegionDownloadState state) {
- thread->invoke(&Impl::setRegionDownloadState, region.getID(), state);
+ impl->actor().invoke(&Impl::setRegionDownloadState, region.getID(), state);
}
void DefaultFileSource::getOfflineRegionStatus(OfflineRegion& region, std::function<void (std::exception_ptr, optional<OfflineRegionStatus>)> callback) const {
- thread->invoke(&Impl::getRegionStatus, region.getID(), callback);
+ impl->actor().invoke(&Impl::getRegionStatus, region.getID(), callback);
}
void DefaultFileSource::setOfflineMapboxTileCountLimit(uint64_t limit) const {
- thread->invokeSync(&Impl::setOfflineMapboxTileCountLimit, limit);
+ impl->actor().invoke(&Impl::setOfflineMapboxTileCountLimit, limit);
}
void DefaultFileSource::pause() {
- thread->pause();
+ impl->pause();
}
void DefaultFileSource::resume() {
- thread->resume();
+ impl->resume();
}
// For testing only:
void DefaultFileSource::put(const Resource& resource, const Response& response) {
- thread->invokeSync(&Impl::put, resource, response);
+ impl->actor().invoke(&Impl::put, resource, response);
}
} // namespace mbgl
diff --git a/platform/default/image.cpp b/platform/default/image.cpp
index ad9d83a08d..447c6bcd66 100644
--- a/platform/default/image.cpp
+++ b/platform/default/image.cpp
@@ -12,7 +12,7 @@ PremultipliedImage decodePNG(const uint8_t*, size_t);
PremultipliedImage decodeJPEG(const uint8_t*, size_t);
PremultipliedImage decodeImage(const std::string& string) {
- const uint8_t* data = reinterpret_cast<const uint8_t*>(string.data());
+ const auto* data = reinterpret_cast<const uint8_t*>(string.data());
const size_t size = string.size();
#if !defined(__ANDROID__) && !defined(__APPLE__)
diff --git a/platform/default/jpeg_reader.cpp b/platform/default/jpeg_reader.cpp
index c5e9d880c0..5f613f9423 100644
--- a/platform/default/jpeg_reader.cpp
+++ b/platform/default/jpeg_reader.cpp
@@ -21,12 +21,12 @@ struct jpeg_stream_wrapper {
};
static void init_source(j_decompress_ptr cinfo) {
- jpeg_stream_wrapper* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
+ auto* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
wrap->stream->seekg(0, std::ios_base::beg);
}
static boolean fill_input_buffer(j_decompress_ptr cinfo) {
- jpeg_stream_wrapper* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
+ auto* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
wrap->stream->read(reinterpret_cast<char*>(&wrap->buffer[0]), BUF_SIZE);
std::streamsize size = wrap->stream->gcount();
wrap->manager.next_input_byte = wrap->buffer.data();
@@ -36,7 +36,7 @@ static boolean fill_input_buffer(j_decompress_ptr cinfo) {
static void skip(j_decompress_ptr cinfo, long count) {
if (count <= 0) return; // A zero or negative skip count should be treated as a no-op.
- jpeg_stream_wrapper* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
+ auto* wrap = reinterpret_cast<jpeg_stream_wrapper*>(cinfo->src);
if (wrap->manager.bytes_in_buffer > 0 && count < static_cast<long>(wrap->manager.bytes_in_buffer))
{
@@ -59,7 +59,7 @@ static void attach_stream(j_decompress_ptr cinfo, std::istream* in) {
cinfo->src = (struct jpeg_source_mgr *)
(*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(jpeg_stream_wrapper));
}
- jpeg_stream_wrapper * src = reinterpret_cast<jpeg_stream_wrapper*> (cinfo->src);
+ auto * src = reinterpret_cast<jpeg_stream_wrapper*> (cinfo->src);
src->manager.init_source = init_source;
src->manager.fill_input_buffer = fill_input_buffer;
src->manager.skip_input_data = skip;
diff --git a/platform/default/local_file_source.cpp b/platform/default/local_file_source.cpp
index 93b42f5fa0..21a291d8d4 100644
--- a/platform/default/local_file_source.cpp
+++ b/platform/default/local_file_source.cpp
@@ -1,4 +1,5 @@
#include <mbgl/storage/local_file_source.hpp>
+#include <mbgl/storage/file_source_request.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/string.hpp>
#include <mbgl/util/thread.hpp>
@@ -21,7 +22,9 @@ namespace mbgl {
class LocalFileSource::Impl {
public:
- void request(const std::string& url, FileSource::Callback callback) {
+ Impl(ActorRef<Impl>) {}
+
+ void request(const std::string& url, ActorRef<FileSourceRequest> req) {
// Cut off the protocol
std::string path = mbgl::util::percentDecode(url.substr(protocolLength));
@@ -44,19 +47,23 @@ public:
}
}
- callback(response);
+ req.invoke(&FileSourceRequest::setResponse, response);
}
};
LocalFileSource::LocalFileSource()
- : thread(std::make_unique<util::Thread<Impl>>(util::ThreadContext{"LocalFileSource", util::ThreadPriority::Low})) {
+ : impl(std::make_unique<util::Thread<Impl>>("LocalFileSource")) {
}
LocalFileSource::~LocalFileSource() = default;
std::unique_ptr<AsyncRequest> LocalFileSource::request(const Resource& resource, Callback callback) {
- return thread->invokeWithCallback(&Impl::request, resource.url, callback);
+ auto req = std::make_unique<FileSourceRequest>(std::move(callback));
+
+ impl->actor().invoke(&Impl::request, resource.url, req->actor());
+
+ return std::move(req);
}
bool LocalFileSource::acceptsURL(const std::string& url) {
diff --git a/platform/default/mbgl/gl/headless_backend.cpp b/platform/default/mbgl/gl/headless_backend.cpp
index d2fbf4e4c7..df3a517823 100644
--- a/platform/default/mbgl/gl/headless_backend.cpp
+++ b/platform/default/mbgl/gl/headless_backend.cpp
@@ -9,8 +9,7 @@
namespace mbgl {
-HeadlessBackend::HeadlessBackend() {
-}
+HeadlessBackend::HeadlessBackend() = default;
HeadlessBackend::HeadlessBackend(std::shared_ptr<HeadlessDisplay> display_)
: display(std::move(display_)) {
diff --git a/platform/default/mbgl/gl/headless_backend.hpp b/platform/default/mbgl/gl/headless_backend.hpp
index 128b579bd2..26033acf82 100644
--- a/platform/default/mbgl/gl/headless_backend.hpp
+++ b/platform/default/mbgl/gl/headless_backend.hpp
@@ -20,7 +20,7 @@ public:
void invalidate() override;
struct Impl {
- virtual ~Impl() {}
+ virtual ~Impl() = default;
virtual void activateContext() = 0;
virtual void deactivateContext() {}
};
diff --git a/platform/default/mbgl/gl/offscreen_view.cpp b/platform/default/mbgl/gl/offscreen_view.cpp
index 5424e03c96..e7cf7cffe5 100644
--- a/platform/default/mbgl/gl/offscreen_view.cpp
+++ b/platform/default/mbgl/gl/offscreen_view.cpp
@@ -24,6 +24,7 @@ public:
context.bindFramebuffer = framebuffer->framebuffer;
}
+ context.scissorTest = false;
context.viewport = { 0, 0, size };
}
diff --git a/platform/default/mbgl/gl/offscreen_view.hpp b/platform/default/mbgl/gl/offscreen_view.hpp
index bf1a9889cd..eb888272e5 100644
--- a/platform/default/mbgl/gl/offscreen_view.hpp
+++ b/platform/default/mbgl/gl/offscreen_view.hpp
@@ -12,7 +12,7 @@ class Context;
class OffscreenView : public View {
public:
OffscreenView(gl::Context&, Size size = { 256, 256 });
- ~OffscreenView();
+ ~OffscreenView() override;
void bind() override;
diff --git a/platform/default/mbgl/storage/offline_download.cpp b/platform/default/mbgl/storage/offline_download.cpp
index 901f996a4f..7f0001f64b 100644
--- a/platform/default/mbgl/storage/offline_download.cpp
+++ b/platform/default/mbgl/storage/offline_download.cpp
@@ -5,8 +5,10 @@
#include <mbgl/storage/response.hpp>
#include <mbgl/storage/http_file_source.hpp>
#include <mbgl/style/parser.hpp>
-#include <mbgl/style/sources/geojson_source_impl.hpp>
-#include <mbgl/style/tile_source_impl.hpp>
+#include <mbgl/style/sources/vector_source.hpp>
+#include <mbgl/style/sources/raster_source.hpp>
+#include <mbgl/style/sources/geojson_source.hpp>
+#include <mbgl/style/sources/image_source.hpp>
#include <mbgl/style/conversion/json.hpp>
#include <mbgl/style/conversion/tileset.hpp>
#include <mbgl/text/glyph.hpp>
@@ -19,6 +21,8 @@
namespace mbgl {
+using namespace style;
+
OfflineDownload::OfflineDownload(int64_t id_,
OfflineRegionDefinition&& definition_,
OfflineDatabase& offlineDatabase_,
@@ -71,22 +75,15 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
result.requiredResourceCountIsPrecise = true;
for (const auto& source : parser.sources) {
- SourceType type = source->baseImpl->type;
-
- switch (type) {
- case SourceType::Vector:
- case SourceType::Raster: {
- style::TileSourceImpl* tileSource =
- static_cast<style::TileSourceImpl*>(source->baseImpl.get());
- const variant<std::string, Tileset>& urlOrTileset = tileSource->getURLOrTileset();
- const uint16_t tileSize = tileSource->getTileSize();
+ SourceType type = source->getType();
+ auto handleTiledSource = [&] (const variant<std::string, Tileset>& urlOrTileset, const uint16_t tileSize) {
if (urlOrTileset.is<Tileset>()) {
result.requiredResourceCount +=
definition.tileCover(type, tileSize, urlOrTileset.get<Tileset>().zoomRange).size();
} else {
result.requiredResourceCount += 1;
- const std::string& url = urlOrTileset.get<std::string>();
+ const auto& url = urlOrTileset.get<std::string>();
optional<Response> sourceResponse = offlineDatabase.get(Resource::source(url));
if (sourceResponse) {
style::conversion::Error error;
@@ -99,12 +96,32 @@ OfflineRegionStatus OfflineDownload::getStatus() const {
result.requiredResourceCountIsPrecise = false;
}
}
+ };
+
+ switch (type) {
+ case SourceType::Vector: {
+ const auto& vectorSource = *source->as<VectorSource>();
+ handleTiledSource(vectorSource.getURLOrTileset(), util::tileSize);
+ break;
+ }
+
+ case SourceType::Raster: {
+ const auto& rasterSource = *source->as<RasterSource>();
+ handleTiledSource(rasterSource.getURLOrTileset(), rasterSource.getTileSize());
break;
}
case SourceType::GeoJSON: {
- style::GeoJSONSource* geojsonSource = source->as<style::GeoJSONSource>();
- if (geojsonSource->getURL()) {
+ const auto& geojsonSource = *source->as<GeoJSONSource>();
+ if (geojsonSource.getURL()) {
+ result.requiredResourceCount += 1;
+ }
+ break;
+ }
+
+ case SourceType::Image: {
+ const auto& imageSource = *source->as<ImageSource>();
+ if (imageSource.getURL()) {
result.requiredResourceCount += 1;
}
break;
@@ -138,20 +155,13 @@ void OfflineDownload::activateDownload() {
parser.parse(*styleResponse.data);
for (const auto& source : parser.sources) {
- SourceType type = source->baseImpl->type;
-
- switch (type) {
- case SourceType::Vector:
- case SourceType::Raster: {
- const style::TileSourceImpl* tileSource =
- static_cast<style::TileSourceImpl*>(source->baseImpl.get());
- const variant<std::string, Tileset>& urlOrTileset = tileSource->getURLOrTileset();
- const uint16_t tileSize = tileSource->getTileSize();
+ SourceType type = source->getType();
+ auto handleTiledSource = [&] (const variant<std::string, Tileset>& urlOrTileset, const uint16_t tileSize) {
if (urlOrTileset.is<Tileset>()) {
queueTiles(type, tileSize, urlOrTileset.get<Tileset>());
} else {
- const std::string& url = urlOrTileset.get<std::string>();
+ const auto& url = urlOrTileset.get<std::string>();
status.requiredResourceCountIsPrecise = false;
status.requiredResourceCount++;
requiredSourceURLs.insert(url);
@@ -170,15 +180,34 @@ void OfflineDownload::activateDownload() {
}
});
}
+ };
+
+ switch (type) {
+ case SourceType::Vector: {
+ const auto& vectorSource = *source->as<VectorSource>();
+ handleTiledSource(vectorSource.getURLOrTileset(), util::tileSize);
+ break;
+ }
+
+ case SourceType::Raster: {
+ const auto& rasterSource = *source->as<RasterSource>();
+ handleTiledSource(rasterSource.getURLOrTileset(), rasterSource.getTileSize());
break;
}
case SourceType::GeoJSON: {
- style::GeoJSONSource::Impl* geojsonSource =
- static_cast<style::GeoJSONSource::Impl*>(source->baseImpl.get());
+ const auto& geojsonSource = *source->as<GeoJSONSource>();
+ if (geojsonSource.getURL()) {
+ queueResource(Resource::source(*geojsonSource.getURL()));
+ }
+ break;
+ }
- if (geojsonSource->getURL()) {
- queueResource(Resource::source(*geojsonSource->getURL()));
+ case SourceType::Image: {
+ const auto& imageSource = *source->as<ImageSource>();
+ auto imageUrl = imageSource.getURL();
+ if (imageUrl && !imageUrl->empty()) {
+ queueResource(Resource::image(*imageUrl));
}
break;
}
diff --git a/platform/default/online_file_source.cpp b/platform/default/online_file_source.cpp
index a72b6f4efc..f10e0f8ffb 100644
--- a/platform/default/online_file_source.cpp
+++ b/platform/default/online_file_source.cpp
@@ -2,16 +2,18 @@
#include <mbgl/storage/http_file_source.hpp>
#include <mbgl/storage/network_status.hpp>
+#include <mbgl/storage/resource_transform.hpp>
#include <mbgl/storage/response.hpp>
#include <mbgl/util/logging.hpp>
+#include <mbgl/actor/mailbox.hpp>
#include <mbgl/util/constants.hpp>
-#include <mbgl/util/thread.hpp>
#include <mbgl/util/mapbox.hpp>
#include <mbgl/util/exception.hpp>
#include <mbgl/util/chrono.hpp>
#include <mbgl/util/async_task.hpp>
#include <mbgl/util/noncopyable.hpp>
+#include <mbgl/util/run_loop.hpp>
#include <mbgl/util/timer.hpp>
#include <mbgl/util/http_timeout.hpp>
@@ -35,12 +37,17 @@ public:
void schedule(optional<Timestamp> expires);
void completed(Response);
+ void setTransformedURL(const std::string&& url);
+ ActorRef<OnlineFileRequest> actor();
+
OnlineFileSource::Impl& impl;
Resource resource;
std::unique_ptr<AsyncRequest> request;
util::Timer timer;
Callback callback;
+ std::shared_ptr<Mailbox> mailbox;
+
// Counts the number of times a response was already expired when received. We're using
// this to add a delay when making a new request so we don't keep retrying immediately
// in case of a server serving expired tiles.
@@ -66,15 +73,12 @@ public:
void add(OnlineFileRequest* request) {
allRequests.insert(request);
if (resourceTransform) {
- // When there's a Resource transform callback set, replace the resource with the
+ // Request the ResourceTransform actor a new url and replace the resource url with the
// transformed one before proceeding to schedule the request.
- request->request =
- resourceTransform(request->resource.kind, std::move(request->resource.url),
- [request](std::string&& url) {
- request->request.release();
- request->resource.url = std::move(url);
- request->schedule();
- });
+ resourceTransform->invoke(&ResourceTransform::transform, request->resource.kind,
+ std::move(request->resource.url), [ref = request->actor()](const std::string&& url) mutable {
+ ref.invoke(&OnlineFileRequest::setTransformedURL, std::move(url));
+ });
} else {
request->schedule();
}
@@ -145,7 +149,7 @@ public:
return activeRequests.find(request) != activeRequests.end();
}
- void setResourceTransform(ResourceTransform&& transform) {
+ void setResourceTransform(optional<ActorRef<ResourceTransform>>&& transform) {
resourceTransform = std::move(transform);
}
@@ -156,7 +160,7 @@ private:
}
}
- ResourceTransform resourceTransform;
+ optional<ActorRef<ResourceTransform>> resourceTransform;
/**
* The lifetime of a request is:
@@ -189,6 +193,7 @@ std::unique_ptr<AsyncRequest> OnlineFileSource::request(const Resource& resource
switch (resource.kind) {
case Resource::Kind::Unknown:
+ case Resource::Kind::Image:
break;
case Resource::Kind::Style:
@@ -216,7 +221,7 @@ std::unique_ptr<AsyncRequest> OnlineFileSource::request(const Resource& resource
return std::make_unique<OnlineFileRequest>(std::move(res), std::move(callback), *impl);
}
-void OnlineFileSource::setResourceTransform(ResourceTransform&& transform) {
+void OnlineFileSource::setResourceTransform(optional<ActorRef<ResourceTransform>>&& transform) {
impl->setResourceTransform(std::move(transform));
}
@@ -361,4 +366,19 @@ void OnlineFileRequest::networkIsReachableAgain() {
}
}
+void OnlineFileRequest::setTransformedURL(const std::string&& url) {
+ resource.url = std::move(url);
+ schedule();
+}
+
+ActorRef<OnlineFileRequest> OnlineFileRequest::actor() {
+ if (!mailbox) {
+ // Lazy constructed because this can be costly and
+ // the ResourceTransform is not used by many apps.
+ mailbox = std::make_shared<Mailbox>(*util::RunLoop::Get());
+ }
+
+ return ActorRef<OnlineFileRequest>(*this, mailbox);
+}
+
} // namespace mbgl
diff --git a/platform/default/png_reader.cpp b/platform/default/png_reader.cpp
index 29ef3058e1..4d4ee29d1f 100644
--- a/platform/default/png_reader.cpp
+++ b/platform/default/png_reader.cpp
@@ -40,7 +40,7 @@ static void user_warning_fn(png_structp, png_const_charp warning_msg) {
}
static void png_read_data(png_structp png_ptr, png_bytep data, png_size_t length) {
- std::istream* fin = reinterpret_cast<std::istream*>(png_get_io_ptr(png_ptr));
+ auto* fin = reinterpret_cast<std::istream*>(png_get_io_ptr(png_ptr));
fin->read(reinterpret_cast<char*>(data), length);
std::streamsize read_count = fin->gcount();
if (read_count < 0 || static_cast<png_size_t>(read_count) != length)
diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp
index 304d5e9aba..0707f9255c 100644
--- a/platform/default/sqlite3.cpp
+++ b/platform/default/sqlite3.cpp
@@ -107,8 +107,7 @@ Database &Database::operator=(Database &&other) {
return *this;
}
-Database::~Database() {
-}
+Database::~Database() = default;
void Database::setBusyTimeout(std::chrono::milliseconds timeout) {
assert(impl);
@@ -151,8 +150,7 @@ Statement &Statement::operator=(Statement &&other) {
return *this;
}
-Statement::~Statement() {
-}
+Statement::~Statement() = default;
template <> void Statement::bind(int offset, std::nullptr_t) {
assert(impl);
@@ -314,7 +312,7 @@ template <> std::string Statement::get(int offset) {
template <> std::vector<uint8_t> Statement::get(int offset) {
assert(impl);
- const uint8_t* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(impl->stmt, offset));
+ const auto* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(impl->stmt, offset));
const uint8_t* end = begin + sqlite3_column_bytes(impl->stmt, offset);
return { begin, end };
}
diff --git a/platform/default/timer.cpp b/platform/default/timer.cpp
index cd0e6da6aa..90a85bfc1f 100644
--- a/platform/default/timer.cpp
+++ b/platform/default/timer.cpp
@@ -10,7 +10,7 @@ namespace util {
class Timer::Impl {
public:
Impl() : timer(new uv_timer_t) {
- uv_loop_t* loop = reinterpret_cast<uv_loop_t*>(RunLoop::getLoopHandle());
+ auto* loop = reinterpret_cast<uv_loop_t*>(RunLoop::getLoopHandle());
if (uv_timer_init(loop, timer) != 0) {
throw std::runtime_error("Failed to initialize timer.");
}
diff --git a/platform/glfw/glfw_view.cpp b/platform/glfw/glfw_view.cpp
index 31b0b92c58..1beaf2b52b 100644
--- a/platform/glfw/glfw_view.cpp
+++ b/platform/glfw/glfw_view.cpp
@@ -1,8 +1,11 @@
#include "glfw_view.hpp"
+#include "ny_route.hpp"
#include <mbgl/annotation/annotation.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/style/transition_options.hpp>
+#include <mbgl/style/layers/fill_extrusion_layer.hpp>
#include <mbgl/util/logging.hpp>
#include <mbgl/util/platform.hpp>
#include <mbgl/util/string.hpp>
@@ -10,6 +13,10 @@
#include <mbgl/map/backend_scope.hpp>
#include <mbgl/map/camera.hpp>
+#include <mapbox/cheap_ruler.hpp>
+#include <mapbox/geometry.hpp>
+#include <mapbox/geojson.hpp>
+
#if MBGL_USE_GLES2
#define GLFW_INCLUDE_ES2
#endif // MBGL_USE_GLES2
@@ -99,7 +106,8 @@ GLFWView::GLFWView(bool fullscreen_, bool benchmark_)
printf("- Press `S` to cycle through bundled styles\n");
printf("- Press `X` to reset the transform\n");
printf("- Press `N` to reset north\n");
- printf("- Press `R` to toggle any available `night` style class\n");
+ printf("- Press `R` to enable the route demo\n");
+ printf("- Press `E` to insert an example building extrusion layer\n");
printf("- Press `Z` to cycle through north orientations\n");
printf("- Prezz `X` to cycle through the viewport modes\n");
printf("- Press `A` to cycle through Mapbox offices in the world + dateline monument\n");
@@ -131,23 +139,26 @@ GLFWView::~GLFWView() {
void GLFWView::setMap(mbgl::Map *map_) {
map = map_;
- map->addAnnotationImage("default_marker", makeImage(22, 22, 1));
+ map->addAnnotationImage(makeImage("default_marker", 22, 22, 1));
}
void GLFWView::updateAssumedState() {
assumeFramebufferBinding(0);
- assumeViewportSize(getFramebufferSize());
+ assumeViewport(0, 0, getFramebufferSize());
}
void GLFWView::bind() {
setFramebufferBinding(0);
- setViewportSize(getFramebufferSize());
+ setViewport(0, 0, getFramebufferSize());
}
void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action, int mods) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
if (action == GLFW_RELEASE) {
+ if (key != GLFW_KEY_R || key != GLFW_KEY_S)
+ view->animateRouteCallback = nullptr;
+
switch (key) {
case GLFW_KEY_ESCAPE:
glfwSetWindowShouldClose(window, true);
@@ -163,17 +174,6 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
if (view->changeStyleCallback)
view->changeStyleCallback();
break;
- case GLFW_KEY_R:
- if (!mods) {
- static const mbgl::style::TransitionOptions transition { { mbgl::Milliseconds(300) } };
- view->map->setTransitionOptions(transition);
- if (view->map->hasClass("night")) {
- view->map->removeClass("night");
- } else {
- view->map->addClass("night");
- }
- }
- break;
#if not MBGL_USE_GLES2
case GLFW_KEY_B: {
auto debug = view->map->getDebug();
@@ -231,6 +231,37 @@ void GLFWView::onKey(GLFWwindow *window, int key, int /*scancode*/, int action,
view->map->flyTo(cameraOptions, animationOptions);
nextPlace = nextPlace % places.size();
} break;
+ case GLFW_KEY_R: {
+ view->show3DExtrusions = true;
+ view->toggle3DExtrusions(view->show3DExtrusions);
+ if (view->animateRouteCallback) break;
+ view->animateRouteCallback = [](mbgl::Map* routeMap) {
+ static mapbox::cheap_ruler::CheapRuler ruler { 40.7 }; // New York
+ static mapbox::geojson::geojson route { mapbox::geojson::parse(mbgl::platform::glfw::route) };
+ const auto& geometry = route.get<mapbox::geometry::geometry<double>>();
+ const auto& lineString = geometry.get<mapbox::geometry::line_string<double>>();
+
+ static double routeDistance = ruler.lineDistance(lineString);
+ static double routeProgress = 0;
+ routeProgress += 0.0005;
+ if (routeProgress > 1.0) routeProgress = 0;
+
+ double distance = routeProgress * routeDistance;
+ auto point = ruler.along(lineString, distance);
+ auto latLng = routeMap->getLatLng();
+ routeMap->setLatLng({ point.y, point.x });
+ double bearing = ruler.bearing({ latLng.longitude(), latLng.latitude() }, point);
+ double easing = bearing - routeMap->getBearing();
+ easing += easing > 180.0 ? -360.0 : easing < -180 ? 360.0 : 0;
+ routeMap->setBearing(routeMap->getBearing() + (easing / 20));
+ routeMap->setPitch(60.0);
+ routeMap->setZoom(18.0);
+ };
+ view->animateRouteCallback(view->map);
+ } break;
+ case GLFW_KEY_E:
+ view->toggle3DExtrusions(!view->show3DExtrusions);
+ break;
}
}
@@ -266,7 +297,7 @@ mbgl::Point<double> GLFWView::makeRandomPoint() const {
}
std::unique_ptr<mbgl::style::Image>
-GLFWView::makeImage(int width, int height, float pixelRatio) {
+GLFWView::makeImage(const std::string& id, int width, int height, float pixelRatio) {
const int r = 255 * (double(std::rand()) / RAND_MAX);
const int g = 255 * (double(std::rand()) / RAND_MAX);
const int b = 255 * (double(std::rand()) / RAND_MAX);
@@ -291,7 +322,7 @@ GLFWView::makeImage(int width, int height, float pixelRatio) {
}
}
- return std::make_unique<mbgl::style::Image>(std::move(image), pixelRatio);
+ return std::make_unique<mbgl::style::Image>(id, std::move(image), pixelRatio);
}
void GLFWView::nextOrientation() {
@@ -308,7 +339,7 @@ void GLFWView::addRandomCustomPointAnnotations(int count) {
for (int i = 0; i < count; i++) {
static int spriteID = 1;
const auto name = std::string{ "marker-" } + mbgl::util::toString(spriteID++);
- map->addAnnotationImage(name, makeImage(22, 22, 1));
+ map->addAnnotationImage(makeImage(name, 22, 22, 1));
spriteIDs.push_back(name);
annotationIDs.push_back(map->addAnnotation(mbgl::SymbolAnnotation { makeRandomPoint(), name }));
}
@@ -356,7 +387,7 @@ void GLFWView::popAnnotation() {
}
void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
double delta = yOffset * 40;
bool isWheel = delta != 0 && std::fmod(delta, 4.000244140625) == 0;
@@ -378,16 +409,18 @@ void GLFWView::onScroll(GLFWwindow *window, double /*xOffset*/, double yOffset)
}
void GLFWView::onWindowResize(GLFWwindow *window, int width, int height) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
view->width = width;
view->height = height;
view->map->setSize({ static_cast<uint32_t>(view->width), static_cast<uint32_t>(view->height) });
}
void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
view->fbWidth = width;
view->fbHeight = height;
+
+ mbgl::BackendScope scope { *view, mbgl::BackendScope::ScopeType::Implicit };
view->bind();
// This is only triggered when the framebuffer is resized, but not the window. It can
@@ -398,7 +431,7 @@ void GLFWView::onFramebufferResize(GLFWwindow *window, int width, int height) {
}
void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modifiers) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
if (button == GLFW_MOUSE_BUTTON_RIGHT ||
(button == GLFW_MOUSE_BUTTON_LEFT && modifiers & GLFW_MOD_CONTROL)) {
@@ -426,7 +459,7 @@ void GLFWView::onMouseClick(GLFWwindow *window, int button, int action, int modi
}
void GLFWView::onMouseMove(GLFWwindow *window, double x, double y) {
- GLFWView *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
+ auto *view = reinterpret_cast<GLFWView *>(glfwGetWindowUserPointer(window));
if (view->tracking) {
double dx = x - view->lastX;
double dy = y - view->lastY;
@@ -459,6 +492,9 @@ void GLFWView::run() {
if (dirty) {
const double started = glfwGetTime();
+ if (animateRouteCallback)
+ animateRouteCallback(map);
+
activate();
mbgl::BackendScope scope { *this, mbgl::BackendScope::ScopeType::Implicit };
@@ -540,6 +576,51 @@ void GLFWView::setWindowTitle(const std::string& title) {
glfwSetWindowTitle(window, (std::string { "Mapbox GL: " } + title).c_str());
}
+void GLFWView::onDidFinishLoadingStyle() {
+ if (show3DExtrusions) {
+ toggle3DExtrusions(show3DExtrusions);
+ }
+}
+
+void GLFWView::toggle3DExtrusions(bool visible) {
+ show3DExtrusions = visible;
+
+ // Satellite-only style does not contain building extrusions data.
+ if (!map->getStyle().getSource("composite")) {
+ return;
+ }
+
+ if (auto layer = map->getStyle().getLayer("3d-buildings")) {
+ layer->setVisibility(mbgl::style::VisibilityType(!show3DExtrusions));
+ return;
+ }
+
+ auto extrusionLayer = std::make_unique<mbgl::style::FillExtrusionLayer>("3d-buildings", "composite");
+ extrusionLayer->setSourceLayer("building");
+ extrusionLayer->setMinZoom(15.0f);
+ extrusionLayer->setFilter(mbgl::style::EqualsFilter { "extrude", { std::string("true") } });
+
+ auto colorFn = mbgl::style::SourceFunction<mbgl::Color> { "height",
+ mbgl::style::ExponentialStops<mbgl::Color> {
+ std::map<float, mbgl::Color> {
+ { 0.f, *mbgl::Color::parse("#160e23") },
+ { 50.f, *mbgl::Color::parse("#00615f") },
+ { 100.f, *mbgl::Color::parse("#55e9ff") }
+ }
+ }
+ };
+ extrusionLayer->setFillExtrusionColor({ colorFn });
+ extrusionLayer->setFillExtrusionOpacity({ 0.6f });
+
+ auto heightSourceFn = mbgl::style::SourceFunction<float> { "height", mbgl::style::IdentityStops<float>() };
+ extrusionLayer->setFillExtrusionHeight({ heightSourceFn });
+
+ auto baseSourceFn = mbgl::style::SourceFunction<float> { "min_height", mbgl::style::IdentityStops<float>() };
+ extrusionLayer->setFillExtrusionBase({ baseSourceFn });
+
+ map->getStyle().addLayer(std::move(extrusionLayer));
+}
+
namespace mbgl {
namespace platform {
diff --git a/platform/glfw/glfw_view.hpp b/platform/glfw/glfw_view.hpp
index 77f4f64b01..366fe4fd68 100644
--- a/platform/glfw/glfw_view.hpp
+++ b/platform/glfw/glfw_view.hpp
@@ -41,6 +41,9 @@ public:
void invalidate() override;
void updateAssumedState() override;
+ // mbgl::MapObserver implementation
+ void onDidFinishLoadingStyle() override;
+
protected:
// mbgl::Backend implementation
mbgl::gl::ProcAddress initializeExtension(const char*) override;
@@ -61,7 +64,7 @@ private:
mbgl::Color makeRandomColor() const;
mbgl::Point<double> makeRandomPoint() const;
- static std::unique_ptr<mbgl::style::Image> makeImage(int width, int height, float pixelRatio);
+ static std::unique_ptr<mbgl::style::Image> makeImage(const std::string& id, int width, int height, float pixelRatio);
void nextOrientation();
@@ -77,6 +80,8 @@ private:
std::vector<std::string> spriteIDs;
private:
+ void toggle3DExtrusions(bool visible);
+
mbgl::Map* map = nullptr;
bool fullscreen = false;
@@ -84,6 +89,7 @@ private:
bool tracking = false;
bool rotating = false;
bool pitching = false;
+ bool show3DExtrusions = false;
// Frame timer
int frames = 0;
@@ -102,6 +108,7 @@ private:
std::function<void()> changeStyleCallback;
std::function<void()> pauseResumeCallback;
+ std::function<void(mbgl::Map*)> animateRouteCallback;
mbgl::util::RunLoop runLoop;
mbgl::util::Timer frameTick;
diff --git a/platform/glfw/main.cpp b/platform/glfw/main.cpp
index 59d2ce3ec6..7192475835 100644
--- a/platform/glfw/main.cpp
+++ b/platform/glfw/main.cpp
@@ -6,8 +6,9 @@
#include <mbgl/util/platform.hpp>
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/storage/default_file_source.hpp>
+#include <mbgl/style/style.hpp>
-#include <signal.h>
+#include <csignal>
#include <getopt.h>
#include <fstream>
#include <sstream>
@@ -19,7 +20,7 @@ namespace {
GLFWView* view = nullptr;
-}
+} // namespace
void quit_handler(int) {
if (view) {
@@ -39,15 +40,15 @@ int main(int argc, char *argv[]) {
bool skipConfig = false;
const struct option long_options[] = {
- {"fullscreen", no_argument, 0, 'f'},
- {"benchmark", no_argument, 0, 'b'},
- {"style", required_argument, 0, 's'},
- {"lon", required_argument, 0, 'x'},
- {"lat", required_argument, 0, 'y'},
- {"zoom", required_argument, 0, 'z'},
- {"bearing", required_argument, 0, 'r'},
- {"pitch", required_argument, 0, 'p'},
- {0, 0, 0, 0}
+ {"fullscreen", no_argument, nullptr, 'f'},
+ {"benchmark", no_argument, nullptr, 'b'},
+ {"style", required_argument, nullptr, 's'},
+ {"lon", required_argument, nullptr, 'x'},
+ {"lat", required_argument, nullptr, 'y'},
+ {"zoom", required_argument, nullptr, 'z'},
+ {"bearing", required_argument, nullptr, 'r'},
+ {"pitch", required_argument, nullptr, 'p'},
+ {nullptr, 0, nullptr, 0}
};
while (true) {
@@ -57,7 +58,7 @@ int main(int argc, char *argv[]) {
switch (opt)
{
case 0:
- if (long_options[option_index].flag != 0)
+ if (long_options[option_index].flag != nullptr)
break;
case 'f':
fullscreen = true;
@@ -99,7 +100,7 @@ int main(int argc, char *argv[]) {
sigIntHandler.sa_handler = quit_handler;
sigemptyset(&sigIntHandler.sa_mask);
sigIntHandler.sa_flags = 0;
- sigaction(SIGINT, &sigIntHandler, NULL);
+ sigaction(SIGINT, &sigIntHandler, nullptr);
if (benchmark) {
mbgl::Log::Info(mbgl::Event::General, "BENCHMARK MODE: Some optimizations are disabled.");
@@ -147,7 +148,7 @@ int main(int argc, char *argv[]) {
}
mbgl::util::default_styles::DefaultStyle newStyle = mbgl::util::default_styles::orderedStyles[currentStyleIndex];
- map.setStyleURL(newStyle.url);
+ map.getStyle().loadURL(newStyle.url);
view->setWindowTitle(newStyle.name);
mbgl::Log::Info(mbgl::Event::Setup, "Changed style to: %s", newStyle.name);
@@ -178,7 +179,7 @@ int main(int argc, char *argv[]) {
}
}
- map.setStyleURL(style);
+ map.getStyle().loadURL(style);
view->run();
@@ -194,7 +195,7 @@ int main(int argc, char *argv[]) {
settings.save();
}
mbgl::Log::Info(mbgl::Event::General,
- "Exit location: --lat=\"%f\" --lon=\"%f\" --zoom=\"%f\" --bearing \"%f\"",
+ R"(Exit location: --lat="%f" --lon="%f" --zoom="%f" --bearing "%f")",
settings.latitude, settings.longitude, settings.zoom, settings.bearing);
view = nullptr;
diff --git a/platform/glfw/ny_route.hpp b/platform/glfw/ny_route.hpp
new file mode 100644
index 0000000000..c3d5157106
--- /dev/null
+++ b/platform/glfw/ny_route.hpp
@@ -0,0 +1,104 @@
+#include <string>
+
+namespace mbgl {
+namespace platform {
+namespace glfw {
+
+constexpr const char* route = R"route(
+{
+ "coordinates": [
+ [ -74.013841, 40.702449 ],
+ [ -74.013863, 40.702462 ],
+ [ -74.013977, 40.702548 ],
+ [ -74.01404, 40.702595 ],
+ [ -74.014152, 40.702685 ],
+ [ -74.014213, 40.702749 ],
+ [ -74.014284, 40.702835 ],
+ [ -74.014333, 40.702911 ],
+ [ -74.014368, 40.702978 ],
+ [ -74.014407, 40.703066 ],
+ [ -74.014438, 40.703152 ],
+ [ -74.014449, 40.703209 ],
+ [ -74.01445, 40.703263 ],
+ [ -74.01445, 40.703332 ],
+ [ -74.014442, 40.703401 ],
+ [ -74.014404, 40.703614 ],
+ [ -74.014245, 40.704524 ],
+ [ -74.01422, 40.704633 ],
+ [ -74.014329, 40.704667 ],
+ [ -74.01445, 40.704705 ],
+ [ -74.014548, 40.704733 ],
+ [ -74.014641, 40.704756 ],
+ [ -74.014727, 40.704776 ],
+ [ -74.014841, 40.704799 ],
+ [ -74.014977, 40.704827 ],
+ [ -74.015033, 40.704838 ],
+ [ -74.015365, 40.704905 ],
+ [ -74.015454, 40.704921 ],
+ [ -74.015541, 40.704933 ],
+ [ -74.015638, 40.704945 ],
+ [ -74.015699, 40.70495 ],
+ [ -74.015755, 40.704953 ],
+ [ -74.01583, 40.704952 ],
+ [ -74.015909, 40.704949 ],
+ [ -74.016073, 40.704935 ],
+ [ -74.016157, 40.704927 ],
+ [ -74.016224, 40.704921 ],
+ [ -74.016284, 40.70491 ],
+ [ -74.016416, 40.704882 ],
+ [ -74.016424, 40.704918 ],
+ [ -74.016437, 40.704962 ],
+ [ -74.016453, 40.705007 ],
+ [ -74.016462, 40.705041 ],
+ [ -74.016467, 40.705072 ],
+ [ -74.016463, 40.705112 ],
+ [ -74.016457, 40.70515 ],
+ [ -74.016447, 40.705189 ],
+ [ -74.016151, 40.705949 ],
+ [ -74.016121, 40.706032 ],
+ [ -74.01609, 40.706121 ],
+ [ -74.01606, 40.706214 ],
+ [ -74.016037, 40.706296 ],
+ [ -74.016016, 40.706383 ],
+ [ -74.016003, 40.70645 ],
+ [ -74.015986, 40.706549 ],
+ [ -74.015971, 40.706613 ],
+ [ -74.015953, 40.706677 ],
+ [ -74.015888, 40.706844 ],
+ [ -74.015805, 40.707053 ],
+ [ -74.015735, 40.707222 ],
+ [ -74.015697, 40.707307 ],
+ [ -74.015597, 40.70752 ],
+ [ -74.015512, 40.707701 ],
+ [ -74.015476, 40.707784 ],
+ [ -74.015442, 40.707859 ],
+ [ -74.015363, 40.708065 ],
+ [ -74.015197, 40.708495 ],
+ [ -74.014864, 40.709446 ],
+ [ -74.01476, 40.709725 ],
+ [ -74.014744, 40.709777 ],
+ [ -74.014729, 40.709827 ],
+ [ -74.01472, 40.709873 ],
+ [ -74.014712, 40.709925 ],
+ [ -74.014709, 40.709998 ],
+ [ -74.014699, 40.710139 ],
+ [ -74.014689, 40.710215 ],
+ [ -74.014674, 40.710286 ],
+ [ -74.014655, 40.710373 ],
+ [ -74.014631, 40.710477 ],
+ [ -74.014602, 40.710583 ],
+ [ -74.014523, 40.710825 ],
+ [ -74.014492, 40.710899 ],
+ [ -74.014463, 40.710966 ],
+ [ -74.014434, 40.711033 ],
+ [ -74.014406, 40.711098 ],
+ [ -74.01438, 40.711171 ],
+ [ -74.01436, 40.71125 ],
+ [ -74.014147, 40.712245 ]
+ ],
+ "type": "LineString"
+})route";
+
+} // namespace glfw
+} // namespace platform
+} // namespace mbgl
diff --git a/platform/ios/CHANGELOG.md b/platform/ios/CHANGELOG.md
index c08952a664..785b0ee78b 100644
--- a/platform/ios/CHANGELOG.md
+++ b/platform/ios/CHANGELOG.md
@@ -2,6 +2,14 @@
Mapbox welcomes participation and contributions from everyone. Please read [CONTRIBUTING.md](../../CONTRIBUTING.md) to get started.
+## master
+
+### Styles
+
+* Added support for displaying geo-referenced images via the `MGLImageSource`. [#9110](https://github.com/mapbox/mapbox-gl-native/pull/9110)
+* The previously-deprecated support for style classes has been removed. For interface compatibility, the API methods remain, but they are now non-functional.
+* Added an `overlays` property to `MGLMapView`. ([#8617](https://github.com/mapbox/mapbox-gl-native/pull/8617))
+
## 3.6.0
### Packaging
diff --git a/platform/ios/app/Info.plist b/platform/ios/app/Info.plist
index d05d81e49d..d5b6825422 100644
--- a/platform/ios/app/Info.plist
+++ b/platform/ios/app/Info.plist
@@ -51,18 +51,5 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
- <key>NSAppTransportSecurity</key>
- <dict>
- <key>NSExceptionDomains</key>
- <dict>
- <key>stamen.com</key>
- <dict>
- <key>NSIncludesSubdomains</key>
- <true/>
- <key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
- <true/>
- </dict>
- </dict>
- </dict>
</dict>
</plist>
diff --git a/platform/ios/app/MBXViewController.m b/platform/ios/app/MBXViewController.m
index d3927374a7..29c5c65012 100644
--- a/platform/ios/app/MBXViewController.m
+++ b/platform/ios/app/MBXViewController.m
@@ -52,7 +52,8 @@ typedef NS_ENUM(NSInteger, MBXSettingsAnnotationsRows) {
};
typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) {
- MBXSettingsRuntimeStylingWater = 0,
+ MBXSettingsRuntimeStylingBuildingExtrusions = 0,
+ MBXSettingsRuntimeStylingWater,
MBXSettingsRuntimeStylingRoads,
MBXSettingsRuntimeStylingRaster,
MBXSettingsRuntimeStylingShape,
@@ -71,6 +72,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsRuntimeStylingRows) {
MBXSettingsRuntimeStylingUpdateShapeSourceFeatures,
MBXSettingsRuntimeStylingVectorSource,
MBXSettingsRuntimeStylingRasterSource,
+ MBXSettingsRuntimeStylingImageSource,
MBXSettingsRuntimeStylingCountryLabels,
MBXSettingsRuntimeStylingRouteLine,
MBXSettingsRuntimeStylingDDSPolygon,
@@ -324,6 +326,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
break;
case MBXSettingsRuntimeStyling:
[settingsTitles addObjectsFromArray:@[
+ @"Add Building Extrusions",
@"Style Water With Function",
@"Style Roads With Function",
@"Add Raster & Apply Function",
@@ -343,6 +346,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
@"Update Shape Source: Features",
@"Style Vector Source",
@"Style Raster Source",
+ @"Style Image Source",
[NSString stringWithFormat:@"Label Countries in %@", (_usingLocaleBasedCountryLabels ? @"Local Language" : [[NSLocale currentLocale] displayNameForKey:NSLocaleIdentifier value:[self bestLanguageForUser]])],
@"Add Route Line",
@"Dynamically Style Polygon",
@@ -523,6 +527,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
case MBXSettingsRuntimeStyling:
switch (indexPath.row)
{
+ case MBXSettingsRuntimeStylingBuildingExtrusions:
+ [self styleBuildingExtrusions];
+ break;
case MBXSettingsRuntimeStylingWater:
[self styleWaterLayer];
break;
@@ -580,6 +587,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
case MBXSettingsRuntimeStylingRasterSource:
[self styleRasterSource];
break;
+ case MBXSettingsRuntimeStylingImageSource:
+ [self styleImageSource];
+ break;
case MBXSettingsRuntimeStylingCountryLabels:
[self styleCountryLabelsLanguage];
break;
@@ -860,6 +870,38 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self.mapView showAnnotations:annotations animated:YES];
}
+- (void)styleBuildingExtrusions
+{
+ MGLSource* source = [self.mapView.style sourceWithIdentifier:@"composite"];
+ if (source) {
+
+ MGLFillExtrusionStyleLayer* layer = [[MGLFillExtrusionStyleLayer alloc] initWithIdentifier:@"extrudedBuildings" source:source];
+ layer.sourceLayerIdentifier = @"building";
+ layer.predicate = [NSPredicate predicateWithFormat:@"extrude == 'true' AND height > 0"];
+ layer.fillExtrusionBase = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"min_height" options:nil];
+ layer.fillExtrusionHeight = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeIdentity sourceStops:nil attributeName:@"height" options:nil];
+
+ // Set the fill color to that of the existing building footprint layer, if it exists.
+ MGLFillStyleLayer* buildingLayer = (MGLFillStyleLayer*)[self.mapView.style layerWithIdentifier:@"building"];
+ if (buildingLayer) {
+ if (buildingLayer.fillColor) {
+ layer.fillExtrusionColor = buildingLayer.fillColor;
+ } else {
+ layer.fillExtrusionColor = [MGLStyleValue valueWithRawValue:[UIColor whiteColor]];
+ }
+
+ layer.fillExtrusionOpacity = [MGLStyleValue<NSNumber *> valueWithRawValue:@0.75];
+ }
+
+ MGLStyleLayer* labelLayer = [self.mapView.style layerWithIdentifier:@"waterway-label"];
+ if (labelLayer) {
+ [self.mapView.style insertLayer:layer belowLayer:labelLayer];
+ } else {
+ [self.mapView.style addLayer:layer];
+ }
+ }
+}
+
- (void)styleWaterLayer
{
MGLFillStyleLayer *waterLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"water"];
@@ -1261,8 +1303,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
- (void)styleRasterSource
{
- // 3rd party raster source requires NSAppTransportSecurity exception for stamen.com
- NSArray *tileURLTemplates = @[@"http://a.tile.stamen.com/terrain-background/{z}/{x}/{y}.jpg"];
+ NSArray *tileURLTemplates = @[@"https://stamen-tiles.a.ssl.fastly.net/terrain-background/{z}/{x}/{y}.jpg"];
MGLRasterSource *rasterSource = [[MGLRasterSource alloc] initWithIdentifier:@"style-raster-source-id" tileURLTemplates:tileURLTemplates options:@{
MGLTileSourceOptionTileSize: @256,
}];
@@ -1272,6 +1313,39 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
[self.mapView.style addLayer:rasterLayer];
}
+- (void)styleImageSource
+{
+ MGLCoordinateQuad coordinateQuad = {
+ { 46.437, -80.425 },
+ { 37.936, -80.425 },
+ { 37.936, -71.516 },
+ { 46.437, -71.516 } };
+
+ MGLImageSource *imageSource = [[MGLImageSource alloc] initWithIdentifier:@"style-image-source-id" coordinateQuad:coordinateQuad URL:[NSURL URLWithString:@"https://www.mapbox.com/mapbox-gl-js/assets/radar0.gif"]];
+
+ [self.mapView.style addSource:imageSource];
+
+ MGLRasterStyleLayer *rasterLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"style-raster-image-layer-id" source:imageSource];
+ [self.mapView.style addLayer:rasterLayer];
+
+ [NSTimer scheduledTimerWithTimeInterval:1.0
+ target:self
+ selector:@selector(updateAnimatedImageSource:)
+ userInfo:imageSource
+ repeats:YES];
+}
+
+
+- (void)updateAnimatedImageSource:(NSTimer *)timer {
+ static int radarSuffix = 0;
+ MGLImageSource *imageSource = (MGLImageSource *)timer.userInfo;
+ NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"https://www.mapbox.com/mapbox-gl-js/assets/radar%d.gif", radarSuffix++]];
+ [imageSource setValue:url forKey:@"URL"];
+ if (radarSuffix > 3) {
+ radarSuffix = 0;
+ }
+}
+
-(void)styleCountryLabelsLanguage
{
NSArray<NSString *> *labelLayers = @[
diff --git a/platform/ios/docs/guides/Adding Points to a Map.md b/platform/ios/docs/guides/Adding Points to a Map.md
index ab1702a076..2698d5564f 100644
--- a/platform/ios/docs/guides/Adding Points to a Map.md
+++ b/platform/ios/docs/guides/Adding Points to a Map.md
@@ -36,7 +36,6 @@ By default, annotations added to the map are displayed with a red pin ([example]
* Annotation images are purely static and cannot be animated
* No control over z-ordering
-* Limits to the number and size of images you can add
### Annotation Views (`MGLAnnotationView`)
diff --git a/platform/ios/docs/guides/For Style Authors.md b/platform/ios/docs/guides/For Style Authors.md
index 35375ea2a9..7eabfed777 100644
--- a/platform/ios/docs/guides/For Style Authors.md
+++ b/platform/ios/docs/guides/For Style Authors.md
@@ -109,7 +109,6 @@ the following terms for concepts defined in the style specification:
In the style specification | In the SDK
---------------------------|---------
-class | style class
filter | predicate
function type | interpolation mode
id | identifier
@@ -130,8 +129,9 @@ In style JSON | In the SDK
`geojson` | `MGLShapeSource`
`raster` | `MGLRasterSource`
`vector` | `MGLVectorSource`
+`image` | `MGLImageSource`
-`canvas`, `image`, and `video` sources are not supported.
+`canvas` and `video` sources are not supported.
### Tile sources
@@ -172,6 +172,12 @@ To create a shape source from local GeoJSON data, first
[convert the GeoJSON data into a shape](working-with-geojson-data.html#converting-geojson-data-into-shape-objects),
then use the `-[MGLShapeSource initWithIdentifier:shape:options:]` method.
+### Image sources
+
+Image sources accept a non-axis aligned quadrilateral as their geographic coordinates.
+These coordinates, in `MGLCoordinateQuad`, are described in counterclockwise order,
+in contrast to the clockwise order defined in the style specification.
+
## Configuring the map content’s appearance
Each layer defined by the style JSON file is represented at runtime by a style
diff --git a/platform/ios/ios.xcodeproj/project.pbxproj b/platform/ios/ios.xcodeproj/project.pbxproj
index ab110bca5c..9af8387233 100644
--- a/platform/ios/ios.xcodeproj/project.pbxproj
+++ b/platform/ios/ios.xcodeproj/project.pbxproj
@@ -7,6 +7,11 @@
objects = {
/* Begin PBXBuildFile section */
+ 071BBAFF1EE7613E001FB02A /* MGLImageSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */; };
+ 071BBB001EE7613F001FB02A /* MGLImageSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */; };
+ 071BBB031EE76146001FB02A /* MGLImageSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 071BBB041EE76147001FB02A /* MGLImageSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 071BBB071EE77631001FB02A /* MGLImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */; };
1753ED421E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; };
1753ED431E53CE6F00A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED411E53CE6F00A9FD90 /* MGLConversion.h */; };
1F06668A1EC64F8E001C16D7 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F0666881EC64F8E001C16D7 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -186,6 +191,8 @@
40F887701D7A1E58008ECB67 /* MGLShapeSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 40F8876F1D7A1DB8008ECB67 /* MGLShapeSource_Private.h */; };
40F887711D7A1E59008ECB67 /* MGLShapeSource_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 40F8876F1D7A1DB8008ECB67 /* MGLShapeSource_Private.h */; };
40FDA76B1CCAAA6800442548 /* MBXAnnotationView.m in Sources */ = {isa = PBXBuildFile; fileRef = 40FDA76A1CCAAA6800442548 /* MBXAnnotationView.m */; };
+ 5549A0391EF2877100073113 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 554180411D2E97DE00012372 /* OpenGLES.framework */; };
+ 5549A03A1EF2877500073113 /* OpenGLES.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 554180411D2E97DE00012372 /* OpenGLES.framework */; };
556660CA1E1BF3A900E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C91E1BF3A900E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
556660D81E1D085500E2C41B /* MGLVersionNumber.m in Sources */ = {isa = PBXBuildFile; fileRef = 556660D71E1D085500E2C41B /* MGLVersionNumber.m */; };
556660DB1E1D8E8D00E2C41B /* MGLFoundation.h in Headers */ = {isa = PBXBuildFile; fileRef = 556660C91E1BF3A900E2C41B /* MGLFoundation.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -540,6 +547,9 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLImageSource.h; sourceTree = "<group>"; };
+ 071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLImageSource.mm; sourceTree = "<group>"; };
+ 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLImageSourceTests.m; path = ../../darwin/test/MGLImageSourceTests.m; sourceTree = "<group>"; };
1753ED411E53CE6F00A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
1F0666881EC64F8E001C16D7 /* MGLLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight.h; sourceTree = "<group>"; };
1F0666891EC64F8E001C16D7 /* MGLLight.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLLight.mm; sourceTree = "<group>"; };
@@ -938,6 +948,7 @@
buildActionMask = 2147483647;
files = (
DA8847D91CBAF91600AB86E3 /* Mapbox.framework in Frameworks */,
+ 5549A0391EF2877100073113 /* OpenGLES.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -971,6 +982,7 @@
buildActionMask = 2147483647;
files = (
DAA4E4081CBB6C9500178DFB /* Mapbox.framework in Frameworks */,
+ 5549A03A1EF2877500073113 /* OpenGLES.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -980,6 +992,8 @@
35136D491D4277EA00C20EFD /* Sources */ = {
isa = PBXGroup;
children = (
+ 071BBAFC1EE75CD4001FB02A /* MGLImageSource.h */,
+ 071BBAFD1EE75CD4001FB02A /* MGLImageSource.mm */,
3566C76A1D4A8DFA008152BC /* MGLRasterSource.h */,
DAF0D80F1DFE0EA000B28378 /* MGLRasterSource_Private.h */,
3566C76B1D4A8DFA008152BC /* MGLRasterSource.mm */,
@@ -1137,6 +1151,7 @@
40CFA64E1D78754A008103BD /* Sources */ = {
isa = PBXGroup;
children = (
+ 071BBB051EE7761A001FB02A /* MGLImageSourceTests.m */,
40CFA6501D787579008103BD /* MGLShapeSourceTests.mm */,
920A3E5C1E6F995200C16EFC /* MGLSourceQueryTests.m */,
4085AF081D933DEA00F11B22 /* MGLTileSetTests.mm */,
@@ -1671,6 +1686,7 @@
DA8848311CBAFA6200AB86E3 /* NSString+MGLAdditions.h in Headers */,
353933F81D3FB79F003F57D7 /* MGLLineStyleLayer.h in Headers */,
DAAF722D1DA903C700312FA4 /* MGLStyleValue_Private.h in Headers */,
+ 071BBB031EE76146001FB02A /* MGLImageSource.h in Headers */,
DA8847F41CBAFA5100AB86E3 /* MGLOfflinePack.h in Headers */,
DA88482E1CBAFA6200AB86E3 /* NSException+MGLAdditions.h in Headers */,
DA8848551CBAFB9800AB86E3 /* MGLLocationManager.h in Headers */,
@@ -1754,6 +1770,7 @@
3566C7671D4A77BA008152BC /* MGLShapeSource.h in Headers */,
DA35A29F1CC9E94C00E826B2 /* MGLCoordinateFormatter.h in Headers */,
404C26E31D89B877000AA13D /* MGLTileSource.h in Headers */,
+ 071BBB041EE76147001FB02A /* MGLImageSource.h in Headers */,
DABFB8611CBE99E500D62B32 /* MGLMultiPoint.h in Headers */,
3510FFF11D6D9D8C00F413B2 /* NSExpression+MGLAdditions.h in Headers */,
35D3A1E71E9BE7EC002B38EE /* MGLScaleBar.h in Headers */,
@@ -1964,7 +1981,6 @@
TargetAttributes = {
DA1DC9491CB6C1C2006E619F = {
CreatedOnToolsVersion = 7.3;
- DevelopmentTeam = GJZR2MEM28;
LastSwiftMigration = 0820;
};
DA25D5B81CCD9EDE00607828 = {
@@ -2150,6 +2166,7 @@
35D9DDE21DA25EEC00DAAD69 /* MGLCodingTests.m in Sources */,
DA1F8F3D1EBD287B00367E42 /* MGLDocumentationGuideTests.swift in Sources */,
3598544D1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m in Sources */,
+ 071BBB071EE77631001FB02A /* MGLImageSourceTests.m in Sources */,
DA2DBBCE1D51E80400D38FF9 /* MGLStyleLayerTests.m in Sources */,
DA35A2C61CCA9F8300E826B2 /* MGLCompassDirectionFormatterTests.m in Sources */,
DAE7DEC21E245455007505A6 /* MGLNSStringAdditionsTests.m in Sources */,
@@ -2226,6 +2243,7 @@
DD0902A91DB1929D00C5BDCE /* MGLNetworkConfiguration.m in Sources */,
35D13AB91D3D15E300AFB4E0 /* MGLStyleLayer.mm in Sources */,
DA35A2CB1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */,
+ 071BBB001EE7613F001FB02A /* MGLImageSource.mm in Sources */,
DA8848321CBAFA6200AB86E3 /* NSString+MGLAdditions.m in Sources */,
408AA8581DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */,
DA35A2A11CC9E95F00E826B2 /* MGLCoordinateFormatter.m in Sources */,
@@ -2307,6 +2325,7 @@
DD0902AA1DB1929D00C5BDCE /* MGLNetworkConfiguration.m in Sources */,
DA35A2B41CCA141D00E826B2 /* MGLCompassDirectionFormatter.m in Sources */,
35D13ABA1D3D15E300AFB4E0 /* MGLStyleLayer.mm in Sources */,
+ 071BBAFF1EE7613E001FB02A /* MGLImageSource.mm in Sources */,
DA35A2CC1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */,
408AA8591DAEDA1E00022900 /* NSDictionary+MGLAdditions.mm in Sources */,
DAA4E4281CBB730400178DFB /* MGLTypes.m in Sources */,
@@ -2629,6 +2648,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
@@ -2642,6 +2662,7 @@
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "$(SRCROOT)/app/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
diff --git a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/bench.xcscheme b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/bench.xcscheme
index 9dd128ff24..f5aff5b3b4 100644
--- a/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/bench.xcscheme
+++ b/platform/ios/ios.xcodeproj/xcshareddata/xcschemes/bench.xcscheme
@@ -42,7 +42,7 @@
</AdditionalOptions>
</TestAction>
<LaunchAction
- buildConfiguration = "Debug"
+ buildConfiguration = "Release"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
diff --git a/platform/ios/jazzy.yml b/platform/ios/jazzy.yml
index 31380faa2c..ba56c312eb 100644
--- a/platform/ios/jazzy.yml
+++ b/platform/ios/jazzy.yml
@@ -75,6 +75,7 @@ custom_categories:
children:
- MGLSource
- MGLTileSource
+ - MGLImageSource
- MGLShapeSource
- MGLRasterSource
- MGLVectorSource
@@ -108,6 +109,9 @@ custom_categories:
- MGLCoordinateBoundsMake
- MGLCoordinateBoundsOffset
- MGLCoordinateInCoordinateBounds
+ - MGLCoordinateQuad
+ - MGLCoordinateQuadMake
+ - MGLCoordinateQuadFromCoordinateBounds
- MGLCoordinateSpan
- MGLCoordinateSpanEqualToCoordinateSpan
- MGLCoordinateSpanMake
@@ -115,6 +119,7 @@ custom_categories:
- MGLDegreesFromRadians
- MGLRadiansFromDegrees
- MGLStringFromCoordinateBounds
+ - MGLStringFromCoordinateQuad
- name: Formatters
children:
- MGLClockDirectionFormatter
diff --git a/platform/ios/src/MGLMapView.h b/platform/ios/src/MGLMapView.h
index 31320ac977..ca765a046b 100644
--- a/platform/ios/src/MGLMapView.h
+++ b/platform/ios/src/MGLMapView.h
@@ -270,13 +270,25 @@ IB_DESIGNABLE
*/
@property (nonatomic, readonly) UIButton *attributionButton;
-@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((deprecated("Use style.styleClasses.")));
+/**
+ Support for style classes has been removed. This property always returns an empty array.
+ */
+@property (nonatomic) NS_ARRAY_OF(NSString *) *styleClasses __attribute__((deprecated("This property is non-functional.")));
-- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("Use style.hasStyleClass:.")));
+/**
+ Support for style classes has been removed. This property always returns NO.
+ */
+- (BOOL)hasStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
-- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("Use style.addStyleClass:.")));
+/**
+ Support for style classes has been removed. This property is a no-op.
+ */
+- (void)addStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
-- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("Use style.removeStyleClass:.")));
+/**
+ Support for style classes has been removed. This property is a no-op.
+ */
+- (void)removeStyleClass:(NSString *)styleClass __attribute__((deprecated("This method is non-functional.")));
#pragma mark Displaying the User’s Location
@@ -1119,6 +1131,15 @@ IB_DESIGNABLE
#pragma mark Overlaying the Map
/**
+ The complete list of overlays associated with the receiver. (read-only)
+
+ The objects in this array must adopt the `MGLOverlay` protocol. If no
+ overlays are associated with the map view, the value of this property is
+ empty array.
+ */
+@property (nonatomic, readonly, nonnull) NS_ARRAY_OF(id <MGLOverlay>) *overlays;
+
+/**
Adds a single overlay object to the map.
To remove an overlay from a map, use the `-removeOverlay:` method.
diff --git a/platform/ios/src/MGLMapView.mm b/platform/ios/src/MGLMapView.mm
index f3b0d8506a..1444fc3cb0 100644
--- a/platform/ios/src/MGLMapView.mm
+++ b/platform/ios/src/MGLMapView.mm
@@ -15,6 +15,7 @@
#include <mbgl/util/default_thread_pool.hpp>
#include <mbgl/storage/default_file_source.hpp>
#include <mbgl/storage/network_status.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/style/transition_options.hpp>
#include <mbgl/style/layers/custom_layer.hpp>
@@ -379,7 +380,7 @@ public:
- (nonnull NSURL *)styleURL
{
- NSString *styleURLString = @(_mbglMap->getStyleURL().c_str()).mgl_stringOrNilIfEmpty;
+ NSString *styleURLString = @(_mbglMap->getStyle().getURL().c_str()).mgl_stringOrNilIfEmpty;
NSAssert(styleURLString || _isTargetingInterfaceBuilder, @"Invalid style URL string %@", styleURLString);
return styleURLString ? [NSURL URLWithString:styleURLString] : nil;
}
@@ -395,12 +396,12 @@ public:
styleURL = styleURL.mgl_URLByStandardizingScheme;
self.style = nil;
- _mbglMap->setStyleURL([[styleURL absoluteString] UTF8String]);
+ _mbglMap->getStyle().loadURL([[styleURL absoluteString] UTF8String]);
}
- (IBAction)reloadStyle:(__unused id)sender {
NSURL *styleURL = self.styleURL;
- _mbglMap->setStyleURL("");
+ _mbglMap->getStyle().loadURL("");
self.styleURL = styleURL;
}
@@ -444,7 +445,6 @@ public:
const float scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [[UIScreen mainScreen] nativeScale] : [[UIScreen mainScreen] scale];
_mbglThreadPool = mbgl::sharedThreadPool();
_mbglMap = new mbgl::Map(*_mbglView, self.size, scaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default);
- [self validateTileCacheSize];
// start paused if in IB
if (_isTargetingInterfaceBuilder || background) {
@@ -763,42 +763,6 @@ public:
#pragma mark - Layout -
-- (void)setFrame:(CGRect)frame
-{
- [super setFrame:frame];
- if ( ! CGRectEqualToRect(frame, self.frame))
- {
- [self validateTileCacheSize];
- }
-}
-
-- (void)setBounds:(CGRect)bounds
-{
- [super setBounds:bounds];
- if ( ! CGRectEqualToRect(bounds, self.bounds))
- {
- [self validateTileCacheSize];
- }
-}
-
-- (void)validateTileCacheSize
-{
- if ( ! _mbglMap)
- {
- return;
- }
-
- CGFloat zoomFactor = self.maximumZoomLevel - self.minimumZoomLevel + 1;
- CGFloat cpuFactor = [NSProcessInfo processInfo].processorCount;
- CGFloat memoryFactor = (CGFloat)[NSProcessInfo processInfo].physicalMemory / 1000 / 1000 / 1000;
- CGFloat sizeFactor = (CGRectGetWidth(self.bounds) / mbgl::util::tileSize) *
- (CGRectGetHeight(self.bounds) / mbgl::util::tileSize);
-
- NSUInteger cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5;
-
- _mbglMap->setSourceTileCacheSize(cacheSize);
-}
-
+ (BOOL)requiresConstraintBasedLayout
{
return YES;
@@ -2164,10 +2128,10 @@ public:
- (void)resetPosition
{
- CGFloat pitch = _mbglMap->getDefaultPitch();
- CLLocationDirection heading = mbgl::util::wrap(_mbglMap->getDefaultBearing(), 0., 360.);
- CLLocationDistance distance = MGLAltitudeForZoomLevel(_mbglMap->getDefaultZoom(), pitch, 0, self.frame.size);
- self.camera = [MGLMapCamera cameraLookingAtCenterCoordinate:MGLLocationCoordinate2DFromLatLng(_mbglMap->getDefaultLatLng())
+ CGFloat pitch = _mbglMap->getStyle().getDefaultPitch();
+ CLLocationDirection heading = mbgl::util::wrap(_mbglMap->getStyle().getDefaultBearing(), 0., 360.);
+ CLLocationDistance distance = MGLAltitudeForZoomLevel(_mbglMap->getStyle().getDefaultZoom(), pitch, 0, self.frame.size);
+ self.camera = [MGLMapCamera cameraLookingAtCenterCoordinate:MGLLocationCoordinate2DFromLatLng(_mbglMap->getStyle().getDefaultLatLng())
fromDistance:distance
pitch:pitch
heading:heading];
@@ -2558,8 +2522,6 @@ public:
- (void)setMinimumZoomLevel:(double)minimumZoomLevel
{
- _mbglMap->setMinZoom(minimumZoomLevel);
- [self validateTileCacheSize];
}
- (double)minimumZoomLevel
@@ -2570,7 +2532,6 @@ public:
- (void)setMaximumZoomLevel:(double)maximumZoomLevel
{
_mbglMap->setMaxZoom(maximumZoomLevel);
- [self validateTileCacheSize];
}
- (double)maximumZoomLevel
@@ -3444,7 +3405,7 @@ public:
annotationImage.delegate = self;
// add sprite
- _mbglMap->addAnnotationImage(iconIdentifier.UTF8String, annotationImage.image.mgl_styleImage);
+ _mbglMap->addAnnotationImage([annotationImage.image mgl_styleImageWithIdentifier:iconIdentifier]);
// Create a slop area with a “radius” equal in size to the annotation
// image’s alignment rect, allowing the eventual tap to be on any point
@@ -3527,6 +3488,22 @@ public:
}
}
+- (nonnull NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+{
+ if (self.annotations == nil) { return @[]; }
+
+ NS_MUTABLE_ARRAY_OF(id <MGLOverlay>) *mutableOverlays = [NSMutableArray array];
+
+ [self.annotations enumerateObjectsUsingBlock:^(id<MGLAnnotation> _Nonnull annotation, NSUInteger idx, BOOL * _Nonnull stop) {
+ if ([annotation conformsToProtocol:@protocol(MGLOverlay)])
+ {
+ [mutableOverlays addObject:(id<MGLOverlay>)annotation];
+ }
+ }];
+
+ return [NSArray arrayWithArray:mutableOverlays];
+}
+
- (void)addOverlay:(id <MGLOverlay>)overlay
{
[self addOverlays:@[ overlay ]];
@@ -4989,7 +4966,7 @@ public:
return;
}
- self.style = [[MGLStyle alloc] initWithMapView:self];
+ self.style = [[MGLStyle alloc] initWithRawStyle:&_mbglMap->getStyle() mapView:self];
if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
{
[self.delegate mapView:self didFinishLoadingStyle:self.style];
@@ -5442,7 +5419,7 @@ public:
/// context state with the anticipated values.
void updateAssumedState() override {
assumeFramebufferBinding(ImplicitFramebufferBinding);
- assumeViewportSize(nativeView.framebufferSize);
+ assumeViewport(0, 0, nativeView.framebufferSize);
}
void bind() override {
@@ -5455,7 +5432,7 @@ public:
updateAssumedState();
} else {
// Our framebuffer is still bound, but the viewport might have changed.
- setViewportSize(nativeView.framebufferSize);
+ setViewport(0, 0, nativeView.framebufferSize);
}
}
diff --git a/platform/ios/src/Mapbox.h b/platform/ios/src/Mapbox.h
index 67a26e8ed4..abe16cc3ee 100644
--- a/platform/ios/src/Mapbox.h
+++ b/platform/ios/src/Mapbox.h
@@ -52,6 +52,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLVectorSource.h"
#import "MGLShapeSource.h"
#import "MGLRasterSource.h"
+#import "MGLImageSource.h"
#import "MGLTilePyramidOfflineRegion.h"
#import "MGLTypes.h"
#import "MGLUserLocation.h"
diff --git a/platform/ios/src/UIImage+MGLAdditions.h b/platform/ios/src/UIImage+MGLAdditions.h
index 642355d412..6e15e07cb5 100644
--- a/platform/ios/src/UIImage+MGLAdditions.h
+++ b/platform/ios/src/UIImage+MGLAdditions.h
@@ -8,7 +8,9 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable instancetype)initWithMGLStyleImage:(const mbgl::style::Image *)styleImage;
-- (std::unique_ptr<mbgl::style::Image>)mgl_styleImage;
+- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier;
+
+- (mbgl::PremultipliedImage)mgl_premultipliedImage;
@end
diff --git a/platform/ios/src/UIImage+MGLAdditions.mm b/platform/ios/src/UIImage+MGLAdditions.mm
index db64d78232..5e28d18190 100644
--- a/platform/ios/src/UIImage+MGLAdditions.mm
+++ b/platform/ios/src/UIImage+MGLAdditions.mm
@@ -6,14 +6,14 @@
- (nullable instancetype)initWithMGLStyleImage:(const mbgl::style::Image *)styleImage
{
- CGImageRef image = CGImageFromMGLPremultipliedImage(styleImage->image.clone());
+ CGImageRef image = CGImageFromMGLPremultipliedImage(styleImage->getImage().clone());
if (!image) {
return nil;
}
- if (self = [self initWithCGImage:image scale:styleImage->pixelRatio orientation:UIImageOrientationUp])
+ if (self = [self initWithCGImage:image scale:styleImage->getPixelRatio() orientation:UIImageOrientationUp])
{
- if (styleImage->sdf)
+ if (styleImage->isSdf())
{
self = [self imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
}
@@ -22,10 +22,14 @@
return self;
}
-- (std::unique_ptr<mbgl::style::Image>)mgl_styleImage {
+- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier {
BOOL isTemplate = self.renderingMode == UIImageRenderingModeAlwaysTemplate;
- return std::make_unique<mbgl::style::Image>(MGLPremultipliedImageFromCGImage(self.CGImage),
+ return std::make_unique<mbgl::style::Image>([identifier UTF8String],
+ self.mgl_premultipliedImage,
float(self.scale), isTemplate);
}
+-(mbgl::PremultipliedImage)mgl_premultipliedImage {
+ return MGLPremultipliedImageFromCGImage(self.CGImage);
+}
@end
diff --git a/platform/ios/vendor/SMCalloutView b/platform/ios/vendor/SMCalloutView
-Subproject 2aede5d8d1577101bf18405246220e7a710df60
+Subproject d6ecaba377c9f963aef630faf86e3b8f8cdb88d
diff --git a/platform/linux/scripts/coveralls.sh b/platform/linux/scripts/coveralls.sh
index b8ab73a24e..57affe1e28 100755
--- a/platform/linux/scripts/coveralls.sh
+++ b/platform/linux/scripts/coveralls.sh
@@ -3,9 +3,13 @@
set -e
set -o pipefail
+command -v lcov 2> /dev/null || {
+ echo "Aborting: lcov not found."
+ exit 1
+}
+
# Collect coverage data and save it into coverage.info
-mapbox_time "lcov_capture" \
-`scripts/mason.sh PREFIX lcov VERSION 1.12`/usr/bin/lcov \
+lcov \
--quiet \
--capture \
--no-external \
@@ -17,5 +21,8 @@ mapbox_time "lcov_capture" \
--base-directory "build/linux-x86_64/${BUILDTYPE}" \
--output-file "build/linux-x86_64/${BUILDTYPE}/coverage.info"
-mapbox_time "coveralls_upload" \
-coveralls-lcov "build/linux-x86_64/${BUILDTYPE}/coverage.info"
+coveralls-lcov \
+ --service-name="${COVERALLS_SERVICE_NAME}" \
+ --repo-token="${COVERALLS_REPO_TOKEN}" \
+ --service-job-id="${CIRCLE_BUILD_NUM}" \
+ "build/linux-x86_64/${BUILDTYPE}/coverage.info"
diff --git a/platform/linux/src/headless_backend_glx.cpp b/platform/linux/src/headless_backend_glx.cpp
index 36a60ec06b..eec0e7656f 100644
--- a/platform/linux/src/headless_backend_glx.cpp
+++ b/platform/linux/src/headless_backend_glx.cpp
@@ -17,7 +17,7 @@ struct GLXImpl : public HeadlessBackend::Impl {
fbConfigs(fbConfigs_) {
}
- ~GLXImpl() {
+ ~GLXImpl() override {
if (glxPbuffer) {
glXDestroyPbuffer(xDisplay, glxPbuffer);
}
@@ -58,8 +58,8 @@ bool HeadlessBackend::hasDisplay() {
void HeadlessBackend::createContext() {
assert(!hasContext());
- Display* xDisplay = display->attribute<Display*>();
- GLXFBConfig* fbConfigs = display->attribute<GLXFBConfig*>();
+ auto* xDisplay = display->attribute<Display*>();
+ auto* fbConfigs = display->attribute<GLXFBConfig*>();
// Try to create a legacy context.
GLXContext glContext = glXCreateNewContext(xDisplay, fbConfigs[0], GLX_RGBA_TYPE, None, True);
@@ -81,7 +81,7 @@ void HeadlessBackend::createContext() {
};
GLXPbuffer glxPbuffer = glXCreatePbuffer(xDisplay, fbConfigs[0], pbufferAttributes);
- impl.reset(new GLXImpl(glContext, glxPbuffer, xDisplay, fbConfigs));
+ impl = std::make_unique<mbgl::GLXImpl>(glContext, glxPbuffer, xDisplay, fbConfigs);
}
} // namespace mbgl
diff --git a/platform/linux/src/headless_display_glx.cpp b/platform/linux/src/headless_display_glx.cpp
index 4275ebb646..5dc342154d 100644
--- a/platform/linux/src/headless_display_glx.cpp
+++ b/platform/linux/src/headless_display_glx.cpp
@@ -27,7 +27,7 @@ HeadlessDisplay::Impl::Impl() {
throw std::runtime_error("Failed to open X display.");
}
- const char *extensions = reinterpret_cast<const char *>(glXQueryServerString(xDisplay, DefaultScreen(xDisplay), GLX_EXTENSIONS));
+ const auto *extensions = reinterpret_cast<const char *>(glXQueryServerString(xDisplay, DefaultScreen(xDisplay), GLX_EXTENSIONS));
if (!extensions) {
throw std::runtime_error("Cannot read GLX extensions.");
}
@@ -73,7 +73,6 @@ HeadlessDisplay::HeadlessDisplay()
: impl(std::make_unique<Impl>()) {
}
-HeadlessDisplay::~HeadlessDisplay() {
-}
+HeadlessDisplay::~HeadlessDisplay() = default;
} // namespace mbgl
diff --git a/platform/macos/CHANGELOG.md b/platform/macos/CHANGELOG.md
index f69f7e1b5d..df8c395ee8 100644
--- a/platform/macos/CHANGELOG.md
+++ b/platform/macos/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog for Mapbox macOS SDK
+## master
+
+### Styles
+* Added support for displaying geo-referenced images via the `MGLImageSource`. [#9110](https://github.com/mapbox/mapbox-gl-native/pull/9110)
+* The previously-deprecated support for style classes has been removed. For interface compatibility, the API methods remain, but they are now non-functional.
+* Added an `overlays` property to `MGLMapView`. ([#8617](https://github.com/mapbox/mapbox-gl-native/pull/8617))
+
## 0.5.0
This version of the Mapbox macOS SDK corresponds to version 3.6.0 of the Mapbox iOS SDK.
@@ -9,8 +16,6 @@ This version of the Mapbox macOS SDK corresponds to version 3.6.0 of the Mapbox
* Xcode 8.0 or higher is now recommended for using this SDK. ([#8775](https://github.com/mapbox/mapbox-gl-native/pull/8775))
* Updated MGLMapView’s logo view to display [the new Mapbox logo](https://www.mapbox.com/blog/new-mapbox-logo/). ([#8771](https://github.com/mapbox/mapbox-gl-native/pull/8771), [#8773](https://github.com/mapbox/mapbox-gl-native/pull/8773))
-### Styles
-
* Added support for 3D extrusion of buildings and other polygonal features via the `MGLFillExtrusionStyleLayer` class and the `fill-extrusion` layer type in style JSON. ([#8431](https://github.com/mapbox/mapbox-gl-native/pull/8431))
* MGLMapView and MGLTilePyramidOfflineRegion now default to version 10 of the Mapbox Streets style. Similarly, several style URL class methods of MGLStyle return URLs to version 10 styles. Unversioned variations of these methods are no longer deprecated. `MGLStyleDefaultVersion` should no longer be used with any style other than Streets. ([#6301](https://github.com/mapbox/mapbox-gl-native/pull/6301))
* Added class methods to MGLStyle that correspond to the new [Traffic Day and Traffic Night](https://www.mapbox.com/blog/live-traffic-maps/) styles. ([#6301](https://github.com/mapbox/mapbox-gl-native/pull/6301))
diff --git a/platform/macos/app/Assets.xcassets/Radar/Contents.json b/platform/macos/app/Assets.xcassets/Radar/Contents.json
new file mode 100644
index 0000000000..da4a164c91
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/Radar/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/platform/macos/app/Assets.xcassets/Radar/southeast_0.imageset/Contents.json b/platform/macos/app/Assets.xcassets/Radar/southeast_0.imageset/Contents.json
new file mode 100644
index 0000000000..ea096b04b8
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/Radar/southeast_0.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "southeast_radar_0.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/platform/macos/app/Assets.xcassets/Radar/southeast_0.imageset/southeast_radar_0.png b/platform/macos/app/Assets.xcassets/Radar/southeast_0.imageset/southeast_radar_0.png
new file mode 100644
index 0000000000..c304b619c4
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/Radar/southeast_0.imageset/southeast_radar_0.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/Radar/southeast_1.imageset/Contents.json b/platform/macos/app/Assets.xcassets/Radar/southeast_1.imageset/Contents.json
new file mode 100644
index 0000000000..a6a031ae2b
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/Radar/southeast_1.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "southeast_radar_1.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/platform/macos/app/Assets.xcassets/Radar/southeast_1.imageset/southeast_radar_1.png b/platform/macos/app/Assets.xcassets/Radar/southeast_1.imageset/southeast_radar_1.png
new file mode 100644
index 0000000000..ed09fffbe1
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/Radar/southeast_1.imageset/southeast_radar_1.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/Radar/southeast_2.imageset/Contents.json b/platform/macos/app/Assets.xcassets/Radar/southeast_2.imageset/Contents.json
new file mode 100644
index 0000000000..d607dda298
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/Radar/southeast_2.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "southeast_radar_2.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/platform/macos/app/Assets.xcassets/Radar/southeast_2.imageset/southeast_radar_2.png b/platform/macos/app/Assets.xcassets/Radar/southeast_2.imageset/southeast_radar_2.png
new file mode 100644
index 0000000000..fee630f863
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/Radar/southeast_2.imageset/southeast_radar_2.png
Binary files differ
diff --git a/platform/macos/app/Assets.xcassets/Radar/southeast_3.imageset/Contents.json b/platform/macos/app/Assets.xcassets/Radar/southeast_3.imageset/Contents.json
new file mode 100644
index 0000000000..9a110068a1
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/Radar/southeast_3.imageset/Contents.json
@@ -0,0 +1,21 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "filename" : "southeast_radar_3.png",
+ "scale" : "1x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "2x"
+ },
+ {
+ "idiom" : "universal",
+ "scale" : "3x"
+ }
+ ],
+ "info" : {
+ "version" : 1,
+ "author" : "xcode"
+ }
+} \ No newline at end of file
diff --git a/platform/macos/app/Assets.xcassets/Radar/southeast_3.imageset/southeast_radar_3.png b/platform/macos/app/Assets.xcassets/Radar/southeast_3.imageset/southeast_radar_3.png
new file mode 100644
index 0000000000..c4c7146afa
--- /dev/null
+++ b/platform/macos/app/Assets.xcassets/Radar/southeast_3.imageset/southeast_radar_3.png
Binary files differ
diff --git a/platform/macos/app/Base.lproj/MainMenu.xib b/platform/macos/app/Base.lproj/MainMenu.xib
index 20a4f65b3f..9a8cf05c16 100644
--- a/platform/macos/app/Base.lproj/MainMenu.xib
+++ b/platform/macos/app/Base.lproj/MainMenu.xib
@@ -554,6 +554,12 @@
<action selector="insertCustomStyleLayer:" target="-1" id="LE5-lz-kx3"/>
</connections>
</menuItem>
+ <menuItem title="Add Animated Image Source" id="tjA-fT-GbA">
+ <modifierMask key="keyEquivalentModifierMask"/>
+ <connections>
+ <action selector="addAnimatedImageSource:" target="-1" id="TuN-Pa-hTG"/>
+ </connections>
+ </menuItem>
<menuItem title="Show All Annnotations" keyEquivalent="A" id="yMj-uM-8SN">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
diff --git a/platform/macos/app/MapDocument.m b/platform/macos/app/MapDocument.m
index 59844d363e..94bf18dea1 100644
--- a/platform/macos/app/MapDocument.m
+++ b/platform/macos/app/MapDocument.m
@@ -617,6 +617,37 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
cos(angle) * 20);
}
+- (IBAction) addAnimatedImageSource:(id)sender {
+
+ MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:@"southeast_0"];
+
+ MGLCoordinateBounds bounds = { {22.551103322318994, -90.24006072802854}, {36.928147474567794, -75.1441643681673} };
+ MGLImageSource *imageSource = [[MGLImageSource alloc] initWithIdentifier:@"animated-radar-source" coordinateQuad:MGLCoordinateQuadFromCoordinateBounds(bounds) image:image];
+ [self.mapView.style addSource:imageSource];
+
+ MGLRasterStyleLayer * imageLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"animated-radar-layer" source:imageSource];
+ [self.mapView.style addLayer:imageLayer];
+
+ [NSTimer scheduledTimerWithTimeInterval:1.0
+ target:self
+ selector:@selector(updateAnimatedImageSource:)
+ userInfo:imageSource
+ repeats:YES];
+}
+
+
+- (void)updateAnimatedImageSource:(NSTimer *)timer {
+ static int radarSuffix = 0;
+ MGLImageSource *imageSource = (MGLImageSource *)timer.userInfo;
+
+ MGLImage *image = [[NSBundle bundleForClass:[self class]] imageForResource:[NSString stringWithFormat:@"southeast_%d", radarSuffix++]];
+ [imageSource setValue:image forKey:@"image"];
+
+ if(radarSuffix > 3) {
+ radarSuffix = 0 ;
+ }
+}
+
- (IBAction)insertCustomStyleLayer:(id)sender {
[self.undoManager registerUndoWithTarget:self handler:^(id _Nonnull target) {
[self removeCustomStyleLayer:sender];
@@ -695,40 +726,58 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
MGLTransition transition = { .duration = 5, .delay = 1 };
self.mapView.style.transition = transition;
- MGLFillStyleLayer *fillStyleLayer = (MGLFillStyleLayer *)[self.mapView.style layerWithIdentifier:@"water"];
-
+ MGLStyleLayer *waterLayer = [self.mapView.style layerWithIdentifier:@"water"];
MGLStyleValue *colorFunction = [MGLStyleValue<NSColor *> valueWithInterpolationMode:MGLInterpolationModeExponential cameraStops:@{
@0.0: [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor redColor]],
@10.0: [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor yellowColor]],
@20.0: [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor blackColor]],
} options:nil];
- fillStyleLayer.fillColor = colorFunction;
+
+ if ([waterLayer respondsToSelector:@selector(fillColor)]) {
+ [waterLayer setValue:colorFunction forKey:@"fillColor"];
+ } else if ([waterLayer respondsToSelector:@selector(lineColor)]) {
+ [waterLayer setValue:colorFunction forKey:@"lineColor"];
+ }
NSString *filePath = [[NSBundle bundleForClass:self.class] pathForResource:@"amsterdam" ofType:@"geojson"];
NSURL *geoJSONURL = [NSURL fileURLWithPath:filePath];
MGLShapeSource *source = [[MGLShapeSource alloc] initWithIdentifier:@"ams" URL:geoJSONURL options:nil];
[self.mapView.style addSource:source];
- MGLFillStyleLayer *fillLayer = [[MGLFillStyleLayer alloc] initWithIdentifier:@"test" source:source];
- fillLayer.fillColor = [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor greenColor]];
- fillLayer.predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"type", @"park"];
- [self.mapView.style addLayer:fillLayer];
+ MGLCircleStyleLayer *circleLayer = [[MGLCircleStyleLayer alloc] initWithIdentifier:@"test" source:source];
+ circleLayer.circleColor = [MGLStyleValue<NSColor *> valueWithRawValue:[NSColor greenColor]];
+ circleLayer.circleRadius = [MGLStyleValue<NSNumber *> valueWithRawValue:[NSNumber numberWithInteger:40]];
+// fillLayer.predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"type", @"park"];
+ [self.mapView.style addLayer:circleLayer];
+ MGLSource *streetsSource = [self.mapView.style sourceWithIdentifier:@"composite"];
+ if (streetsSource) {
NSImage *image = [NSImage imageNamed:NSImageNameIChatTheaterTemplate];
[self.mapView.style setImage:image forName:NSImageNameIChatTheaterTemplate];
- MGLSource *streetsSource = [self.mapView.style sourceWithIdentifier:@"composite"];
- MGLSymbolStyleLayer *theaterLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"theaters" source:streetsSource];
- theaterLayer.sourceLayerIdentifier = @"poi_label";
- theaterLayer.predicate = [NSPredicate predicateWithFormat:@"maki == 'theatre'"];
- theaterLayer.iconImageName = [MGLStyleValue valueWithRawValue:NSImageNameIChatTheaterTemplate];
- theaterLayer.iconScale = [MGLStyleValue valueWithRawValue:@2];
- theaterLayer.iconColor = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential cameraStops:@{
- @16.0: [MGLStyleValue valueWithRawValue:[NSColor redColor]],
- @18.0: [MGLStyleValue valueWithRawValue:[NSColor yellowColor]],
- @20.0: [MGLStyleValue valueWithRawValue:[NSColor blackColor]],
- } options:nil];
- [self.mapView.style addLayer:theaterLayer];
+ MGLSymbolStyleLayer *theaterLayer = [[MGLSymbolStyleLayer alloc] initWithIdentifier:@"theaters" source:streetsSource];
+ theaterLayer.sourceLayerIdentifier = @"poi_label";
+ theaterLayer.predicate = [NSPredicate predicateWithFormat:@"maki == 'theatre'"];
+ theaterLayer.iconImageName = [MGLStyleValue valueWithRawValue:NSImageNameIChatTheaterTemplate];
+ theaterLayer.iconScale = [MGLStyleValue valueWithRawValue:@2];
+ theaterLayer.iconColor = [MGLStyleValue valueWithInterpolationMode:MGLInterpolationModeExponential cameraStops:@{
+ @16.0: [MGLStyleValue valueWithRawValue:[NSColor redColor]],
+ @18.0: [MGLStyleValue valueWithRawValue:[NSColor yellowColor]],
+ @20.0: [MGLStyleValue valueWithRawValue:[NSColor blackColor]],
+ } options:nil];
+ [self.mapView.style addLayer:theaterLayer];
+ }
+
+ NSURL *imageURL = [NSURL URLWithString:@"https://www.mapbox.com/mapbox-gl-js/assets/radar.gif"];
+ MGLCoordinateQuad quad = { {46.437, -80.425},
+ {37.936, -80.425},
+ {37.936, -71.516},
+ {46.437, -71.516} };
+ MGLImageSource *imageSource = [[MGLImageSource alloc] initWithIdentifier:@"radar-source" coordinateQuad:quad URL:imageURL];
+ [self.mapView.style addSource:imageSource];
+
+ MGLRasterStyleLayer * imageLayer = [[MGLRasterStyleLayer alloc] initWithIdentifier:@"radar-layer" source:imageSource];
+ [self.mapView.style addLayer:imageLayer];
}
- (IBAction)dropPin:(NSMenuItem *)sender {
@@ -937,6 +986,9 @@ NS_ARRAY_OF(id <MGLAnnotation>) *MBXFlattenedShapes(NS_ARRAY_OF(id <MGLAnnotatio
if (menuItem.action == @selector(drawAnimatedAnnotation:)) {
return !_isShowingAnimatedAnnotation;
}
+ if (menuItem.action == @selector(addAnimatedImageSource:)) {
+ return YES;
+ }
if (menuItem.action == @selector(insertCustomStyleLayer:)) {
return ![self.mapView.style layerWithIdentifier:@"mbx-custom"];
}
diff --git a/platform/macos/docs/guides/For Style Authors.md b/platform/macos/docs/guides/For Style Authors.md
index b9163582b4..3cacc81376 100644
--- a/platform/macos/docs/guides/For Style Authors.md
+++ b/platform/macos/docs/guides/For Style Authors.md
@@ -96,7 +96,6 @@ the following terms for concepts defined in the style specification:
In the style specification | In the SDK
---------------------------|---------
-class | style class
filter | predicate
function type | interpolation mode
id | identifier
@@ -117,8 +116,9 @@ In style JSON | In the SDK
`geojson` | `MGLShapeSource`
`raster` | `MGLRasterSource`
`vector` | `MGLVectorSource`
+`image` | `MGLImageSource`
-`canvas`, `image`, and `video` sources are not supported.
+`canvas` and `video` sources are not supported.
### Tile sources
@@ -159,6 +159,12 @@ To create a shape source from local GeoJSON data, first
[convert the GeoJSON data into a shape](working-with-geojson-data.html#converting-geojson-data-into-shape-objects),
then use the `-[MGLShapeSource initWithIdentifier:shape:options:]` method.
+### Image sources
+
+Image sources accept a non-axis aligned quadrilateral as their geographic coordinates.
+These coordinates, in `MGLCoordinateQuad`, are described in counterclockwise order,
+in contrast to the clockwise order defined in the style specification.
+
## Configuring the map content’s appearance
Each layer defined by the style JSON file is represented at runtime by a style
diff --git a/platform/macos/macos.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj
index 564d81afb2..723bbc6f4b 100644
--- a/platform/macos/macos.xcodeproj/project.pbxproj
+++ b/platform/macos/macos.xcodeproj/project.pbxproj
@@ -7,6 +7,9 @@
objects = {
/* Begin PBXBuildFile section */
+ 0721493F1EE200E900085505 /* MGLImageSource.h in Headers */ = {isa = PBXBuildFile; fileRef = 07A019EB1ED662D800ACD43E /* MGLImageSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 07A019EF1ED665CD00ACD43E /* MGLImageSource.mm in Sources */ = {isa = PBXBuildFile; fileRef = 07A019EC1ED662D800ACD43E /* MGLImageSource.mm */; };
+ 07BA4CAC1EE21887004528F5 /* MGLImageSourceTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 07BA4CAB1EE21887004528F5 /* MGLImageSourceTests.m */; };
1753ED401E53CE6100A9FD90 /* MGLConversion.h in Headers */ = {isa = PBXBuildFile; fileRef = 1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */; };
1F7454A31ECFB00300021D39 /* MGLLight_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454A01ECFB00300021D39 /* MGLLight_Private.h */; };
1F7454A41ECFB00300021D39 /* MGLLight.h in Headers */ = {isa = PBXBuildFile; fileRef = 1F7454A11ECFB00300021D39 /* MGLLight.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -271,6 +274,9 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
+ 07A019EB1ED662D800ACD43E /* MGLImageSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLImageSource.h; sourceTree = "<group>"; };
+ 07A019EC1ED662D800ACD43E /* MGLImageSource.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLImageSource.mm; sourceTree = "<group>"; };
+ 07BA4CAB1EE21887004528F5 /* MGLImageSourceTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLImageSourceTests.m; sourceTree = "<group>"; };
1753ED3F1E53CE5200A9FD90 /* MGLConversion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLConversion.h; sourceTree = "<group>"; };
1F7454A01ECFB00300021D39 /* MGLLight_Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight_Private.h; sourceTree = "<group>"; };
1F7454A11ECFB00300021D39 /* MGLLight.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLLight.h; sourceTree = "<group>"; };
@@ -664,6 +670,8 @@
DA8F25951D51CAC70010E6B5 /* MGLVectorSource.h */,
DA7DC9801DED5F5C0027472F /* MGLVectorSource_Private.h */,
DA8F25961D51CAC70010E6B5 /* MGLVectorSource.mm */,
+ 07A019EB1ED662D800ACD43E /* MGLImageSource.h */,
+ 07A019EC1ED662D800ACD43E /* MGLImageSource.mm */,
);
name = Sources;
sourceTree = "<group>";
@@ -774,6 +782,7 @@
DA87A9961DC9D88400810D09 /* MGLShapeSourceTests.mm */,
DA87A9971DC9D88400810D09 /* MGLTileSetTests.mm */,
920A3E581E6F859D00C16EFC /* MGLSourceQueryTests.m */,
+ 07BA4CAB1EE21887004528F5 /* MGLImageSourceTests.m */,
);
name = Sources;
sourceTree = "<group>";
@@ -1166,6 +1175,7 @@
DAE6C3B41CC31EF300DB3429 /* MGLCompassCell.h in Headers */,
DA87A99C1DC9D8DD00810D09 /* MGLShapeSource_Private.h in Headers */,
3537CA741D3F93A600380318 /* MGLStyle_Private.h in Headers */,
+ 0721493F1EE200E900085505 /* MGLImageSource.h in Headers */,
DA8F259A1D51CAD00010E6B5 /* MGLSource_Private.h in Headers */,
DA8F25931D51CA750010E6B5 /* MGLSymbolStyleLayer.h in Headers */,
DAE6C3B91CC31EF300DB3429 /* MGLOpenGLLayer.h in Headers */,
@@ -1386,6 +1396,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
+ 07A019EF1ED665CD00ACD43E /* MGLImageSource.mm in Sources */,
40ABDB561DB0022100372083 /* NSImage+MGLAdditions.mm in Sources */,
DAE6C3901CC31E2A00DB3429 /* MGLPointAnnotation.mm in Sources */,
DAE6C3981CC31E2A00DB3429 /* NSBundle+MGLAdditions.m in Sources */,
@@ -1478,6 +1489,7 @@
DA87A9A71DCACC5000810D09 /* MGLBackgroundStyleLayerTests.mm in Sources */,
DAA999011E9F5EC5002E6EA6 /* MGLFillExtrusionStyleLayerTests.mm in Sources */,
DA29875A1E1A4290002299F5 /* MGLDocumentationExampleTests.swift in Sources */,
+ 07BA4CAC1EE21887004528F5 /* MGLImageSourceTests.m in Sources */,
DAE6C3D31CC34C9900DB3429 /* MGLOfflinePackTests.m in Sources */,
DA87A9A51DCACC5000810D09 /* MGLLineStyleLayerTests.mm in Sources */,
DA87A9A31DCACC5000810D09 /* MGLRasterStyleLayerTests.mm in Sources */,
diff --git a/platform/macos/src/MGLMapView.h b/platform/macos/src/MGLMapView.h
index fb715a506d..6bfdcfd100 100644
--- a/platform/macos/src/MGLMapView.h
+++ b/platform/macos/src/MGLMapView.h
@@ -730,6 +730,15 @@ MGL_EXPORT IB_DESIGNABLE
#pragma mark Overlaying the Map
/**
+ The complete list of overlays associated with the receiver. (read-only)
+
+ The objects in this array must adopt the `MGLOverlay` protocol. If no
+ overlays are associated with the map view, the value of this property is
+ empty array.
+ */
+@property (nonatomic, readonly, nonnull) NS_ARRAY_OF(id <MGLOverlay>) *overlays;
+
+/**
Adds a single overlay to the map.
To remove an overlay from a map, use the `-removeOverlay:` method.
diff --git a/platform/macos/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm
index 1908a46cf9..70198c6432 100644
--- a/platform/macos/src/MGLMapView.mm
+++ b/platform/macos/src/MGLMapView.mm
@@ -20,9 +20,11 @@
#import "MGLPolyline.h"
#import "MGLAnnotationImage.h"
#import "MGLMapViewDelegate.h"
+#import "MGLImageSource.h"
#import <mbgl/map/map.hpp>
#import <mbgl/map/view.hpp>
+#import <mbgl/style/style.hpp>
#import <mbgl/annotation/annotation.hpp>
#import <mbgl/map/camera.hpp>
#import <mbgl/storage/reachability.h>
@@ -238,7 +240,7 @@ public:
// If the Style URL inspectable was not set, make sure to go through
// -setStyleURL: to load the default style.
- if (_mbglMap->getStyleURL().empty()) {
+ if (_mbglMap->getStyle().getURL().empty()) {
self.styleURL = nil;
}
}
@@ -269,7 +271,6 @@ public:
_mbglThreadPool = mbgl::sharedThreadPool();
_mbglMap = new mbgl::Map(*_mbglView, self.size, [NSScreen mainScreen].backingScaleFactor, *mbglFileSource, *_mbglThreadPool, mbgl::MapMode::Continuous, mbgl::GLContextMode::Unique, mbgl::ConstrainMode::None, mbgl::ViewportMode::Default);
- [self validateTileCacheSize];
// Install the OpenGL layer. Interface Builder’s synchronous drawing means
// we can’t display a map, so don’t even bother to have a map layer.
@@ -606,7 +607,7 @@ public:
}
- (nonnull NSURL *)styleURL {
- NSString *styleURLString = @(_mbglMap->getStyleURL().c_str()).mgl_stringOrNilIfEmpty;
+ NSString *styleURLString = @(_mbglMap->getStyle().getURL().c_str()).mgl_stringOrNilIfEmpty;
return styleURLString ? [NSURL URLWithString:styleURLString] : [MGLStyle streetsStyleURLWithVersion:MGLStyleDefaultVersion];
}
@@ -628,12 +629,12 @@ public:
styleURL = styleURL.mgl_URLByStandardizingScheme;
self.style = nil;
- _mbglMap->setStyleURL(styleURL.absoluteString.UTF8String);
+ _mbglMap->getStyle().loadURL(styleURL.absoluteString.UTF8String);
}
- (IBAction)reloadStyle:(__unused id)sender {
NSURL *styleURL = self.styleURL;
- _mbglMap->setStyleURL("");
+ _mbglMap->getStyle().loadURL("");
self.styleURL = styleURL;
}
@@ -685,9 +686,6 @@ public:
- (void)setFrame:(NSRect)frame {
super.frame = frame;
- if (!NSEqualRects(frame, self.frame)) {
- [self validateTileCacheSize];
- }
if (!_isTargetingInterfaceBuilder) {
_mbglMap->setSize(self.size);
}
@@ -787,21 +785,6 @@ public:
}
}
-- (void)validateTileCacheSize {
- if (!_mbglMap) {
- return;
- }
-
- CGFloat zoomFactor = self.maximumZoomLevel - self.minimumZoomLevel + 1;
- CGFloat cpuFactor = [NSProcessInfo processInfo].processorCount;
- CGFloat memoryFactor = (CGFloat)[NSProcessInfo processInfo].physicalMemory / 1000 / 1000 / 1000;
- CGFloat sizeFactor = (NSWidth(self.bounds) / mbgl::util::tileSize) * (NSHeight(self.bounds) / mbgl::util::tileSize);
-
- NSUInteger cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5;
-
- _mbglMap->setSourceTileCacheSize(cacheSize);
-}
-
- (void)setNeedsGLDisplay {
MGLAssertIsMainThread();
@@ -936,20 +919,23 @@ public:
return;
}
- self.style = [[MGLStyle alloc] initWithMapView:self];
+ self.style = [[MGLStyle alloc] initWithRawStyle:&_mbglMap->getStyle() mapView:self];
if ([self.delegate respondsToSelector:@selector(mapView:didFinishLoadingStyle:)])
{
[self.delegate mapView:self didFinishLoadingStyle:self.style];
}
}
-- (void)sourceDidChange {
+- (void)sourceDidChange:(MGLSource *)source {
if (!_mbglMap) {
return;
}
-
- [self installAttributionView];
+ // Attribution only applies to tiled sources
+ if ([source isKindOfClass:[MGLTileSource class]]) {
+ [self installAttributionView];
+ }
self.needsUpdateConstraints = YES;
+ self.needsDisplay = YES;
}
#pragma mark Printing
@@ -1056,13 +1042,11 @@ public:
- (void)setMinimumZoomLevel:(double)minimumZoomLevel
{
_mbglMap->setMinZoom(minimumZoomLevel);
- [self validateTileCacheSize];
}
- (void)setMaximumZoomLevel:(double)maximumZoomLevel
{
_mbglMap->setMaxZoom(maximumZoomLevel);
- [self validateTileCacheSize];
}
- (double)maximumZoomLevel {
@@ -1954,7 +1938,7 @@ public:
return;
}
- _mbglMap->addAnnotationImage(iconIdentifier.UTF8String, annotationImage.image.mgl_styleImage);
+ _mbglMap->addAnnotationImage([annotationImage.image mgl_styleImageWithIdentifier:iconIdentifier]);
// Create a slop area with a “radius” equal to the annotation image’s entire
// size, allowing the eventual click to be on any point within this image.
@@ -2418,6 +2402,22 @@ public:
#pragma mark Overlays
+- (nonnull NS_ARRAY_OF(id <MGLOverlay>) *)overlays
+{
+ if (self.annotations == nil) { return @[]; }
+
+ NS_MUTABLE_ARRAY_OF(id <MGLOverlay>) *mutableOverlays = [NSMutableArray array];
+
+ [self.annotations enumerateObjectsUsingBlock:^(id<MGLAnnotation> _Nonnull annotation, NSUInteger idx, BOOL * _Nonnull stop) {
+ if ([annotation conformsToProtocol:@protocol(MGLOverlay)])
+ {
+ [mutableOverlays addObject:(id<MGLOverlay>)annotation];
+ }
+ }];
+
+ return [NSArray arrayWithArray:mutableOverlays];
+}
+
- (void)addOverlay:(id <MGLOverlay>)overlay {
[self addOverlays:@[overlay]];
}
@@ -2831,8 +2831,10 @@ public:
[nativeView mapViewDidFinishLoadingStyle];
}
- void onSourceChanged(mbgl::style::Source&) override {
- [nativeView sourceDidChange];
+ void onSourceChanged(mbgl::style::Source& source) override {
+ NSString *identifier = @(source.getID().c_str());
+ MGLSource * nativeSource = [nativeView.style sourceWithIdentifier:identifier];
+ [nativeView sourceDidChange:nativeSource];
}
mbgl::gl::ProcAddress initializeExtension(const char* name) override {
@@ -2872,12 +2874,12 @@ public:
void updateAssumedState() override {
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &fbo);
assumeFramebufferBinding(fbo);
- assumeViewportSize(nativeView.framebufferSize);
+ assumeViewport(0, 0, nativeView.framebufferSize);
}
void bind() override {
setFramebufferBinding(fbo);
- setViewportSize(nativeView.framebufferSize);
+ setViewport(0, 0, nativeView.framebufferSize);
}
mbgl::PremultipliedImage readStillImage() {
diff --git a/platform/macos/src/Mapbox.h b/platform/macos/src/Mapbox.h
index 0f47dace70..e4ad258b6e 100644
--- a/platform/macos/src/Mapbox.h
+++ b/platform/macos/src/Mapbox.h
@@ -50,6 +50,7 @@ FOUNDATION_EXPORT MGL_EXPORT const unsigned char MapboxVersionString[];
#import "MGLVectorSource.h"
#import "MGLShapeSource.h"
#import "MGLRasterSource.h"
+#import "MGLImageSource.h"
#import "MGLTilePyramidOfflineRegion.h"
#import "MGLTypes.h"
#import "NSValue+MGLAdditions.h"
diff --git a/platform/macos/src/NSImage+MGLAdditions.h b/platform/macos/src/NSImage+MGLAdditions.h
index d3cc80615b..c08fc57bea 100644
--- a/platform/macos/src/NSImage+MGLAdditions.h
+++ b/platform/macos/src/NSImage+MGLAdditions.h
@@ -10,7 +10,9 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable instancetype)initWithMGLStyleImage:(const mbgl::style::Image *)image;
-- (std::unique_ptr<mbgl::style::Image>)mgl_styleImage;
+- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier;
+
+- (mbgl::PremultipliedImage) mgl_premultipliedImage;
@end
diff --git a/platform/macos/src/NSImage+MGLAdditions.mm b/platform/macos/src/NSImage+MGLAdditions.mm
index 91c4f7bf66..6abe53e9ae 100644
--- a/platform/macos/src/NSImage+MGLAdditions.mm
+++ b/platform/macos/src/NSImage+MGLAdditions.mm
@@ -16,21 +16,32 @@
}
- (nullable instancetype)initWithMGLStyleImage:(const mbgl::style::Image *)styleImage {
- CGImageRef image = CGImageFromMGLPremultipliedImage(styleImage->image.clone());
+ CGImageRef image = CGImageFromMGLPremultipliedImage(styleImage->getImage().clone());
if (!image) {
return nil;
}
NSBitmapImageRep *rep = [[NSBitmapImageRep alloc] initWithCGImage:image];
CGImageRelease(image);
- if (self = [self initWithSize:NSMakeSize(styleImage->getWidth(), styleImage->getHeight())]) {
+ CGFloat w = styleImage->getImage().size.width / styleImage->getPixelRatio();
+ CGFloat h = styleImage->getImage().size.height / styleImage->getPixelRatio();
+ if (self = [self initWithSize:NSMakeSize(w, h)]) {
[self addRepresentation:rep];
- [self setTemplate:styleImage->sdf];
+ [self setTemplate:styleImage->isSdf()];
}
return self;
}
-- (std::unique_ptr<mbgl::style::Image>)mgl_styleImage {
+- (std::unique_ptr<mbgl::style::Image>)mgl_styleImageWithIdentifier:(NSString *)identifier {
+ mbgl::PremultipliedImage cPremultipliedImage = self.mgl_premultipliedImage;
+ auto imageWidth = cPremultipliedImage.size.width;
+ return std::make_unique<mbgl::style::Image>([identifier UTF8String],
+ std::move(cPremultipliedImage),
+ (float)(imageWidth / self.size.width),
+ [self isTemplate]);
+}
+
+- (mbgl::PremultipliedImage)mgl_premultipliedImage {
// Create a bitmap image representation from the image, respecting backing
// scale factor and any resizing done on the image at runtime.
// http://www.cocoabuilder.com/archive/cocoa/82430-nsimage-getting-raw-bitmap-data.html#82431
@@ -40,9 +51,6 @@
mbgl::PremultipliedImage cPremultipliedImage({ static_cast<uint32_t>(rep.pixelsWide), static_cast<uint32_t>(rep.pixelsHigh) });
std::copy(rep.bitmapData, rep.bitmapData + cPremultipliedImage.bytes(), cPremultipliedImage.data.get());
- return std::make_unique<mbgl::style::Image>(std::move(cPremultipliedImage),
- (float)(rep.pixelsWide / self.size.width),
- [self isTemplate]);
+ return cPremultipliedImage;
}
-
@end
diff --git a/platform/node/CHANGELOG.md b/platform/node/CHANGELOG.md
index e77ceff31f..dee001c426 100644
--- a/platform/node/CHANGELOG.md
+++ b/platform/node/CHANGELOG.md
@@ -1,3 +1,16 @@
+# 3.5.4 - June 6, 2017
+- Add support for ImageSource [#8968](https://github.com/mapbox/mapbox-gl-native/pull/8968)
+- Fixed an issue with `map.addImage()` which would cause added images to randomly be replaced with images found the style's sprite sheet ([#9119](https://github.com/mapbox/mapbox-gl-native/pull/9119))
+
+# 3.5.3 - May 30, 2017
+
+- Fixed a regression around `line-dasharrary` and `fill-pattern` that caused these properties to sometimes not render correctly ([#9130](https://github.com/mapbox/mapbox-gl-native/pull/9130))
+
+# 3.5.2 - May 18, 2017
+
+- Fixed a memory leak ([#8884](https://github.com/mapbox/mapbox-gl-native/pull/9035))
+
+
# 3.5.1 - May 8, 2017
- Adds Node v6 binaries. **Note, Node v4 binaries will be removed on August 1st.** ([#8884](https://github.com/mapbox/mapbox-gl-native/pull/8884))
diff --git a/platform/node/README.md b/platform/node/README.md
index 545d87861f..d19b2a9343 100644
--- a/platform/node/README.md
+++ b/platform/node/README.md
@@ -1,6 +1,6 @@
# node-mapbox-gl-native
-[![NPM](https://nodei.co/npm/mapbox-gl-native.png)](https://npmjs.org/package/mapbox-gl-native)
+[![NPM](https://nodei.co/npm/@mapbox/mapbox-gl-native.png)](https://npmjs.org/package/@mapbox/mapbox-gl-native)
## Installing
@@ -14,7 +14,7 @@ By default, installs binaries. On these platforms no additional dependencies are
Run:
```
-npm install mapbox-gl-native
+npm install @mapbox/mapbox-gl-native
```
Other platforms will fall back to a source compile with `make node`; see INSTALL.md in the repository root directory for prequisites.
@@ -31,7 +31,7 @@ npm run test-suite
```js
var fs = require('fs');
var path = require('path');
-var mbgl = require('mapbox-gl-native');
+var mbgl = require('@mapbox/mapbox-gl-native');
var sharp = require('sharp');
var options = {
diff --git a/platform/node/scripts/after_success.sh b/platform/node/scripts/after_success.sh
index ae34446927..a050dbce07 100755
--- a/platform/node/scripts/after_success.sh
+++ b/platform/node/scripts/after_success.sh
@@ -3,7 +3,7 @@
set -e
set -o pipefail
-if [[ -n ${PUBLISH:-} ]]; then
+if [[ "${PUBLISH:-}" == "true" ]]; then
if [[ "${BUILDTYPE}" == "Release" ]]; then
./node_modules/.bin/node-pre-gyp package publish info
else
diff --git a/platform/node/src/node_conversion.hpp b/platform/node/src/node_conversion.hpp
index 22daedef6a..d266745548 100644
--- a/platform/node/src/node_conversion.hpp
+++ b/platform/node/src/node_conversion.hpp
@@ -82,6 +82,14 @@ inline optional<float> toNumber(v8::Local<v8::Value> value) {
return value->NumberValue();
}
+inline optional<double> toDouble(v8::Local<v8::Value> value) {
+ Nan::HandleScope scope;
+ if (!value->IsNumber()) {
+ return {};
+ }
+ return value->NumberValue();
+}
+
inline optional<std::string> toString(v8::Local<v8::Value> value) {
Nan::HandleScope scope;
if (!value->IsString()) {
diff --git a/platform/node/src/node_map.cpp b/platform/node/src/node_map.cpp
index 1c8bf6d1d2..9ba88193c9 100644
--- a/platform/node/src/node_map.cpp
+++ b/platform/node/src/node_map.cpp
@@ -9,6 +9,7 @@
#include <mbgl/style/conversion/source.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/filter.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/image.hpp>
#include <mbgl/map/backend_scope.hpp>
#include <mbgl/map/query.hpp>
@@ -60,7 +61,6 @@ void NodeMap::Init(v8::Local<v8::Object> target) {
Nan::SetPrototypeMethod(tpl, "release", Release);
Nan::SetPrototypeMethod(tpl, "cancel", Cancel);
- Nan::SetPrototypeMethod(tpl, "addClass", AddClass);
Nan::SetPrototypeMethod(tpl, "addSource", AddSource);
Nan::SetPrototypeMethod(tpl, "addLayer", AddLayer);
Nan::SetPrototypeMethod(tpl, "removeLayer", RemoveLayer);
@@ -214,7 +214,7 @@ void NodeMap::Load(const Nan::FunctionCallbackInfo<v8::Value>& info) {
}
try {
- nodeMap->map->setStyleJSON(style);
+ nodeMap->map->getStyle().loadJSON(style);
} catch (const std::exception &ex) {
return Nan::ThrowError(ex.what());
}
@@ -278,7 +278,7 @@ NodeMap::RenderOptions NodeMap::ParseOptions(v8::Local<v8::Object> obj) {
const int length = classes->Length();
options.classes.reserve(length);
for (int i = 0; i < length; i++) {
- options.classes.push_back(std::string { *Nan::Utf8String(Nan::To<v8::String>(Nan::Get(classes, i).ToLocalChecked()).ToLocalChecked()) });
+ options.classes.emplace_back(std::string { *Nan::Utf8String(Nan::To<v8::String>(Nan::Get(classes, i).ToLocalChecked()).ToLocalChecked()) });
}
}
@@ -376,10 +376,6 @@ void NodeMap::startRender(NodeMap::RenderOptions options) {
view = std::make_unique<mbgl::OffscreenView>(backend.getContext(), fbSize);
}
- if (map->getClasses() != options.classes) {
- map->setClasses(options.classes);
- }
-
if (map->getZoom() != options.zoom) {
map->setZoom(options.zoom);
}
@@ -532,7 +528,7 @@ void NodeMap::Cancel(const Nan::FunctionCallbackInfo<v8::Value>& info) {
}
void NodeMap::cancel() {
- auto style = map->getStyleJSON();
+ auto style = map->getStyle().getJSON();
map = std::make_unique<mbgl::Map>(backend, mbgl::Size{ 256, 256 },
pixelRatio, *this, threadpool, mbgl::MapMode::Still);
@@ -540,29 +536,12 @@ void NodeMap::cancel() {
// FIXME: Reload the style after recreating the map. We need to find
// a better way of canceling an ongoing rendering on the core level
// without resetting the map, which is way too expensive.
- map->setStyleJSON(style);
+ map->getStyle().loadJSON(style);
error = std::make_exception_ptr(std::runtime_error("Canceled"));
renderFinished();
}
-void NodeMap::AddClass(const Nan::FunctionCallbackInfo<v8::Value>& info) {
- auto nodeMap = Nan::ObjectWrap::Unwrap<NodeMap>(info.Holder());
- if (!nodeMap->map) return Nan::ThrowError(releasedMessage());
-
- if (info.Length() <= 0 || !info[0]->IsString()) {
- return Nan::ThrowTypeError("First argument must be a string");
- }
-
- try {
- nodeMap->map->addClass(*Nan::Utf8String(info[0]));
- } catch (const std::exception &ex) {
- return Nan::ThrowError(ex.what());
- }
-
- info.GetReturnValue().SetUndefined();
-}
-
void NodeMap::AddSource(const Nan::FunctionCallbackInfo<v8::Value>& info) {
using namespace mbgl::style;
using namespace mbgl::style::conversion;
@@ -585,7 +564,7 @@ void NodeMap::AddSource(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return;
}
- nodeMap->map->addSource(std::move(*source));
+ nodeMap->map->getStyle().addSource(std::move(*source));
}
void NodeMap::AddLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
@@ -606,7 +585,7 @@ void NodeMap::AddLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return;
}
- nodeMap->map->addLayer(std::move(*layer));
+ nodeMap->map->getStyle().addLayer(std::move(*layer));
}
void NodeMap::RemoveLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
@@ -624,7 +603,7 @@ void NodeMap::RemoveLayer(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("First argument must be a string");
}
- nodeMap->map->removeLayer(*Nan::Utf8String(info[0]));
+ nodeMap->map->getStyle().removeLayer(*Nan::Utf8String(info[0]));
}
void NodeMap::AddImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
@@ -660,7 +639,7 @@ void NodeMap::AddImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("width parameter required");
}
- if (!Nan::Get(optionObject, Nan::New("pixelRatio").ToLocalChecked()).ToLocalChecked()->IsUint32()) {
+ if (!Nan::Get(optionObject, Nan::New("pixelRatio").ToLocalChecked()).ToLocalChecked()->IsNumber()) {
return Nan::ThrowTypeError("pixelRatio parameter required");
}
@@ -671,7 +650,7 @@ void NodeMap::AddImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("Max height and width is 1024");
}
- uint32_t pixelRatio = Nan::Get(optionObject, Nan::New("pixelRatio").ToLocalChecked()).ToLocalChecked()->Uint32Value();
+ float pixelRatio = Nan::Get(optionObject, Nan::New("pixelRatio").ToLocalChecked()).ToLocalChecked()->NumberValue();
auto imageBuffer = Nan::To<v8::Object>(info[1]).ToLocalChecked()->ToObject();
char * imageDataBuffer = node::Buffer::Data(imageBuffer);
@@ -686,7 +665,7 @@ void NodeMap::AddImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
mbgl::UnassociatedImage cImage({ imageWidth, imageHeight}, std::move(data));
mbgl::PremultipliedImage cPremultipliedImage = mbgl::util::premultiply(std::move(cImage));
- nodeMap->map->addImage(*Nan::Utf8String(info[0]), std::make_unique<mbgl::style::Image>(std::move(cPremultipliedImage), pixelRatio));
+ nodeMap->map->getStyle().addImage(std::make_unique<mbgl::style::Image>(*Nan::Utf8String(info[0]), std::move(cPremultipliedImage), pixelRatio));
}
void NodeMap::RemoveImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
@@ -704,7 +683,7 @@ void NodeMap::RemoveImage(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("First argument must be a string");
}
- nodeMap->map->removeImage(*Nan::Utf8String(info[0]));
+ nodeMap->map->getStyle().removeImage(*Nan::Utf8String(info[0]));
}
void NodeMap::SetLayoutProperty(const Nan::FunctionCallbackInfo<v8::Value>& info) {
@@ -722,7 +701,7 @@ void NodeMap::SetLayoutProperty(const Nan::FunctionCallbackInfo<v8::Value>& info
return Nan::ThrowTypeError("First argument must be a string");
}
- mbgl::style::Layer* layer = nodeMap->map->getLayer(*Nan::Utf8String(info[0]));
+ mbgl::style::Layer* layer = nodeMap->map->getStyle().getLayer(*Nan::Utf8String(info[0]));
if (!layer) {
return Nan::ThrowTypeError("layer not found");
}
@@ -754,7 +733,7 @@ void NodeMap::SetPaintProperty(const Nan::FunctionCallbackInfo<v8::Value>& info)
return Nan::ThrowTypeError("First argument must be a string");
}
- mbgl::style::Layer* layer = nodeMap->map->getLayer(*Nan::Utf8String(info[0]));
+ mbgl::style::Layer* layer = nodeMap->map->getStyle().getLayer(*Nan::Utf8String(info[0]));
if (!layer) {
return Nan::ThrowTypeError("layer not found");
}
@@ -763,12 +742,7 @@ void NodeMap::SetPaintProperty(const Nan::FunctionCallbackInfo<v8::Value>& info)
return Nan::ThrowTypeError("Second argument must be a string");
}
- mbgl::optional<std::string> klass;
- if (info.Length() == 4 && info[3]->IsString()) {
- klass = std::string(*Nan::Utf8String(info[3]));
- }
-
- mbgl::optional<Error> error = setPaintProperty(*layer, *Nan::Utf8String(info[1]), info[2], klass);
+ mbgl::optional<Error> error = setPaintProperty(*layer, *Nan::Utf8String(info[1]), info[2]);
if (error) {
return Nan::ThrowTypeError(error->message.c_str());
}
@@ -812,7 +786,7 @@ void NodeMap::SetFilter(const Nan::FunctionCallbackInfo<v8::Value>& info) {
return Nan::ThrowTypeError("First argument must be a string");
}
- mbgl::style::Layer* layer = nodeMap->map->getLayer(*Nan::Utf8String(info[0]));
+ mbgl::style::Layer* layer = nodeMap->map->getStyle().getLayer(*Nan::Utf8String(info[0]));
if (!layer) {
return Nan::ThrowTypeError("layer not found");
}
@@ -947,7 +921,7 @@ void NodeMap::QueryRenderedFeatures(const Nan::FunctionCallbackInfo<v8::Value>&
auto layers = layersOption.As<v8::Array>();
std::vector<std::string> layersVec;
for (uint32_t i=0; i < layers->Length(); i++) {
- layersVec.push_back(*Nan::Utf8String(Nan::Get(layers,i).ToLocalChecked()));
+ layersVec.emplace_back(*Nan::Utf8String(Nan::Get(layers,i).ToLocalChecked()));
}
queryOptions.layerIDs = layersVec;
}
diff --git a/platform/node/src/node_map.hpp b/platform/node/src/node_map.hpp
index cdc8f1e51f..7b81ecd894 100644
--- a/platform/node/src/node_map.hpp
+++ b/platform/node/src/node_map.hpp
@@ -42,7 +42,6 @@ public:
static void Render(const Nan::FunctionCallbackInfo<v8::Value>&);
static void Release(const Nan::FunctionCallbackInfo<v8::Value>&);
static void Cancel(const Nan::FunctionCallbackInfo<v8::Value>&);
- static void AddClass(const Nan::FunctionCallbackInfo<v8::Value>&);
static void AddSource(const Nan::FunctionCallbackInfo<v8::Value>&);
static void AddLayer(const Nan::FunctionCallbackInfo<v8::Value>&);
static void RemoveLayer(const Nan::FunctionCallbackInfo<v8::Value>&);
diff --git a/platform/node/test/js/map.test.js b/platform/node/test/js/map.test.js
index 4ab76b937a..04d02d0558 100644
--- a/platform/node/test/js/map.test.js
+++ b/platform/node/test/js/map.test.js
@@ -108,7 +108,6 @@ test('Map', function(t) {
'render',
'release',
'cancel',
- 'addClass',
'addSource',
'addLayer',
'removeLayer',
diff --git a/platform/node/test/suite_implementation.js b/platform/node/test/suite_implementation.js
index 8ac372b7c3..b717ecd2b2 100644
--- a/platform/node/test/suite_implementation.js
+++ b/platform/node/test/suite_implementation.js
@@ -70,7 +70,7 @@ module.exports = function (style, options, callback) {
applyOperations(operations.slice(1), callback);
});
- } else if (operation[0] === 'addImage') {
+ } else if (operation[0] === 'addImage' || operation[0] === 'updateImage') {
var img = PNG.sync.read(fs.readFileSync(path.join(__dirname, '../../../mapbox-gl-js/test/integration', operation[2])));
map.addImage(operation[1], img.data, {
@@ -80,6 +80,11 @@ module.exports = function (style, options, callback) {
});
applyOperations(operations.slice(1), callback);
+
+ } else if (operation[0] === 'setStyle') {
+ map.load(operation[1]);
+ applyOperations(operations.slice(1), callback);
+
} else {
// Ensure that the next `map.render(options)` does not overwrite this change.
if (operation[0] === 'setCenter') {
diff --git a/platform/qt/app/mapwindow.cpp b/platform/qt/app/mapwindow.cpp
index a72faf005e..03ca052ec4 100644
--- a/platform/qt/app/mapwindow.cpp
+++ b/platform/qt/app/mapwindow.cpp
@@ -79,8 +79,6 @@ void MapWindow::changeStyle()
void MapWindow::keyPressEvent(QKeyEvent *ev)
{
- static const qint64 transitionDuration = 300;
-
switch (ev->key()) {
case Qt::Key_S:
changeStyle();
@@ -92,6 +90,9 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
m_sourceAdded = true;
+ // Not in all styles, but will work on streets
+ QString before = "waterway-label";
+
QFile geojson(":source1.geojson");
geojson.open(QIODevice::ReadOnly);
@@ -106,7 +107,7 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
routeCase["id"] = "routeCase";
routeCase["type"] = "line";
routeCase["source"] = "routeSource";
- m_map->addLayer(routeCase);
+ m_map->addLayer(routeCase, before);
m_map->setPaintProperty("routeCase", "line-color", QColor("white"));
m_map->setPaintProperty("routeCase", "line-width", 20.0);
@@ -118,7 +119,7 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
route["id"] = "route";
route["type"] = "line";
route["source"] = "routeSource";
- m_map->addLayer(route);
+ m_map->addLayer(route, before);
m_map->setPaintProperty("route", "line-color", QColor("blue"));
m_map->setPaintProperty("route", "line-width", 8.0);
@@ -277,21 +278,6 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
}
}
break;
- case Qt::Key_4: {
- if (m_styleSourcedAnnotationId.isNull()) {
- QMapbox::Coordinate topLeft = m_map->coordinateForPixel({ 0, 0 });
- QMapbox::Coordinate topRight = m_map->coordinateForPixel({ 0, qreal(size().height()) });
- QMapbox::Coordinate bottomLeft = m_map->coordinateForPixel({ qreal(size().width()), 0 });
- QMapbox::Coordinate bottomRight = m_map->coordinateForPixel({ qreal(size().width()), qreal(size().height()) });
- QMapbox::CoordinatesCollections geometry { { { bottomLeft, bottomRight, topRight, topLeft, bottomLeft } } };
- QMapbox::StyleSourcedAnnotation styleSourced { { QMapbox::ShapeAnnotationGeometry::PolygonType, geometry }, "water" };
- m_styleSourcedAnnotationId = m_map->addAnnotation(QVariant::fromValue<QMapbox::StyleSourcedAnnotation>(styleSourced));
- } else {
- m_map->removeAnnotation(m_styleSourcedAnnotationId.toUInt());
- m_styleSourcedAnnotationId.clear();
- }
- }
- break;
case Qt::Key_5: {
if (m_map->layerExists("circleLayer")) {
m_map->removeLayer("circleLayer");
@@ -319,14 +305,6 @@ void MapWindow::keyPressEvent(QKeyEvent *ev)
case Qt::Key_Tab:
m_map->cycleDebugOptions();
break;
- case Qt::Key_R: {
- m_map->setTransitionOptions(transitionDuration);
- if (m_map->hasClass("night")) {
- m_map->removeClass("night");
- } else {
- m_map->addClass("night");
- }
- } break;
default:
break;
}
diff --git a/platform/qt/app/mapwindow.hpp b/platform/qt/app/mapwindow.hpp
index 6b4b7fd1cc..c484114ec0 100644
--- a/platform/qt/app/mapwindow.hpp
+++ b/platform/qt/app/mapwindow.hpp
@@ -64,7 +64,6 @@ private:
QVariant m_symbolAnnotationId;
QVariant m_lineAnnotationId;
QVariant m_fillAnnotationId;
- QVariant m_styleSourcedAnnotationId;
bool m_sourceAdded = false;
};
diff --git a/platform/qt/include/qmapbox.hpp b/platform/qt/include/qmapbox.hpp
index e69b37108d..1b61d3270f 100644
--- a/platform/qt/include/qmapbox.hpp
+++ b/platform/qt/include/qmapbox.hpp
@@ -62,11 +62,6 @@ struct Q_DECL_EXPORT FillAnnotation {
QVariant outlineColor;
};
-struct Q_DECL_EXPORT StyleSourcedAnnotation {
- ShapeAnnotationGeometry geometry;
- QString layerID;
-};
-
typedef QVariant Annotation;
typedef quint32 AnnotationID;
typedef QList<AnnotationID> AnnotationIDs;
@@ -109,6 +104,5 @@ Q_DECLARE_METATYPE(QMapbox::SymbolAnnotation);
Q_DECLARE_METATYPE(QMapbox::ShapeAnnotationGeometry);
Q_DECLARE_METATYPE(QMapbox::LineAnnotation);
Q_DECLARE_METATYPE(QMapbox::FillAnnotation);
-Q_DECLARE_METATYPE(QMapbox::StyleSourcedAnnotation);
#endif // QMAPBOX_H
diff --git a/platform/qt/include/qmapboxgl.hpp b/platform/qt/include/qmapboxgl.hpp
index 00c5735a93..e2fb283989 100644
--- a/platform/qt/include/qmapboxgl.hpp
+++ b/platform/qt/include/qmapboxgl.hpp
@@ -168,12 +168,6 @@ public:
void setGestureInProgress(bool inProgress);
- void addClass(const QString &);
- void removeClass(const QString &);
- bool hasClass(const QString &) const;
- void setClasses(const QStringList &);
- QStringList getClasses() const;
-
void setTransitionOptions(qint64 duration, qint64 delay = 0);
void addAnnotationIcon(const QString &name, const QImage &sprite);
@@ -183,7 +177,7 @@ public:
void removeAnnotation(QMapbox::AnnotationID);
void setLayoutProperty(const QString &layer, const QString &property, const QVariant &value);
- void setPaintProperty(const QString &layer, const QString &property, const QVariant &value, const QString &klass = QString());
+ void setPaintProperty(const QString &layer, const QString &property, const QVariant &value);
bool isFullyLoaded() const;
@@ -219,8 +213,8 @@ public:
QMapbox::CustomLayerRenderFunction,
QMapbox::CustomLayerDeinitializeFunction,
void* context,
- char* before = NULL);
- void addLayer(const QVariantMap &params);
+ const QString& before = QString());
+ void addLayer(const QVariantMap &params, const QString& before = QString());
bool layerExists(const QString &id);
void removeLayer(const QString &id);
diff --git a/platform/qt/src/qmapbox.cpp b/platform/qt/src/qmapbox.cpp
index 410e114690..751b16f9db 100644
--- a/platform/qt/src/qmapbox.cpp
+++ b/platform/qt/src/qmapbox.cpp
@@ -139,16 +139,6 @@ namespace QMapbox {
*/
/*!
- \class QMapbox::StyleSourcedAnnotation
-
- \inmodule Mapbox Qt SDK
-
- Represents a style sourced annotation object, along with its properties.
-
- A style sourced annotation comprises of its geometry and a layer identifier.
-*/
-
-/*!
\typedef QMapbox::Annotation
Alias for QVariant.
diff --git a/platform/qt/src/qmapboxgl.cpp b/platform/qt/src/qmapboxgl.cpp
index ce7e237afb..f094e2a0ec 100644
--- a/platform/qt/src/qmapboxgl.cpp
+++ b/platform/qt/src/qmapboxgl.cpp
@@ -9,6 +9,7 @@
#include <mbgl/map/map.hpp>
#include <mbgl/map/backend_scope.hpp>
#include <mbgl/math/minmax.hpp>
+#include <mbgl/style/style.hpp>
#include <mbgl/style/conversion.hpp>
#include <mbgl/style/conversion/layer.hpp>
#include <mbgl/style/conversion/source.hpp>
@@ -71,16 +72,6 @@ QThreadStorage<std::shared_ptr<mbgl::util::RunLoop>> loop;
// Conversion helper functions.
-auto fromQStringList(const QStringList &list)
-{
- std::vector<std::string> strings;
- strings.reserve(list.size());
- for (const QString &string : list) {
- strings.push_back(string.toStdString());
- }
- return strings;
-}
-
mbgl::Size sanitizedSize(const QSize& size) {
return mbgl::Size {
mbgl::util::max(0u, static_cast<uint32_t>(size.width())),
@@ -88,7 +79,7 @@ mbgl::Size sanitizedSize(const QSize& size) {
};
};
-std::unique_ptr<mbgl::style::Image> toStyleImage(const QImage &sprite) {
+std::unique_ptr<mbgl::style::Image> toStyleImage(const QString &id, const QImage &sprite) {
const QImage swapped = sprite
.rgbSwapped()
.convertToFormat(QImage::Format_ARGB32_Premultiplied);
@@ -97,6 +88,7 @@ std::unique_ptr<mbgl::style::Image> toStyleImage(const QImage &sprite) {
memcpy(img.get(), swapped.constBits(), swapped.byteCount());
return std::make_unique<mbgl::style::Image>(
+ id.toStdString(),
mbgl::PremultipliedImage(
{ static_cast<uint32_t>(swapped.width()), static_cast<uint32_t>(swapped.height()) },
std::move(img)),
@@ -483,12 +475,12 @@ void QMapboxGL::cycleDebugOptions()
*/
QString QMapboxGL::styleJson() const
{
- return QString::fromStdString(d_ptr->mapObj->getStyleJSON());
+ return QString::fromStdString(d_ptr->mapObj->getStyle().getJSON());
}
void QMapboxGL::setStyleJson(const QString &style)
{
- d_ptr->mapObj->setStyleJSON(style.toStdString());
+ d_ptr->mapObj->getStyle().loadJSON(style.toStdString());
}
/*!
@@ -508,12 +500,12 @@ void QMapboxGL::setStyleJson(const QString &style)
*/
QString QMapboxGL::styleUrl() const
{
- return QString::fromStdString(d_ptr->mapObj->getStyleURL());
+ return QString::fromStdString(d_ptr->mapObj->getStyle().getURL());
}
void QMapboxGL::setStyleUrl(const QString &url)
{
- d_ptr->mapObj->setStyleURL(url.toStdString());
+ d_ptr->mapObj->getStyle().loadURL(url.toStdString());
}
/*!
@@ -752,81 +744,15 @@ void QMapboxGL::setGestureInProgress(bool progress)
}
/*!
- Adds an \a className to the list of active classes. Layers tagged with a certain class
- will only be active when the class is added.
-
- This was removed from the \l {https://www.mapbox.com/mapbox-gl-style-spec/#layer-paint.*}
- {Mapbox style specification} and should no longer be used.
-
- \deprecated
- \sa removeClass()
-*/
-void QMapboxGL::addClass(const QString &className)
-{
- d_ptr->mapObj->addClass(className.toStdString());
-}
-
-/*!
- Removes a \a className.
-
- \deprecated
- \sa addClass()
-*/
-void QMapboxGL::removeClass(const QString &className)
-{
- d_ptr->mapObj->removeClass(className.toStdString());
-}
-
-/*!
- Returns true when \a className is active, false otherwise.
-
- \deprecated
- \sa addClass()
-*/
-bool QMapboxGL::hasClass(const QString &className) const
-{
- return d_ptr->mapObj->hasClass(className.toStdString());
-}
-
-/*!
- Bulk adds a list of \a classNames.
-
- \deprecated
- \sa addClass()
-*/
-void QMapboxGL::setClasses(const QStringList &classNames)
-{
- d_ptr->mapObj->setClasses(fromQStringList(classNames));
-}
-
-/*!
- Returns a list of active classes.
-
- \deprecated
- \sa setClasses()
-*/
-QStringList QMapboxGL::getClasses() const
-{
- QStringList classNames;
- for (const std::string &mbglClass : d_ptr->mapObj->getClasses()) {
- classNames << QString::fromStdString(mbglClass);
- }
- return classNames;
-}
-
-/*!
- Sets the \a duration and \a delay of style class transitions. Style property
- values transition to new values with animation when a new class is set.
-
- \deprecated
- \sa addClass()
+ Sets the \a duration and \a delay of style transitions. Style paint property
+ values transition to new values with animation when they are updated.
*/
void QMapboxGL::setTransitionOptions(qint64 duration, qint64 delay) {
static auto convert = [](qint64 value) -> mbgl::optional<mbgl::Duration> {
return std::chrono::duration_cast<mbgl::Duration>(mbgl::Milliseconds(value));
};
- d_ptr->mapObj->setTransitionOptions(mbgl::style::TransitionOptions{ convert(duration), convert(delay) });
+ d_ptr->mapObj->getStyle().setTransitionOptions(mbgl::style::TransitionOptions{ convert(duration), convert(delay) });
}
mbgl::Annotation asMapboxGLAnnotation(const QMapbox::Annotation & annotation) {
@@ -866,9 +792,6 @@ mbgl::Annotation asMapboxGLAnnotation(const QMapbox::Annotation & annotation) {
} else {
return mbgl::FillAnnotation { asMapboxGLGeometry(fillAnnotation.geometry), fillAnnotation.opacity, { *color }, {} };
}
- } else if (annotation.canConvert<QMapbox::StyleSourcedAnnotation>()) {
- QMapbox::StyleSourcedAnnotation styleSourcedAnnotation = annotation.value<QMapbox::StyleSourcedAnnotation>();
- return mbgl::StyleSourcedAnnotation { asMapboxGLGeometry(styleSourcedAnnotation.geometry), styleSourcedAnnotation.layerID.toStdString() };
}
qWarning() << "Unable to convert annotation:" << annotation;
@@ -944,7 +867,7 @@ void QMapboxGL::setLayoutProperty(const QString& layer, const QString& property,
{
using namespace mbgl::style;
- Layer* layer_ = d_ptr->mapObj->getLayer(layer.toStdString());
+ Layer* layer_ = d_ptr->mapObj->getStyle().getLayer(layer.toStdString());
if (!layer_) {
qWarning() << "Layer not found:" << layer;
return;
@@ -961,9 +884,6 @@ void QMapboxGL::setLayoutProperty(const QString& layer, const QString& property,
as defined by the \l {https://www.mapbox.com/mapbox-gl-style-spec/} {Mapbox style specification}
for paint properties.
- The argument \a styleClass is deprecated and is used for defining the style class for the paint
- property.
-
For paint properties that take a color as \a value, such as \c fill-color, a string such as
\c blue can be passed or a QColor.
@@ -1009,22 +929,17 @@ void QMapboxGL::setLayoutProperty(const QString& layer, const QString& property,
map->setPaintProperty("route","line-dasharray", lineDashArray);
\endcode
*/
-void QMapboxGL::setPaintProperty(const QString& layer, const QString& property, const QVariant& value, const QString& styleClass)
+void QMapboxGL::setPaintProperty(const QString& layer, const QString& property, const QVariant& value)
{
using namespace mbgl::style;
- Layer* layer_ = d_ptr->mapObj->getLayer(layer.toStdString());
+ Layer* layer_ = d_ptr->mapObj->getStyle().getLayer(layer.toStdString());
if (!layer_) {
qWarning() << "Layer not found:" << layer;
return;
}
- mbgl::optional<std::string> klass;
- if (!styleClass.isEmpty()) {
- klass = styleClass.toStdString();
- }
-
- if (conversion::setPaintProperty(*layer_, property.toStdString(), value, klass)) {
+ if (conversion::setPaintProperty(*layer_, property.toStdString(), value)) {
qWarning() << "Error setting paint property:" << layer << "-" << property;
return;
}
@@ -1114,7 +1029,7 @@ void QMapboxGL::addAnnotationIcon(const QString &name, const QImage &icon)
{
if (icon.isNull()) return;
- d_ptr->mapObj->addAnnotationImage(name.toStdString(), toStyleImage(icon));
+ d_ptr->mapObj->addAnnotationImage(toStyleImage(name, icon));
}
/*!
@@ -1267,7 +1182,7 @@ void QMapboxGL::addSource(const QString &id, const QVariantMap &params)
return;
}
- d_ptr->mapObj->addSource(std::move(*source));
+ d_ptr->mapObj->getStyle().addSource(std::move(*source));
}
/*!
@@ -1275,7 +1190,7 @@ void QMapboxGL::addSource(const QString &id, const QVariantMap &params)
*/
bool QMapboxGL::sourceExists(const QString& sourceID)
{
- return !!d_ptr->mapObj->getSource(sourceID.toStdString());
+ return !!d_ptr->mapObj->getStyle().getSource(sourceID.toStdString());
}
/*!
@@ -1289,7 +1204,7 @@ void QMapboxGL::updateSource(const QString &id, const QVariantMap &params)
using namespace mbgl::style;
using namespace mbgl::style::conversion;
- auto source = d_ptr->mapObj->getSource(id.toStdString());
+ auto source = d_ptr->mapObj->getStyle().getSource(id.toStdString());
if (!source) {
addSource(id, params);
return;
@@ -1319,8 +1234,8 @@ void QMapboxGL::removeSource(const QString& id)
{
auto sourceIDStdString = id.toStdString();
- if (d_ptr->mapObj->getSource(sourceIDStdString)) {
- d_ptr->mapObj->removeSource(sourceIDStdString);
+ if (d_ptr->mapObj->getStyle().getSource(sourceIDStdString)) {
+ d_ptr->mapObj->getStyle().removeSource(sourceIDStdString);
}
}
@@ -1337,9 +1252,9 @@ void QMapboxGL::addCustomLayer(const QString &id,
QMapbox::CustomLayerRenderFunction renderFn,
QMapbox::CustomLayerDeinitializeFunction deinitFn,
void *context,
- char *before)
+ const QString& before)
{
- d_ptr->mapObj->addLayer(std::make_unique<mbgl::style::CustomLayer>(
+ d_ptr->mapObj->getStyle().addLayer(std::make_unique<mbgl::style::CustomLayer>(
id.toStdString(),
reinterpret_cast<mbgl::style::CustomLayerInitializeFunction>(initFn),
// This cast is safe as long as both mbgl:: and QMapbox::
@@ -1347,13 +1262,14 @@ void QMapboxGL::addCustomLayer(const QString &id,
(mbgl::style::CustomLayerRenderFunction)renderFn,
reinterpret_cast<mbgl::style::CustomLayerDeinitializeFunction>(deinitFn),
context),
- before ? mbgl::optional<std::string>(before) : mbgl::optional<std::string>());
+ before.isEmpty() ? mbgl::optional<std::string>() : mbgl::optional<std::string>(before.toStdString()));
}
/*!
Adds a style layer to the map as specified by the \l
{https://www.mapbox.com/mapbox-gl-style-spec/#root-layers}{Mapbox style specification} with
- \a params.
+ \a params. The layer will be added under the layer specified by \a before, if specified.
+ Otherwise it will be added as the topmost layer.
This example shows how to add a layer that will be used to show a route line on the map. Note
that nothing will be drawn until we set paint properties using setPaintProperty().
@@ -1369,7 +1285,7 @@ void QMapboxGL::addCustomLayer(const QString &id,
/note The source must exist prior to adding a layer.
*/
-void QMapboxGL::addLayer(const QVariantMap &params)
+void QMapboxGL::addLayer(const QVariantMap &params, const QString& before)
{
using namespace mbgl::style;
using namespace mbgl::style::conversion;
@@ -1381,7 +1297,8 @@ void QMapboxGL::addLayer(const QVariantMap &params)
return;
}
- d_ptr->mapObj->addLayer(std::move(*layer));
+ d_ptr->mapObj->getStyle().addLayer(std::move(*layer),
+ before.isEmpty() ? mbgl::optional<std::string>() : mbgl::optional<std::string>(before.toStdString()));
}
/*!
@@ -1389,7 +1306,7 @@ void QMapboxGL::addLayer(const QVariantMap &params)
*/
bool QMapboxGL::layerExists(const QString& id)
{
- return !!d_ptr->mapObj->getLayer(id.toStdString());
+ return !!d_ptr->mapObj->getStyle().getLayer(id.toStdString());
}
/*!
@@ -1397,7 +1314,7 @@ bool QMapboxGL::layerExists(const QString& id)
*/
void QMapboxGL::removeLayer(const QString& id)
{
- d_ptr->mapObj->removeLayer(id.toStdString());
+ d_ptr->mapObj->getStyle().removeLayer(id.toStdString());
}
/*!
@@ -1414,7 +1331,7 @@ void QMapboxGL::addImage(const QString &id, const QImage &image)
{
if (image.isNull()) return;
- d_ptr->mapObj->addImage(id.toStdString(), toStyleImage(image));
+ d_ptr->mapObj->getStyle().addImage(toStyleImage(id, image));
}
/*!
@@ -1422,7 +1339,7 @@ void QMapboxGL::addImage(const QString &id, const QImage &image)
*/
void QMapboxGL::removeImage(const QString &id)
{
- d_ptr->mapObj->removeImage(id.toStdString());
+ d_ptr->mapObj->getStyle().removeImage(id.toStdString());
}
/*!
@@ -1450,7 +1367,7 @@ void QMapboxGL::setFilter(const QString& layer, const QVariant& filter)
using namespace mbgl::style;
using namespace mbgl::style::conversion;
- Layer* layer_ = d_ptr->mapObj->getLayer(layer.toStdString());
+ Layer* layer_ = d_ptr->mapObj->getStyle().getLayer(layer.toStdString());
if (!layer_) {
qWarning() << "Layer not found:" << layer;
return;
@@ -1590,12 +1507,12 @@ mbgl::Size QMapboxGLPrivate::framebufferSize() const {
void QMapboxGLPrivate::updateAssumedState() {
assumeFramebufferBinding(fbObject);
- assumeViewportSize(framebufferSize());
+ assumeViewport(0, 0, framebufferSize());
}
void QMapboxGLPrivate::bind() {
setFramebufferBinding(fbObject);
- setViewportSize(framebufferSize());
+ setViewport(0, 0, framebufferSize());
}
void QMapboxGLPrivate::invalidate()
@@ -1680,7 +1597,7 @@ void QMapboxGLPrivate::onDidFinishLoadingStyle()
void QMapboxGLPrivate::onSourceChanged(mbgl::style::Source&)
{
std::string attribution;
- for (const auto& source : mapObj->getSources()) {
+ for (const auto& source : mapObj->getStyle().getSources()) {
// Avoid duplicates by using the most complete attribution HTML snippet.
if (source->getAttribution() && (attribution.size() < source->getAttribution()->size()))
attribution = *source->getAttribution();
diff --git a/platform/qt/src/qt_conversion.hpp b/platform/qt/src/qt_conversion.hpp
index 4b93ca7423..40d7e5b928 100644
--- a/platform/qt/src/qt_conversion.hpp
+++ b/platform/qt/src/qt_conversion.hpp
@@ -83,6 +83,13 @@ inline optional<float> toNumber(const QVariant& value) {
return {};
}
}
+inline optional<double> toDouble(const QVariant& value) {
+ if (value.type() == QVariant::Int || value.type() == QVariant::Double) {
+ return value.toDouble();
+ } else {
+ return {};
+ }
+}
inline optional<std::string> toString(const QVariant& value) {
if (value.type() == QVariant::String) {